]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/posix/getaddrinfo.c
Update.
[thirdparty/glibc.git] / sysdeps / posix / getaddrinfo.c
CommitLineData
46ec036d
UD
1/* The Inner Net License, Version 2.00
2
3 The author(s) grant permission for redistribution and use in source and
4binary forms, with or without modification, of the software and documentation
5provided that the following conditions are met:
6
70. If you receive a version of the software that is specifically labelled
8 as not being for redistribution (check the version message and/or README),
9 you are not permitted to redistribute that version of the software in any
10 way or form.
111. All terms of the all other applicable copyrights and licenses must be
12 followed.
132. Redistributions of source code must retain the authors' copyright
14 notice(s), this list of conditions, and the following disclaimer.
153. Redistributions in binary form must reproduce the authors' copyright
16 notice(s), this list of conditions, and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
aeb25823 184. [The copyright holder has authorized the removal of this clause.]
46ec036d
UD
195. Neither the name(s) of the author(s) nor the names of its contributors
20 may be used to endorse or promote products derived from this software
21 without specific prior written permission.
22
23THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
24EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
27DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34 If these license terms cause you a real problem, contact the author. */
35
36/* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
37
c0bc5f7b
UD
38#include <assert.h>
39#include <errno.h>
40#include <netdb.h>
9c42c64d 41#include <resolv.h>
c0bc5f7b 42#include <stdio.h>
46ec036d 43#include <stdlib.h>
c0bc5f7b 44#include <string.h>
1fb05e3d 45#include <unistd.h>
c0bc5f7b 46#include <arpa/inet.h>
1fb05e3d 47#include <sys/socket.h>
46ec036d 48#include <netinet/in.h>
c0bc5f7b
UD
49#include <sys/types.h>
50#include <sys/un.h>
51#include <sys/utsname.h>
4fcddf8e 52#include <net/if.h>
1fb05e3d 53
46ec036d
UD
54#define GAIH_OKIFUNSPEC 0x0100
55#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
56
40a55d20
UD
57#ifndef UNIX_PATH_MAX
58#define UNIX_PATH_MAX 108
59#endif
46ec036d 60
40a55d20
UD
61struct gaih_service
62 {
63 const char *name;
64 int num;
65 };
46ec036d 66
40a55d20
UD
67struct gaih_servtuple
68 {
69 struct gaih_servtuple *next;
70 int socktype;
71 int protocol;
72 int port;
73 };
46ec036d 74
3e2d61a3 75static const struct gaih_servtuple nullserv;
46ec036d 76
40a55d20
UD
77struct gaih_addrtuple
78 {
79 struct gaih_addrtuple *next;
80 int family;
81 char addr[16];
c0bc5f7b 82 uint32_t scopeid;
40a55d20 83 };
46ec036d 84
40a55d20
UD
85struct gaih_typeproto
86 {
87 int socktype;
88 int protocol;
3e2d61a3 89 char name[4];
f3ac48d0 90 int protoflag;
40a55d20 91 };
46ec036d 92
f3ac48d0
UD
93/* Values for `protoflag'. */
94#define GAI_PROTO_NOSERVICE 1
85599e53 95#define GAI_PROTO_PROTOANY 2
f3ac48d0 96
3e2d61a3 97static const struct gaih_typeproto gaih_inet_typeproto[] =
40a55d20 98{
3e2d61a3
UD
99 { 0, 0, "", 0 },
100 { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
101 { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
102 { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
103 { 0, 0, "", 0 }
46ec036d
UD
104};
105
40a55d20
UD
106struct gaih
107 {
108 int family;
109 int (*gaih)(const char *name, const struct gaih_service *service,
110 const struct addrinfo *req, struct addrinfo **pai);
111 };
112
3e2d61a3
UD
113#if PF_UNSPEC == 0
114static const struct addrinfo default_hints;
115#else
116static const struct addrinfo default_hints =
40a55d20 117 { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
3e2d61a3 118#endif
40a55d20
UD
119
120
64b7897d
UD
121#if 0
122/* Using Unix sockets this way is a security risk. */
40a55d20
UD
123static int
124gaih_local (const char *name, const struct gaih_service *service,
125 const struct addrinfo *req, struct addrinfo **pai)
1fb05e3d
UD
126{
127 struct utsname utsname;
128
f1a785ac
UD
129 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
130 return GAIH_OKIFUNSPEC | -EAI_NONAME;
131
40a55d20 132 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
db7dc811 133 if (uname (&utsname) < 0)
1fb05e3d 134 return -EAI_SYSTEM;
1fb05e3d 135
40a55d20
UD
136 if (name != NULL)
137 {
138 if (strcmp(name, "localhost") &&
139 strcmp(name, "local") &&
140 strcmp(name, "unix") &&
141 strcmp(name, utsname.nodename))
142 return GAIH_OKIFUNSPEC | -EAI_NONAME;
143 }
144
a0bf6ac7
UD
145 if (req->ai_protocol || req->ai_socktype)
146 {
3e2d61a3 147 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
f3ac48d0 148
4b1fef84 149 while (tp->name[0]
f3ac48d0 150 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
3a47453d
UD
151 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
152 || (req->ai_protocol != 0
85599e53 153 && !(tp->protoflag & GAI_PROTO_PROTOANY)
3a47453d 154 && req->ai_protocol != tp->protocol)))
f3ac48d0 155 ++tp;
a0bf6ac7 156
4b1fef84 157 if (! tp->name[0])
a0bf6ac7
UD
158 {
159 if (req->ai_socktype)
160 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
161 else
162 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
163 }
164 }
165
166 *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
40a55d20
UD
167 + ((req->ai_flags & AI_CANONNAME)
168 ? (strlen(utsname.nodename) + 1): 0));
169 if (*pai == NULL)
1fb05e3d
UD
170 return -EAI_MEMORY;
171
172 (*pai)->ai_next = NULL;
173 (*pai)->ai_flags = req->ai_flags;
174 (*pai)->ai_family = AF_LOCAL;
175 (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
176 (*pai)->ai_protocol = req->ai_protocol;
a0bf6ac7
UD
177 (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
178 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
40a55d20 179
1fb05e3d 180#if SALEN
40a55d20
UD
181 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
182 sizeof (struct sockaddr_un);
1fb05e3d 183#endif /* SALEN */
40a55d20 184
1fb05e3d
UD
185 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
186 memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
40a55d20
UD
187
188 if (service)
189 {
190 struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
191
192 if (strchr (service->name, '/') != NULL)
193 {
194 if (strlen (service->name) >= sizeof (sunp->sun_path))
195 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
196
197 strcpy (sunp->sun_path, service->name);
198 }
199 else
200 {
201 if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
202 sizeof (sunp->sun_path))
203 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
204
205 __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
206 }
207 }
208 else
209 {
e658b54e
UD
210 /* This is a dangerous use of the interface since there is a time
211 window between the test for the file and the actual creation
212 (done by the caller) in which a file with the same name could
213 be created. */
214 char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
215
216 if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
217 0) != 0
218 || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
40a55d20
UD
219 return -EAI_SYSTEM;
220 }
221
1fb05e3d 222 if (req->ai_flags & AI_CANONNAME)
a0bf6ac7
UD
223 (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
224 + sizeof (struct sockaddr_un),
225 utsname.nodename);
1fb05e3d
UD
226 else
227 (*pai)->ai_canonname = NULL;
228 return 0;
40a55d20 229}
64b7897d 230#endif /* 0 */
46ec036d 231
40a55d20 232static int
3e2d61a3 233gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
85599e53 234 const struct addrinfo *req, struct gaih_servtuple *st)
46ec036d
UD
235{
236 struct servent *s;
40a55d20 237 size_t tmpbuflen = 1024;
993b3242 238 struct servent ts;
40a55d20
UD
239 char *tmpbuf;
240 int r;
241
242 do
993b3242 243 {
40a55d20 244 tmpbuf = __alloca (tmpbuflen);
40a55d20
UD
245
246 r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
247 &s);
a0bf6ac7 248 if (r != 0 || s == NULL)
993b3242 249 {
a0bf6ac7 250 if (r == ERANGE)
40a55d20
UD
251 tmpbuflen *= 2;
252 else
253 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
993b3242
UD
254 }
255 }
40a55d20 256 while (r);
993b3242 257
238ae1eb
UD
258 st->next = NULL;
259 st->socktype = tp->socktype;
85599e53
UD
260 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
261 ? req->ai_protocol : tp->protocol);
238ae1eb 262 st->port = s->s_port;
46ec036d
UD
263
264 return 0;
265}
266
40a55d20
UD
267#define gethosts(_family, _type) \
268 { \
269 int i, herrno; \
270 size_t tmpbuflen; \
271 struct hostent th; \
272 char *tmpbuf; \
273 tmpbuflen = 512; \
7813b61a 274 no_data = 0; \
40a55d20
UD
275 do { \
276 tmpbuflen *= 2; \
277 tmpbuf = __alloca (tmpbuflen); \
40a55d20
UD
278 rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \
279 tmpbuflen, &h, &herrno); \
4fe53b3a 280 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
fb7268b2 281 if (rc != 0) \
40a55d20 282 { \
fb7268b2
UD
283 if (herrno == NETDB_INTERNAL) \
284 { \
285 __set_h_errno (herrno); \
286 return -EAI_SYSTEM; \
287 } \
288 if (herrno == TRY_AGAIN) \
7813b61a
UD
289 no_data = EAI_AGAIN; \
290 else \
291 no_data = herrno == NO_DATA; \
40a55d20 292 } \
7813b61a 293 else if (h != NULL) \
40a55d20
UD
294 { \
295 for (i = 0; h->h_addr_list[i]; i++) \
296 { \
85599e53 297 if (*pat == NULL) { \
a0bf6ac7 298 *pat = __alloca (sizeof(struct gaih_addrtuple)); \
85599e53
UD
299 (*pat)->scopeid = 0; \
300 } \
40a55d20
UD
301 (*pat)->next = NULL; \
302 (*pat)->family = _family; \
303 memcpy ((*pat)->addr, h->h_addr_list[i], \
304 sizeof(_type)); \
305 pat = &((*pat)->next); \
306 } \
307 } \
308 }
309
310static int
311gaih_inet (const char *name, const struct gaih_service *service,
312 const struct addrinfo *req, struct addrinfo **pai)
46ec036d 313{
3e2d61a3
UD
314 const struct gaih_typeproto *tp = gaih_inet_typeproto;
315 struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
1fb05e3d 316 struct gaih_addrtuple *at = NULL;
40a55d20 317 int rc;
46ec036d 318
40a55d20
UD
319 if (req->ai_protocol || req->ai_socktype)
320 {
f3ac48d0
UD
321 ++tp;
322
4b1fef84 323 while (tp->name[0]
3a47453d
UD
324 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
325 || (req->ai_protocol != 0
85599e53 326 && !(tp->protoflag & GAI_PROTO_PROTOANY)
3a47453d 327 && req->ai_protocol != tp->protocol)))
f3ac48d0
UD
328 ++tp;
329
4b1fef84 330 if (! tp->name[0])
6e4c40ba
UD
331 {
332 if (req->ai_socktype)
333 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
334 else
335 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
336 }
40a55d20
UD
337 }
338
339 if (service != NULL)
340 {
f3ac48d0
UD
341 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
342 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
343
40a55d20
UD
344 if (service->num < 0)
345 {
4b1fef84 346 if (tp->name[0])
40a55d20 347 {
238ae1eb
UD
348 st = (struct gaih_servtuple *)
349 __alloca (sizeof (struct gaih_servtuple));
350
85599e53 351 if ((rc = gaih_inet_serv (service->name, tp, req, st)))
40a55d20
UD
352 return rc;
353 }
354 else
355 {
356 struct gaih_servtuple **pst = &st;
4b1fef84 357 for (tp++; tp->name[0]; tp++)
40a55d20 358 {
3a47453d
UD
359 struct gaih_servtuple *newp;
360
361 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
362 continue;
363
84a4fd33
UD
364 if (req->ai_socktype != 0
365 && req->ai_socktype != tp->socktype)
366 continue;
85599e53
UD
367 if (req->ai_protocol != 0
368 && !(tp->protoflag & GAI_PROTO_PROTOANY)
369 && req->ai_protocol != tp->protocol)
370 continue;
84a4fd33 371
3a47453d 372 newp = (struct gaih_servtuple *)
238ae1eb
UD
373 __alloca (sizeof (struct gaih_servtuple));
374
85599e53 375 if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
40a55d20
UD
376 {
377 if (rc & GAIH_OKIFUNSPEC)
378 continue;
379 return rc;
380 }
238ae1eb
UD
381
382 *pst = newp;
383 pst = &(newp->next);
40a55d20 384 }
3e2d61a3 385 if (st == (struct gaih_servtuple *) &nullserv)
40a55d20
UD
386 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
387 }
46ec036d 388 }
40a55d20
UD
389 else
390 {
a0bf6ac7 391 st = __alloca (sizeof (struct gaih_servtuple));
40a55d20
UD
392 st->next = NULL;
393 st->socktype = tp->socktype;
85599e53
UD
394 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
395 ? req->ai_protocol : tp->protocol);
40a55d20 396 st->port = htons (service->num);
46ec036d 397 }
40a55d20 398 }
84a4fd33
UD
399 else if (req->ai_socktype || req->ai_protocol)
400 {
401 st = __alloca (sizeof (struct gaih_servtuple));
402 st->next = NULL;
85599e53
UD
403 st->socktype = tp->socktype;
404 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
405 ? req->ai_protocol : tp->protocol);
84a4fd33
UD
406 st->port = 0;
407 }
408 else
409 {
410 /* Neither socket type nor protocol is set. Return all socket types
411 we know about. */
412 struct gaih_servtuple **lastp = &st;
4b1fef84 413 for (++tp; tp->name[0]; ++tp)
84a4fd33
UD
414 {
415 struct gaih_servtuple *newp;
416
417 newp = __alloca (sizeof (struct gaih_servtuple));
418 newp->next = NULL;
419 newp->socktype = tp->socktype;
420 newp->protocol = tp->protocol;
421 newp->port = 0;
422
423 *lastp = newp;
424 lastp = &newp->next;
425 }
426 }
40a55d20
UD
427
428 if (name != NULL)
429 {
a0bf6ac7 430 at = __alloca (sizeof (struct gaih_addrtuple));
46ec036d 431
a0bf6ac7 432 at->family = AF_UNSPEC;
c0bc5f7b 433 at->scopeid = 0;
40a55d20 434 at->next = NULL;
46ec036d 435
a0bf6ac7
UD
436 if (inet_pton (AF_INET, name, at->addr) > 0)
437 {
438 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
439 at->family = AF_INET;
440 else
441 return -EAI_ADDRFAMILY;
442 }
46ec036d 443
c0bc5f7b 444 if (at->family == AF_UNSPEC)
a0bf6ac7 445 {
c0bc5f7b
UD
446 char *namebuf = strdupa (name);
447 char *scope_delim;
448
449 scope_delim = strchr (namebuf, SCOPE_DELIMITER);
450 if (scope_delim != NULL)
451 *scope_delim = '\0';
452
453 if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
454 {
c0bc5f7b
UD
455 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
456 at->family = AF_INET6;
457 else
458 return -EAI_ADDRFAMILY;
459
460 if (scope_delim != NULL)
461 {
462 int try_numericscope = 0;
463 if (IN6_IS_ADDR_LINKLOCAL (at->addr)
464 || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
465 {
466 at->scopeid = if_nametoindex (scope_delim + 1);
467 if (at->scopeid == 0)
468 try_numericscope = 1;
469 }
470 else
471 try_numericscope = 1;
472
473 if (try_numericscope != 0)
474 {
475 char *end;
476 assert (sizeof (uint32_t) <= sizeof (unsigned long));
477 at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
478 10);
479 if (*end != '\0')
480 return GAIH_OKIFUNSPEC | -EAI_NONAME;
481 }
482 }
483 }
a0bf6ac7 484 }
40a55d20 485
ce75c139 486 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
40a55d20
UD
487 {
488 struct hostent *h;
489 struct gaih_addrtuple **pat = &at;
a0bf6ac7 490 int no_data = 0;
5ad81f40 491 int no_inet6_data;
9c42c64d
UD
492 int old_res_options = _res.options;
493
494 /* If we are looking for both IPv4 and IPv6 address we don't
495 want the lookup functions to automatically promote IPv4
496 addresses to IPv6 addresses. Currently this is decided
497 by setting the RES_USE_INET6 bit in _res.options. */
498 if (req->ai_family == AF_UNSPEC)
499 _res.options &= ~RES_USE_INET6;
40a55d20 500
7396d844 501 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
40a55d20 502 gethosts (AF_INET6, struct in6_addr);
5ad81f40 503 no_inet6_data = no_data;
40a55d20 504
9c42c64d
UD
505 if (req->ai_family == AF_UNSPEC)
506 _res.options = old_res_options;
507
7396d844 508 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
40a55d20 509 gethosts (AF_INET, struct in_addr);
a0bf6ac7 510
5ad81f40 511 if (no_data != 0 && no_inet6_data != 0)
7813b61a
UD
512 {
513 /* If both requests timed out report this. */
514 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
515 return -EAI_AGAIN;
516
517 /* We made requests but they turned out no data. The name
518 is known, though. */
519 return (GAIH_OKIFUNSPEC | -EAI_NODATA);
520 }
46ec036d 521 }
40a55d20
UD
522
523 if (at->family == AF_UNSPEC)
524 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
46ec036d 525 }
40a55d20
UD
526 else
527 {
7396d844 528 struct gaih_addrtuple *atr;
a0bf6ac7
UD
529 atr = at = __alloca (sizeof (struct gaih_addrtuple));
530 memset (at, '\0', sizeof (struct gaih_addrtuple));
40a55d20 531
7396d844
UD
532 if (req->ai_family == 0)
533 {
a0bf6ac7
UD
534 at->next = __alloca (sizeof (struct gaih_addrtuple));
535 memset (at->next, '\0', sizeof (struct gaih_addrtuple));
7396d844 536 }
40a55d20 537
7396d844
UD
538 if (req->ai_family == 0 || req->ai_family == AF_INET6)
539 {
540 at->family = AF_INET6;
541 if ((req->ai_flags & AI_PASSIVE) == 0)
a585ba22 542 memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
7396d844
UD
543 atr = at->next;
544 }
40a55d20 545
7396d844
UD
546 if (req->ai_family == 0 || req->ai_family == AF_INET)
547 {
548 atr->family = AF_INET;
549 if ((req->ai_flags & AI_PASSIVE) == 0)
550 *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
551 }
46ec036d 552 }
1fb05e3d 553
40a55d20
UD
554 if (pai == NULL)
555 return 0;
46ec036d
UD
556
557 {
558 const char *c = NULL;
559 struct gaih_servtuple *st2;
560 struct gaih_addrtuple *at2 = at;
40a55d20 561 size_t socklen, namelen;
85599e53 562 sa_family_t family;
40a55d20 563
f21acc89
UD
564 /*
565 buffer is the size of an unformatted IPv6 address in printable format.
566 */
567 char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
46ec036d 568
40a55d20
UD
569 while (at2 != NULL)
570 {
571 if (req->ai_flags & AI_CANONNAME)
572 {
573 struct hostent *h = NULL;
46ec036d 574
40a55d20
UD
575 int herrno;
576 struct hostent th;
577 size_t tmpbuflen = 512;
578 char *tmpbuf;
46ec036d 579
40a55d20
UD
580 do
581 {
582 tmpbuflen *= 2;
583 tmpbuf = __alloca (tmpbuflen);
46ec036d 584
40a55d20
UD
585 if (tmpbuf == NULL)
586 return -EAI_MEMORY;
587
588 rc = __gethostbyaddr_r (at2->addr,
589 ((at2->family == AF_INET6)
590 ? sizeof(struct in6_addr)
591 : sizeof(struct in_addr)),
592 at2->family, &th, tmpbuf, tmpbuflen,
593 &h, &herrno);
594
595 }
a0bf6ac7 596 while (rc == errno && herrno == NETDB_INTERNAL);
40a55d20 597
a0bf6ac7 598 if (rc != 0 && herrno == NETDB_INTERNAL)
40a55d20
UD
599 {
600 __set_h_errno (herrno);
601 return -EAI_SYSTEM;
602 }
603
604 if (h == NULL)
605 c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer));
606 else
607 c = h->h_name;
608
609 if (c == NULL)
610 return GAIH_OKIFUNSPEC | -EAI_NONAME;
611
612 namelen = strlen (c) + 1;
613 }
614 else
615 namelen = 0;
616
617 if (at2->family == AF_INET6)
85599e53
UD
618 {
619 family = AF_INET6;
620 socklen = sizeof (struct sockaddr_in6);
621 }
40a55d20 622 else
85599e53
UD
623 {
624 family = AF_INET;
625 socklen = sizeof (struct sockaddr_in);
626 }
40a55d20
UD
627
628 for (st2 = st; st2 != NULL; st2 = st2->next)
629 {
630 *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
631 if (*pai == NULL)
632 return -EAI_MEMORY;
633
634 (*pai)->ai_flags = req->ai_flags;
85599e53 635 (*pai)->ai_family = family;
40a55d20
UD
636 (*pai)->ai_socktype = st2->socktype;
637 (*pai)->ai_protocol = st2->protocol;
638 (*pai)->ai_addrlen = socklen;
639 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
46ec036d 640#if SALEN
c0bc5f7b 641 (*pai)->ai_addr->sa_len = socklen;
46ec036d 642#endif /* SALEN */
85599e53 643 (*pai)->ai_addr->sa_family = family;
5a97622d 644
85599e53 645 if (family == AF_INET6)
40a55d20
UD
646 {
647 struct sockaddr_in6 *sin6p =
648 (struct sockaddr_in6 *) (*pai)->ai_addr;
46ec036d 649
40a55d20
UD
650 sin6p->sin6_flowinfo = 0;
651 memcpy (&sin6p->sin6_addr,
652 at2->addr, sizeof (struct in6_addr));
c0bc5f7b
UD
653 sin6p->sin6_port = st2->port;
654 sin6p->sin6_scope_id = at2->scopeid;
40a55d20
UD
655 }
656 else
657 {
658 struct sockaddr_in *sinp =
659 (struct sockaddr_in *) (*pai)->ai_addr;
660 memcpy (&sinp->sin_addr,
661 at2->addr, sizeof (struct in_addr));
c0bc5f7b 662 sinp->sin_port = st2->port;
40a55d20
UD
663 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
664 }
46ec036d 665
40a55d20
UD
666 if (c)
667 {
668 (*pai)->ai_canonname = ((void *) (*pai) +
669 sizeof (struct addrinfo) + socklen);
670 strcpy ((*pai)->ai_canonname, c);
671 }
672 else
673 (*pai)->ai_canonname = NULL;
46ec036d 674
40a55d20
UD
675 (*pai)->ai_next = NULL;
676 pai = &((*pai)->ai_next);
677 }
46ec036d 678
40a55d20
UD
679 at2 = at2->next;
680 }
46ec036d 681 }
40a55d20 682 return 0;
46ec036d
UD
683}
684
40a55d20
UD
685static struct gaih gaih[] =
686 {
687 { PF_INET6, gaih_inet },
688 { PF_INET, gaih_inet },
64b7897d 689#if 0
40a55d20 690 { PF_LOCAL, gaih_local },
64b7897d 691#endif
40a55d20
UD
692 { PF_UNSPEC, NULL }
693 };
46ec036d 694
40a55d20
UD
695int
696getaddrinfo (const char *name, const char *service,
697 const struct addrinfo *hints, struct addrinfo **pai)
46ec036d 698{
a0bf6ac7 699 int i = 0, j = 0, last_i = 0;
1fb05e3d 700 struct addrinfo *p = NULL, **end;
46ec036d
UD
701 struct gaih *g = gaih, *pg = NULL;
702 struct gaih_service gaih_service, *pservice;
703
40a55d20 704 if (name != NULL && name[0] == '*' && name[1] == 0)
1fb05e3d
UD
705 name = NULL;
706
40a55d20 707 if (service != NULL && service[0] == '*' && service[1] == 0)
1fb05e3d
UD
708 service = NULL;
709
40a55d20 710 if (name == NULL && service == NULL)
46ec036d
UD
711 return EAI_NONAME;
712
40a55d20
UD
713 if (hints == NULL)
714 hints = &default_hints;
46ec036d 715
b09bb958 716 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST))
46ec036d
UD
717 return EAI_BADFLAGS;
718
40a55d20 719 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
46ec036d
UD
720 return EAI_BADFLAGS;
721
40a55d20
UD
722 if (service && service[0])
723 {
724 char *c;
725 gaih_service.name = service;
726 gaih_service.num = strtoul (gaih_service.name, &c, 10);
727 if (*c)
728 gaih_service.num = -1;
1fb05e3d 729 else
40a55d20
UD
730 /* Can't specify a numerical socket unless a protocol family was
731 given. */
85599e53 732 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
1fb05e3d 733 return EAI_SERVICE;
40a55d20
UD
734 pservice = &gaih_service;
735 }
736 else
46ec036d
UD
737 pservice = NULL;
738
1fb05e3d
UD
739 if (pai)
740 end = &p;
741 else
742 end = NULL;
743
40a55d20
UD
744 while (g->gaih)
745 {
7396d844 746 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
40a55d20
UD
747 {
748 j++;
7396d844 749 if (pg == NULL || pg->gaih != g->gaih)
40a55d20
UD
750 {
751 pg = g;
7396d844
UD
752 i = g->gaih (name, pservice, hints, end);
753 if (i != 0)
40a55d20 754 {
a0bf6ac7
UD
755 /* EAI_NODATA is a more specific result as it says that
756 we found a result but it is not usable. */
757 if (last_i != (GAIH_OKIFUNSPEC | -EAI_NODATA))
758 last_i = i;
759
7396d844 760 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
40a55d20
UD
761 continue;
762
763 if (p)
764 freeaddrinfo (p);
765
7396d844 766 return -(i & GAIH_EAI);
40a55d20
UD
767 }
768 if (end)
769 while(*end) end = &((*end)->ai_next);
770 }
46ec036d 771 }
40a55d20 772 ++g;
46ec036d 773 }
46ec036d 774
40a55d20 775 if (j == 0)
46ec036d
UD
776 return EAI_FAMILY;
777
40a55d20
UD
778 if (p)
779 {
780 *pai = p;
781 return 0;
782 }
46ec036d 783
a0bf6ac7 784 if (pai == NULL && last_i == 0)
1fb05e3d
UD
785 return 0;
786
46ec036d 787 if (p)
40a55d20 788 freeaddrinfo (p);
46ec036d 789
a0bf6ac7 790 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
46ec036d 791}
9b0b40d3 792libc_hidden_def (getaddrinfo)
46ec036d 793
40a55d20
UD
794void
795freeaddrinfo (struct addrinfo *ai)
46ec036d
UD
796{
797 struct addrinfo *p;
798
40a55d20
UD
799 while (ai != NULL)
800 {
801 p = ai;
802 ai = ai->ai_next;
803 free (p);
804 }
46ec036d 805}
9b0b40d3 806libc_hidden_def (freeaddrinfo)