summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/getaddrinfo.c
diff options
context:
space:
mode:
authorderaadt <>1999-07-03 21:45:44 +0000
committerderaadt <>1999-07-03 21:45:44 +0000
commit0395bc5800143dafc68a0782a5243348d093419e (patch)
treea228bf063fbcb765aec27af54950c8defa19f79f /src/lib/libc/net/getaddrinfo.c
parent11b6f12bb197a5b34ad2a1da38937da31e9410ac (diff)
downloadopenbsd-0395bc5800143dafc68a0782a5243348d093419e.tar.gz
openbsd-0395bc5800143dafc68a0782a5243348d093419e.tar.bz2
openbsd-0395bc5800143dafc68a0782a5243348d093419e.zip
cleaned up
Diffstat (limited to 'src/lib/libc/net/getaddrinfo.c')
-rw-r--r--src/lib/libc/net/getaddrinfo.c923
1 files changed, 468 insertions, 455 deletions
diff --git a/src/lib/libc/net/getaddrinfo.c b/src/lib/libc/net/getaddrinfo.c
index 0e33aa1368..2094692339 100644
--- a/src/lib/libc/net/getaddrinfo.c
+++ b/src/lib/libc/net/getaddrinfo.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * %%% copyright-cmetz-96-bsd 2 * %%% copyright-cmetz-96-bsd
3 * Copyright (c) 1996-1999, Craig Metz, All rights reserved. 3 * Copyright (c) 1996-1999, Craig Metz, All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
@@ -17,7 +17,7 @@
17 * 4. Neither the name of the author nor the names of contributors 17 * 4. Neither the name of the author nor the names of contributors
18 * may be used to endorse or promote products derived from this software 18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission. 19 * without specific prior written permission.
20 * 20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -29,7 +29,6 @@
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE. 31 * SUCH DAMAGE.
32 *
33 */ 32 */
34 33
35/* getaddrinfo() v1.38 */ 34/* getaddrinfo() v1.38 */
@@ -50,504 +49,518 @@
50#include <sys/utsname.h> 49#include <sys/utsname.h>
51#include <sys/un.h> 50#include <sys/un.h>
52#include <netinet/in.h> 51#include <netinet/in.h>
52#include <arpa/inet.h>
53#include <netdb.h> 53#include <netdb.h>
54#include <errno.h> 54#include <errno.h>
55 55
56#ifndef AF_LOCAL 56#define GAIH_OKIFUNSPEC 0x0100
57#define AF_LOCAL AF_UNIX 57#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
58#endif /* AF_LOCAL */
59#ifndef PF_LOCAL
60#define PF_LOCAL PF_UNIX
61#endif /* PF_LOCAL */
62#ifndef UNIX_PATH_MAX
63#define UNIX_PATH_MAX 108
64#endif /* UNIX_PATH_MAX */
65
66#define GAIH_OKIFUNSPEC 0x0100
67#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
68 58
69static struct addrinfo nullreq = 59static struct addrinfo nullreq = {
70{ 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL }; 60 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL
61};
71 62
72struct gaih_service { 63struct gaih_service {
73 char *name; 64 char *name;
74 int num; 65 int num;
75}; 66};
76 67
77struct gaih_servtuple { 68struct gaih_servtuple {
78 struct gaih_servtuple *next; 69 struct gaih_servtuple *next;
79 int socktype; 70 int socktype;
80 int protocol; 71 int protocol;
81 int port; 72 int port;
82}; 73};
83 74
84static struct gaih_servtuple nullserv = { 75static struct gaih_servtuple nullserv = {
85 NULL, 0, 0, 0 76 NULL, 0, 0, 0
86}; 77};
87 78
88struct gaih_addrtuple { 79struct gaih_addrtuple {
89 struct gaih_addrtuple *next; 80 struct gaih_addrtuple *next;
90 int family; 81 int family;
91 char addr[16]; 82 char addr[16];
92 char *cname; 83 char *cname;
93}; 84};
94 85
95struct gaih_typeproto { 86static struct gaih_typeproto {
96 int socktype; 87 int socktype;
97 int protocol; 88 int protocol;
98 char *name; 89 char *name;
90} gaih_inet_typeproto[] = {
91 { 0, 0, NULL },
92 { SOCK_STREAM, IPPROTO_TCP, "tcp" },
93 { SOCK_DGRAM, IPPROTO_UDP, "udp" },
94 { 0, 0, NULL }
99}; 95};
100 96
101#define RETURN_ERROR(x) do { \ 97static int
102 rval = (x); \ 98netdb_lookup_addr(const char *name, int af,
103 goto ret; \ 99 const struct addrinfo *req, struct gaih_addrtuple **pat)
104 } while(0) 100{
101 int rval = 0, herrno, i;
102 char *prevcname = NULL;
103 struct hostent *h;
104
105 h = gethostbyname2(name, af);
106 herrno = h_errno;
107
108 if (!h) {
109 switch (herrno) {
110 case NETDB_INTERNAL:
111 return -EAI_SYSTEM;
112 case HOST_NOT_FOUND:
113 return 1;
114 case TRY_AGAIN:
115 return -EAI_AGAIN;
116 case NO_RECOVERY:
117 return -EAI_FAIL;
118 case NO_DATA:
119 return 1;
120 default:
121 return -EAI_FAIL;
122 }
123 }
124
125 for (i = 0; h->h_addr_list[i]; i++) {
126 while (*pat)
127 pat = &((*pat)->next);
128
129 if (!(*pat = malloc(sizeof(struct gaih_addrtuple))))
130 return -EAI_MEMORY;
131 memset(*pat, 0, sizeof(struct gaih_addrtuple));
132
133 switch ((*pat)->family = af) {
134 case AF_INET:
135 memcpy((*pat)->addr, h->h_addr_list[i],
136 sizeof(struct in_addr));
137 break;
138 case AF_INET6:
139 memcpy((*pat)->addr, h->h_addr_list[i],
140 sizeof(struct in6_addr));
141 break;
142 default:
143 return -EAI_FAIL;
144 }
145
146 if (req->ai_flags & AI_CANONNAME) {
147 if (prevcname && !strcmp(prevcname, h->h_name))
148 (*pat)->cname = prevcname;
149 else
150 prevcname = (*pat)->cname = strdup(h->h_name);
151 }
152 pat = &((*pat)->next);
153 }
154 return rval;
155}
105 156
106static int netdb_lookup_addr(const char *name, int af, const struct addrinfo *req, struct gaih_addrtuple **pat) 157static int
158gaih_local(const char *name, const struct gaih_service *service,
159 const struct addrinfo *req, struct addrinfo **pai)
107{ 160{
108 int rval, herrno, i; 161 struct utsname utsname;
109 char *prevcname = NULL; 162 struct addrinfo *ai;
110 struct hostent *h; 163 struct sockaddr_un *sun;
111 164 int siz;
112 h = gethostbyname2(name, af); 165
113 herrno = h_errno; 166 if (name || (req->ai_flags & AI_CANONNAME))
114 167 if (uname(&utsname) < 0)
115 if (!h) { 168 return (-EAI_SYSTEM);
116 switch(herrno) { 169
117 case NETDB_INTERNAL: 170 if (name && strcmp(name, "localhost") && strcmp(name, "local") &&
118 RETURN_ERROR(-EAI_SYSTEM); 171 strcmp(name, "unix") && strcmp(name, utsname.nodename))
119 case HOST_NOT_FOUND: 172 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
120 RETURN_ERROR(1); 173
121 case TRY_AGAIN: 174 siz = sizeof(struct addrinfo) + sizeof(struct sockaddr_un);
122 RETURN_ERROR(-EAI_AGAIN); 175 if (req->ai_flags & AI_CANONNAME)
123 case NO_RECOVERY: 176 siz += strlen(utsname.nodename) + 1;
124 RETURN_ERROR(-EAI_FAIL); 177
125 case NO_DATA: 178 if (!(ai = malloc(siz)))
126 RETURN_ERROR(1); 179 return -EAI_MEMORY;
127 default: 180
128 RETURN_ERROR(-EAI_FAIL); 181 *pai = ai;
129 }; 182 ai->ai_next = NULL;
130 }; 183 ai->ai_flags = req->ai_flags;
131 184 ai->ai_family = AF_LOCAL;
132 for (i = 0; h->h_addr_list[i]; i++) { 185 ai->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
133 while(*pat) 186 ai->ai_protocol = req->ai_protocol;
134 pat = &((*pat)->next); 187 ai->ai_addrlen = sizeof(struct sockaddr_un);
135 188 ai->ai_addr = (void *)ai + sizeof(struct addrinfo);
136 if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) 189
137 RETURN_ERROR(-EAI_MEMORY); 190 sun = (struct sockaddr_un *)ai->ai_addr;
138 191 sun->sun_len = sizeof(struct sockaddr_un);
139 memset(*pat, 0, sizeof(struct gaih_addrtuple)); 192 sun->sun_family = AF_LOCAL;
140 193 memset(&sun->sun_path, 0, sizeof sun->sun_path);
141 switch((*pat)->family = af) { 194
142 case AF_INET: 195 if (service) {
143 memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in_addr)); 196 char *c;
144 break; 197
145 case AF_INET6: 198 c = strchr(service->name, '/');
146 memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in6_addr)); 199 if (c) {
147 break; 200 if (strlen(service->name) >= sizeof(sun->sun_path))
148 default: 201 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
149 RETURN_ERROR(-EAI_FAIL); 202 strlcpy(sun->sun_path, service->name, sizeof (sun->sun_path));
150 }; 203 } else {
151 204 if (strlen(P_tmpdir "/") + strlen(service->name) + 1 >=
152 if (req->ai_flags & AI_CANONNAME) { 205 sizeof(sun->sun_path))
153 if (prevcname && !strcmp(prevcname, h->h_name)) 206 return(GAIH_OKIFUNSPEC | -EAI_SERVICE);
154 (*pat)->cname = prevcname; 207 snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s",
155 else 208 P_tmpdir, service->name);
156 prevcname = (*pat)->cname = strdup(h->h_name); 209 }
157 }; 210 } else {
158 211 extern char *_mktemp __P((char *));
159 pat = &((*pat)->next); 212 char tmpn[MAXPATHLEN], *c;
160 } 213
161 214 snprintf(tmpn, sizeof tmpn, "%stmp.XXXXXXXXXXXXX", P_tmpdir);
162 rval = 0; 215 if (!(c = _mktemp(tmpn)))
216 return (GAIH_OKIFUNSPEC | -EAI_SYSTEM);
217 strlcpy(sun->sun_path, c, sizeof(sun->sun_path));
218 }
163 219
164ret: 220 ai->ai_canonname = NULL;
165 return rval; 221 if (req->ai_flags & AI_CANONNAME) {
166}; 222 ai->ai_canonname = (void *)sun + sizeof(struct sockaddr_un);
223 strlcpy(ai->ai_canonname, utsname.nodename,
224 strlen(utsname.nodename)+1);
225 }
226 return 0;
227}
167 228
168static int gaih_local(const char *name, const struct gaih_service *service, 229static int
169 const struct addrinfo *req, struct addrinfo **pai) 230gaih_inet_serv(char *servicename, struct gaih_typeproto *tp,
231 struct gaih_servtuple **st)
170{ 232{
171 int rval; 233 struct servent *s;
172 struct utsname utsname;
173
174 if (name || (req->ai_flags & AI_CANONNAME))
175 if (uname(&utsname) < 0)
176 RETURN_ERROR(-EAI_SYSTEM);
177 if (name) {
178 if (strcmp(name, "localhost") && strcmp(name, "local") && strcmp(name, "unix") && strcmp(name, utsname.nodename))
179 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_NONAME);
180 };
181
182 if (!(*pai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_un) + ((req->ai_flags & AI_CANONNAME) ? (strlen(utsname.nodename) + 1): 0))))
183 RETURN_ERROR(-EAI_MEMORY);
184
185 (*pai)->ai_next = NULL;
186 (*pai)->ai_flags = req->ai_flags;
187 (*pai)->ai_family = AF_LOCAL;
188 (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
189 (*pai)->ai_protocol = req->ai_protocol;
190 (*pai)->ai_addrlen = sizeof(struct sockaddr_un);
191 (*pai)->ai_addr = (void *)(*pai) + sizeof(struct addrinfo);
192 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_len = sizeof(struct sockaddr_un);
193 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
194 memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
195 if (service) {
196 char *c;
197 if (c = strchr(service->name, '/')) {
198 if (strlen(service->name) >= sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path))
199 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE);
200 strcpy(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, service->name);
201 } else {
202 if (strlen(P_tmpdir "/") + 1 + strlen(service->name) >= sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path))
203 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE);
204 strcpy(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, P_tmpdir "/");
205 strcat(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, service->name);
206 };
207 } else {
208 char *c;
209 if (!(c = tmpnam(NULL)))
210 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SYSTEM);
211
212 strncpy((((struct sockaddr_un *)(*pai)->ai_addr)->sun_path), c, sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path) - 1);
213 c[sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path) - 1] = 0;
214 };
215 if (req->ai_flags & AI_CANONNAME) {
216 strncpy((*pai)->ai_canonname = (char *)(*pai) + sizeof(struct addrinfo) + sizeof(struct sockaddr_un), utsname.nodename, sizeof(utsname.nodename) - 1);
217 (*pai)->ai_canonname[sizeof(utsname.nodename) - 1] = 0;
218 } else
219 (*pai)->ai_canonname = NULL;
220
221 rval = 0;
222 234
223ret: 235 s = getservbyname(servicename, tp->name);
224 return rval; 236 if (!s)
225}; 237 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
226 238
227static struct gaih_typeproto gaih_inet_typeproto[] = { 239 if (!(*st = malloc(sizeof(struct gaih_servtuple))))
228 { 0, 0, NULL }, 240 return (-EAI_MEMORY);
229 { SOCK_STREAM, IPPROTO_TCP, "tcp" },
230 { SOCK_DGRAM, IPPROTO_UDP, "udp" },
231 { 0, 0, NULL }
232};
233 241
234static int gaih_inet_serv(char *servicename, struct gaih_typeproto *tp, struct gaih_servtuple **st) 242 (*st)->next = NULL;
243 (*st)->socktype = tp->socktype;
244 (*st)->protocol = tp->protocol;
245 (*st)->port = s->s_port;
246 return (0);
247}
248
249static int
250gaih_inet(const char *name, const struct gaih_service *service,
251 const struct addrinfo*req, struct addrinfo **pai)
235{ 252{
236 int rval; 253 struct gaih_typeproto *tp = gaih_inet_typeproto;
237 struct servent *s; 254 struct gaih_servtuple *st = &nullserv;
255 struct gaih_addrtuple *at = NULL;
256 char *prevcname = NULL;
257 struct gaih_servtuple *st2;
258 struct gaih_addrtuple *at2 = at;
259 struct addrinfo *ai = NULL;
260 int canonlen, addrlen, rval = 0;
261
262 if (req->ai_protocol || req->ai_socktype) {
263 for (tp++; tp->name &&
264 ((req->ai_socktype != tp->socktype) || !req->ai_socktype) &&
265 ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++);
266 if (!tp->name) {
267 rval = GAIH_OKIFUNSPEC | -EAI_SERVICE;
268 if (req->ai_socktype)
269 rval = GAIH_OKIFUNSPEC | -EAI_SOCKTYPE;
270 goto ret;
271 }
272 }
273 if (service && (service->num < 0)) {
274 if (tp->name) {
275 rval = gaih_inet_serv(service->name, tp, &st);
276 if (rval)
277 goto ret;
278 } else {
279 struct gaih_servtuple **pst = &st;
280 for (tp++; tp->name; tp++) {
281 rval = gaih_inet_serv(service->name, tp, pst);
282 if (rval) {
283 if (rval & GAIH_OKIFUNSPEC)
284 continue;
285 goto ret;
286 }
287 pst = &((*pst)->next);
288 }
289 if (st == &nullserv) {
290 rval = GAIH_OKIFUNSPEC | -EAI_SERVICE;
291 goto ret;
292 }
293 }
294 } else {
295 if (!(st = malloc(sizeof(struct gaih_servtuple)))) {
296 rval = -EAI_MEMORY;
297 goto ret;
298 }
299
300 st->next = NULL;
301 st->socktype = tp->socktype;
302 st->protocol = tp->protocol;
303 if (service)
304 st->port = htons(service->num);
305 else
306 st->port = 0;
307 }
238 308
239 if (!(s = getservbyname(servicename, tp->name))) 309 if (!name) {
240 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); 310 if (!(at = malloc(sizeof(struct gaih_addrtuple)))) {
311 rval = -EAI_MEMORY;
312 goto ret;
313 }
241 314
242 if (!(*st = malloc(sizeof(struct gaih_servtuple)))) 315 memset(at, 0, sizeof(struct gaih_addrtuple));
243 RETURN_ERROR(-EAI_MEMORY);
244 316
245 (*st)->next = NULL; 317 if (req->ai_family)
246 (*st)->socktype = tp->socktype; 318 at->family = req->ai_family;
247 (*st)->protocol = tp->protocol; 319 else {
248 (*st)->port = s->s_port; 320 if (!(at->next = malloc(sizeof(struct gaih_addrtuple)))) {
321 rval = -EAI_MEMORY;
322 goto ret;
323 }
249 324
250 rval = 0; 325 at->family = AF_INET6;
251 326
252ret: 327 memset(at->next, 0, sizeof(struct gaih_addrtuple));
253 return rval; 328 at->next->family = AF_INET;
254} 329 }
255 330
256static int gaih_inet(const char *name, const struct gaih_service *service, 331 goto build;
257 const struct addrinfo *req, struct addrinfo **pai) 332 }
258{ 333
259 int rval; 334 if (!req->ai_family || (req->ai_family == AF_INET)) {
260 struct hostent *h = NULL; 335 struct in_addr in_addr;
261 struct gaih_typeproto *tp = gaih_inet_typeproto; 336 if (inet_pton(AF_INET, name, &in_addr) > 0) {
262 struct gaih_servtuple *st = &nullserv; 337 if (!(at = malloc(sizeof(struct gaih_addrtuple)))) {
263 struct gaih_addrtuple *at = NULL; 338 rval = -EAI_MEMORY;
264 int i; 339 goto ret;
265 340 }
266 if (req->ai_protocol || req->ai_socktype) { 341
267 for (tp++; tp->name && 342 memset(at, 0, sizeof(struct gaih_addrtuple));
268 ((req->ai_socktype != tp->socktype) || !req->ai_socktype) && 343
269 ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++); 344 at->family = AF_INET;
270 if (!tp->name) 345 memcpy(at->addr, &in_addr, sizeof(struct in_addr));
271 if (req->ai_socktype) 346 goto build;
272 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SOCKTYPE); 347 }
273 else 348 }
274 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); 349
275 } 350 if (!req->ai_family || (req->ai_family == AF_INET6)) {
276 351 struct in6_addr in6_addr;
277 if (service && (service->num < 0)) { 352 if (inet_pton(AF_INET6, name, &in6_addr) > 0) {
278 if (tp->name) { 353 if (!(at = malloc(sizeof(struct gaih_addrtuple)))) {
279 if (rval = gaih_inet_serv(service->name, tp, &st)) 354 rval = -EAI_MEMORY;
280 goto ret; 355 goto ret;
281 } else { 356 }
282 struct gaih_servtuple **pst = &st; 357
283 for (tp++; tp->name; tp++) { 358 memset(at, 0, sizeof(struct gaih_addrtuple));
284 if (rval = gaih_inet_serv(service->name, tp, pst)) { 359
285 if (rval & GAIH_OKIFUNSPEC) 360 at->family = AF_INET6;
286 continue; 361 memcpy(at->addr, &in6_addr, sizeof(struct in6_addr));
287 goto ret; 362 goto build;
288 }; 363 }
289 pst = &((*pst)->next); 364 }
290 }; 365
291 if (st == &nullserv) 366 if (!(req->ai_flags & AI_NUMERICHOST)) {
292 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); 367 if (!req->ai_family || (req->ai_family == AF_INET6))
293 }; 368 if ((rval = netdb_lookup_addr(name, AF_INET6, req, &at)) < 0)
294 } else { 369 goto ret;
295 if (!(st = malloc(sizeof(struct gaih_servtuple)))) 370 if (!req->ai_family || (req->ai_family == AF_INET))
296 RETURN_ERROR(-EAI_MEMORY); 371 if ((rval = netdb_lookup_addr(name, AF_INET, req, &at)) < 0)
297 372 goto ret;
298 st->next = NULL; 373
299 st->socktype = tp->socktype; 374 if (!rval)
300 st->protocol = tp->protocol; 375 goto build;
301 if (service) 376 }
302 st->port = htons(service->num); 377
303 else 378 if (!at) {
304 st->port = 0; 379 rval = GAIH_OKIFUNSPEC | -EAI_NONAME;
305 }; 380 goto ret;
306 381 }
307 if (!name) {
308 if (!(at = malloc(sizeof(struct gaih_addrtuple))))
309 RETURN_ERROR(-EAI_MEMORY);
310
311 memset(at, 0, sizeof(struct gaih_addrtuple));
312
313 if (req->ai_family)
314 at->family = req->ai_family;
315 else {
316 if (!(at->next = malloc(sizeof(struct gaih_addrtuple))))
317 RETURN_ERROR(-EAI_MEMORY);
318
319 at->family = AF_INET6;
320
321 memset(at->next, 0, sizeof(struct gaih_addrtuple));
322 at->next->family = AF_INET;
323 };
324
325 goto build;
326 };
327
328 if (!req->ai_family || (req->ai_family == AF_INET)) {
329 struct in_addr in_addr;
330 if (inet_pton(AF_INET, name, &in_addr) > 0) {
331 if (!(at = malloc(sizeof(struct gaih_addrtuple))))
332 RETURN_ERROR(-EAI_MEMORY);
333
334 memset(at, 0, sizeof(struct gaih_addrtuple));
335
336 at->family = AF_INET;
337 memcpy(at->addr, &in_addr, sizeof(struct in_addr));
338 goto build;
339 };
340 };
341
342 if (!req->ai_family || (req->ai_family == AF_INET6)) {
343 struct in6_addr in6_addr;
344 if (inet_pton(AF_INET6, name, &in6_addr) > 0) {
345 if (!(at = malloc(sizeof(struct gaih_addrtuple))))
346 RETURN_ERROR(-EAI_MEMORY);
347
348 memset(at, 0, sizeof(struct gaih_addrtuple));
349
350 at->family = AF_INET6;
351 memcpy(at->addr, &in6_addr, sizeof(struct in6_addr));
352 goto build;
353 };
354 };
355
356 if (!(req->ai_flags & AI_NUMERICHOST)) {
357 if (!req->ai_family || (req->ai_family == AF_INET6))
358 if ((rval = netdb_lookup_addr(name, AF_INET6, req, &at)) < 0)
359 goto ret;
360 if (!req->ai_family || (req->ai_family == AF_INET))
361 if ((rval = netdb_lookup_addr(name, AF_INET, req, &at)) < 0)
362 goto ret;
363
364 if (!rval)
365 goto build;
366 };
367
368 if (!at)
369 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_NONAME);
370 382
371build: 383build:
372 { 384 while (at2) {
373 char *prevcname = NULL; 385 if (req->ai_flags & AI_CANONNAME) {
374 struct gaih_servtuple *st2; 386 if (at2->cname)
375 struct gaih_addrtuple *at2 = at; 387 canonlen = strlen(at2->cname) + 1;
376 int j; 388 else
377 389 if (name)
378 while(at2) { 390 canonlen = strlen(name) + 1;
379 if (req->ai_flags & AI_CANONNAME) { 391 else
380 if (at2->cname) 392 canonlen = 2;
381 j = strlen(at2->cname) + 1; 393 } else
382 else 394 canonlen = 0;
383 if (name) 395
384 j = strlen(name) + 1; 396 if (at2->family == AF_INET6)
385 else 397 addrlen = sizeof(struct sockaddr_in6);
386 j = 2; 398 else
387 } else 399 addrlen = sizeof(struct sockaddr_in);
388 j = 0; 400
389 401 st2 = st;
390 if (at2->family == AF_INET6) 402 while (st2) {
391 i = sizeof(struct sockaddr_in6); 403 if (!(ai = malloc(sizeof(struct addrinfo) +
392 else 404 addrlen + canonlen))) {
393 i = sizeof(struct sockaddr_in); 405 rval = -EAI_MEMORY;
394 406 goto ret;
395 st2 = st; 407 }
396 while(st2) { 408
397 if (!(*pai = malloc(sizeof(struct addrinfo) + i + j))) 409 *pai = ai;
398 RETURN_ERROR(-EAI_MEMORY); 410 memset(ai, 0, sizeof(struct addrinfo) + addrlen + canonlen);
399 411
400 memset(*pai, 0, sizeof(struct addrinfo) + i + j); 412 ai->ai_flags = req->ai_flags;
401 413 ai->ai_family = at2->family;
402 (*pai)->ai_flags = req->ai_flags; 414 ai->ai_socktype = st2->socktype;
403 (*pai)->ai_family = at2->family; 415 ai->ai_protocol = st2->protocol;
404 (*pai)->ai_socktype = st2->socktype; 416 ai->ai_addrlen = addrlen;
405 (*pai)->ai_protocol = st2->protocol; 417 ai->ai_addr = (void *)ai + sizeof(struct addrinfo);
406 (*pai)->ai_addrlen = i; 418 ai->ai_addr->sa_len = addrlen;
407 (*pai)->ai_addr = (void *)(*pai) + sizeof(struct addrinfo); 419 ai->ai_addr->sa_family = at2->family;
408 ((struct sockaddr_in *)(*pai)->ai_addr)->sin_len = i; 420
409 ((struct sockaddr_in *)(*pai)->ai_addr)->sin_family = at2->family; 421 switch (at2->family) {
410 ((struct sockaddr_in *)(*pai)->ai_addr)->sin_port = st2->port; 422 case AF_INET6:
411 423 {
412 if (at2->family == AF_INET6) 424 struct sockaddr_in6 *sin6 = (void *)ai->ai_addr;
413 memcpy(&((struct sockaddr_in6 *)(*pai)->ai_addr)->sin6_addr, at2->addr, sizeof(struct in6_addr)); 425
414 else 426 memcpy(&sin6->sin6_addr, at2->addr,
415 memcpy(&((struct sockaddr_in *)(*pai)->ai_addr)->sin_addr, at2->addr, sizeof(struct in_addr)); 427 sizeof(sin6->sin6_addr));
416 428 sin6->sin6_port = st2->port;
417 if (j) { 429 break;
418 (*pai)->ai_canonname = (void *)(*pai) + sizeof(struct addrinfo) + i; 430 }
419 if (at2->cname) { 431 default:
420 strcpy((*pai)->ai_canonname, at2->cname); 432 {
421 if (prevcname != at2->cname) { 433 struct sockaddr_in *sin = (void *)ai->ai_addr;
422 if (prevcname) 434
423 free(prevcname); 435 memcpy(&sin->sin_addr, at2->addr,
424 prevcname = at2->cname; 436 sizeof(sin->sin_addr));
425 }; 437 sin->sin_port = st2->port;
426 } else 438 break;
427 strcpy((*pai)->ai_canonname, name ? name : "*"); 439 }
428 }; 440 }
429 441
430 pai = &((*pai)->ai_next); 442 if (canonlen) {
431 443 ai->ai_canonname = (void *) ai->ai_addr + addrlen;
432 st2 = st2->next; 444
433 }; 445 if (at2->cname) {
434 at2 = at2->next; 446 strcpy(ai->ai_canonname, at2->cname);
435 }; 447 if (prevcname != at2->cname) {
436 }; 448 if (prevcname)
437 449 free(prevcname);
438 rval = 0; 450 prevcname = at2->cname;
451 }
452 } else
453 strcpy(ai->ai_canonname, name ? name : "*");
454 }
455 pai = &(ai->ai_next);
456 st2 = st2->next;
457 }
458 at2 = at2->next;
459 }
460 rval = 0;
439 461
440ret: 462ret:
441 if (st != &nullserv) { 463 if (st != &nullserv) {
442 struct gaih_servtuple *st2 = st; 464 struct gaih_servtuple *st2 = st;
443 while(st) { 465 while (st) {
444 st2 = st->next; 466 st2 = st->next;
445 free(st); 467 free(st);
446 st = st2; 468 st = st2;
447 } 469 }
448 } 470 }
449 if (at) { 471 if (at) {
450 struct gaih_addrtuple *at2 = at; 472 struct gaih_addrtuple *at2 = at;
451 while(at) { 473 while (at) {
452 at2 = at->next; 474 at2 = at->next;
453 free(at); 475 free(at);
454 at = at2; 476 at = at2;
455 } 477 }
456 } 478 }
457 479 return rval;
458 return rval;
459} 480}
460 481
461struct gaih { 482static struct gaih {
462 int family; 483 int family;
463 char *name; 484 char *name;
464 int (*gaih)(const char *name, const struct gaih_service *service, 485 int (*gaih) __P((const char *name,
465 const struct addrinfo *req, struct addrinfo **pai); 486 const struct gaih_service *service,
466}; 487 const struct addrinfo *req, struct addrinfo **pai));
467 488} gaih[] = {
468static struct gaih gaih[] = { 489 { PF_INET6, "inet6", gaih_inet },
469 { PF_INET6, "inet6", gaih_inet }, 490 { PF_INET, "inet", gaih_inet },
470 { PF_INET, "inet", gaih_inet }, 491 { PF_LOCAL, "local", gaih_local },
471 { PF_LOCAL, "local", gaih_local }, 492 { -1, NULL, NULL}
472 { -1, NULL, NULL }
473}; 493};
474 494
475int getaddrinfo(const char *name, const char *service, 495int
476 const struct addrinfo *req, struct addrinfo **pai) 496getaddrinfo(const char *name, const char *service,
497 const struct addrinfo *req, struct addrinfo **pai)
477{ 498{
478 int rval = EAI_SYSTEM; /* XXX */ 499 int rval = EAI_SYSTEM; /* XXX */
479 int i, j = 0; 500 int j = 0;
480 struct addrinfo *p = NULL, **end; 501 struct addrinfo *p = NULL, **end;
481 struct gaih *g = gaih, *pg = NULL; 502 struct gaih *g = gaih, *pg = NULL;
482 struct gaih_service gaih_service, *pservice; 503 struct gaih_service gaih_service, *pservice;
483
484 if (name && (name[0] == '*') && !name[1])
485 name = NULL;
486
487 if (service && (service[0] == '*') && !service[1])
488 service = NULL;
489
490 if (!req)
491 req = &nullreq;
492
493 if (req->ai_flags & ~(AI_CANONNAME | AI_PASSIVE | AI_NUMERICHOST | AI_EXT))
494 RETURN_ERROR(EAI_BADFLAGS);
495
496 if (service && *service) {
497 char *c;
498 gaih_service.num = strtoul(gaih_service.name = (void *)service, &c, 10);
499 if (*c) {
500 gaih_service.num = -1;
501 }
502
503 pservice = &gaih_service;
504 } else
505 pservice = NULL;
506
507 if (pai)
508 end = &p;
509 else
510 end = NULL;
511
512 while(g->gaih) {
513 if ((req->ai_family == g->family) || !req->ai_family) {
514 j++;
515 if (!((pg && (pg->gaih == g->gaih)))) {
516 pg = g;
517 if (rval = g->gaih(name, pservice, req, end)) {
518 if (!req->ai_family && (rval & GAIH_OKIFUNSPEC))
519 continue;
520
521 if (p)
522 freeaddrinfo(p);
523
524 rval = -(rval & GAIH_EAI);
525 goto ret;
526 }
527 if (end)
528 while(*end) end = &((*end)->ai_next);
529 }
530 }
531 g++;
532 }
533 504
534 if (!j) 505 if (name && (name[0] == '*') && !name[1])
535 RETURN_ERROR(EAI_FAMILY); 506 name = NULL;
536 507
537 if (p) { 508 if (service && service[0] == '*' && service[1] == '\0')
538 *pai = p; 509 service = NULL;
539 rval = 0;
540 goto ret;
541 }
542 510
543 if (!pai && !rval) { 511 if (!req)
544 rval = 0; 512 req = &nullreq;
545 goto ret;
546 };
547 513
548 RETURN_ERROR(EAI_NONAME); 514 if (req->ai_flags & ~(AI_CANONNAME | AI_PASSIVE | AI_NUMERICHOST | AI_EXT))
515 return (EAI_BADFLAGS);
549 516
550ret: 517 if (service && *service) {
551 return rval; 518 char *c;
552}
553 519
520 gaih_service.num = strtoul(service, &c, 10);
521 if (*c)
522 gaih_service.num = -1;
523 gaih_service.name = (void *)service;
524 pservice = &gaih_service;
525 } else
526 pservice = NULL;
527
528 if (pai)
529 end = &p;
530 else
531 end = NULL;
532
533 while (g->gaih) {
534 if ((req->ai_family == g->family) || !req->ai_family) {
535 j++;
536 if (!((pg && (pg->gaih == g->gaih)))) {
537 pg = g;
538 rval = g->gaih(name, pservice, req, end);
539 if (rval) {
540 if (!req->ai_family && (rval & GAIH_OKIFUNSPEC))
541 continue;
542
543 if (p)
544 freeaddrinfo(p);
545
546 return -(rval & GAIH_EAI);
547 }
548 if (end)
549 while (*end)
550 end = &((*end)->ai_next);
551 }
552 }
553 g++;
554 }
555
556 if (!j)
557 return (EAI_FAMILY);
558
559 if (p) {
560 *pai = p;
561 return (0);
562 }
563 if (!pai && !rval)
564 return (0);
565 return EAI_NONAME;
566}