]> git.saurik.com Git - apt.git/blob - methods/rfc2553emu.cc
merge patch from Daniel Hartwig to Show a error message if {,dist-}upgrade is used...
[apt.git] / methods / rfc2553emu.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: rfc2553emu.cc,v 1.8 2001/02/20 07:03:18 jgg Exp $
4 /* ######################################################################
5
6 RFC 2553 Emulation - Provides emulation for RFC 2553 getaddrinfo,
7 freeaddrinfo and getnameinfo
8
9 This is really C code, it just has a .cc extensions to play nicer with
10 the rest of APT.
11
12 Originally written by Jason Gunthorpe <jgg@debian.org> and placed into
13 the Public Domain, do with it what you will.
14
15 ##################################################################### */
16 /*}}}*/
17 #include <config.h>
18
19 #include <stdlib.h>
20 #include <arpa/inet.h>
21 #include <netinet/in.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include "rfc2553emu.h"
25
26 #ifndef HAVE_GETADDRINFO
27 // getaddrinfo - Resolve a hostname /*{{{*/
28 // ---------------------------------------------------------------------
29 /* */
30 int getaddrinfo(const char *nodename, const char *servname,
31 const struct addrinfo *hints,
32 struct addrinfo **res)
33 {
34 struct addrinfo **Result = res;
35 hostent *Addr;
36 unsigned int Port;
37 int Proto;
38 const char *End;
39 char **CurAddr;
40
41 // Try to convert the service as a number
42 Port = htons(strtol(servname,(char **)&End,0));
43 Proto = SOCK_STREAM;
44
45 if (hints != 0 && hints->ai_socktype != 0)
46 Proto = hints->ai_socktype;
47
48 // Not a number, must be a name.
49 if (End != servname + strlen(servname))
50 {
51 struct servent *Srv = 0;
52
53 // Do a lookup in the service database
54 if (hints == 0 || hints->ai_socktype == SOCK_STREAM)
55 Srv = getservbyname(servname,"tcp");
56 if (hints != 0 && hints->ai_socktype == SOCK_DGRAM)
57 Srv = getservbyname(servname,"udp");
58 if (Srv == 0)
59 return EAI_NONAME;
60
61 // Get the right protocol
62 Port = Srv->s_port;
63 if (strcmp(Srv->s_proto,"tcp") == 0)
64 Proto = SOCK_STREAM;
65 else
66 {
67 if (strcmp(Srv->s_proto,"udp") == 0)
68 Proto = SOCK_DGRAM;
69 else
70 return EAI_NONAME;
71 }
72
73 if (hints != 0 && hints->ai_socktype != Proto &&
74 hints->ai_socktype != 0)
75 return EAI_SERVICE;
76 }
77
78 // Hostname lookup, only if this is not a listening socket
79 if (hints != 0 && (hints->ai_flags & AI_PASSIVE) != AI_PASSIVE)
80 {
81 Addr = gethostbyname(nodename);
82 if (Addr == 0)
83 {
84 if (h_errno == TRY_AGAIN)
85 return EAI_AGAIN;
86 if (h_errno == NO_RECOVERY)
87 return EAI_FAIL;
88 return EAI_NONAME;
89 }
90
91 // No A records
92 if (Addr->h_addr_list[0] == 0)
93 return EAI_NONAME;
94
95 CurAddr = Addr->h_addr_list;
96 }
97 else
98 CurAddr = (char **)&End; // Fake!
99
100 // Start constructing the linked list
101 *res = 0;
102 for (; *CurAddr != 0; CurAddr++)
103 {
104 // New result structure
105 *Result = (struct addrinfo *)calloc(sizeof(**Result),1);
106 if (*Result == 0)
107 {
108 freeaddrinfo(*res);
109 return EAI_MEMORY;
110 }
111 if (*res == 0)
112 *res = *Result;
113
114 (*Result)->ai_family = AF_INET;
115 (*Result)->ai_socktype = Proto;
116
117 // If we have the IPPROTO defines we can set the protocol field
118 #ifdef IPPROTO_TCP
119 if (Proto == SOCK_STREAM)
120 (*Result)->ai_protocol = IPPROTO_TCP;
121 if (Proto == SOCK_DGRAM)
122 (*Result)->ai_protocol = IPPROTO_UDP;
123 #endif
124
125 // Allocate space for the address
126 (*Result)->ai_addrlen = sizeof(struct sockaddr_in);
127 (*Result)->ai_addr = (struct sockaddr *)calloc(sizeof(sockaddr_in),1);
128 if ((*Result)->ai_addr == 0)
129 {
130 freeaddrinfo(*res);
131 return EAI_MEMORY;
132 }
133
134 // Set the address
135 ((struct sockaddr_in *)(*Result)->ai_addr)->sin_family = AF_INET;
136 ((struct sockaddr_in *)(*Result)->ai_addr)->sin_port = Port;
137
138 if (hints != 0 && (hints->ai_flags & AI_PASSIVE) != AI_PASSIVE)
139 ((struct sockaddr_in *)(*Result)->ai_addr)->sin_addr = *(in_addr *)(*CurAddr);
140 else
141 {
142 // Already zerod by calloc.
143 break;
144 }
145
146 Result = &(*Result)->ai_next;
147 }
148
149 return 0;
150 }
151 /*}}}*/
152 // freeaddrinfo - Free the result of getaddrinfo /*{{{*/
153 // ---------------------------------------------------------------------
154 /* */
155 void freeaddrinfo(struct addrinfo *ai)
156 {
157 while (ai != 0)
158 {
159 free(ai->ai_addr);
160 ai = ai->ai_next;
161 free(ai);
162 }
163 }
164 /*}}}*/
165 #endif // HAVE_GETADDRINFO
166
167 #ifndef HAVE_GETNAMEINFO
168 // getnameinfo - Convert a sockaddr to a string /*{{{*/
169 // ---------------------------------------------------------------------
170 /* */
171 int getnameinfo(const struct sockaddr *sa, socklen_t salen,
172 char *host, size_t hostlen,
173 char *serv, size_t servlen,
174 int flags)
175 {
176 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
177
178 // This routine only supports internet addresses
179 if (sa->sa_family != AF_INET)
180 return EAI_ADDRFAMILY;
181
182 if (host != 0)
183 {
184 // Try to resolve the hostname
185 if ((flags & NI_NUMERICHOST) != NI_NUMERICHOST)
186 {
187 struct hostent *Ent = gethostbyaddr((char *)&sin->sin_addr,sizeof(sin->sin_addr),
188 AF_INET);
189 if (Ent != 0)
190 strncpy(host,Ent->h_name,hostlen);
191 else
192 {
193 if ((flags & NI_NAMEREQD) == NI_NAMEREQD)
194 {
195 if (h_errno == TRY_AGAIN)
196 return EAI_AGAIN;
197 if (h_errno == NO_RECOVERY)
198 return EAI_FAIL;
199 return EAI_NONAME;
200 }
201
202 flags |= NI_NUMERICHOST;
203 }
204 }
205
206 // Resolve as a plain numberic
207 if ((flags & NI_NUMERICHOST) == NI_NUMERICHOST)
208 {
209 strncpy(host,inet_ntoa(sin->sin_addr),hostlen);
210 }
211 }
212
213 if (serv != 0)
214 {
215 // Try to resolve the hostname
216 if ((flags & NI_NUMERICSERV) != NI_NUMERICSERV)
217 {
218 struct servent *Ent;
219 if ((flags & NI_DATAGRAM) == NI_DATAGRAM)
220 Ent = getservbyport(ntohs(sin->sin_port),"udp");
221 else
222 Ent = getservbyport(ntohs(sin->sin_port),"tcp");
223
224 if (Ent != 0)
225 strncpy(serv,Ent->s_name,servlen);
226 else
227 {
228 if ((flags & NI_NAMEREQD) == NI_NAMEREQD)
229 return EAI_NONAME;
230
231 flags |= NI_NUMERICSERV;
232 }
233 }
234
235 // Resolve as a plain numberic
236 if ((flags & NI_NUMERICSERV) == NI_NUMERICSERV)
237 {
238 snprintf(serv,servlen,"%u",ntohs(sin->sin_port));
239 }
240 }
241
242 return 0;
243 }
244 /*}}}*/
245 #endif // HAVE_GETNAMEINFO