(gaih_inet): Fix code to determine canonical name.
[glibc.git] / sysdeps / posix / getaddrinfo.c
blob2dc5e90a32fa3fe9239e5e4de768a85021c80430
1 /* The Inner Net License, Version 2.00
3 The author(s) grant permission for redistribution and use in source and
4 binary forms, with or without modification, of the software and documentation
5 provided that the following conditions are met:
7 0. 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.
11 1. All terms of the all other applicable copyrights and licenses must be
12 followed.
13 2. Redistributions of source code must retain the authors' copyright
14 notice(s), this list of conditions, and the following disclaimer.
15 3. 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.
18 4. [The copyright holder has authorized the removal of this clause.]
19 5. 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.
23 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
24 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
27 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 ANY 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
32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 If these license terms cause you a real problem, contact the author. */
36 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
38 #include <assert.h>
39 #include <errno.h>
40 #include <netdb.h>
41 #include <resolv.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <arpa/inet.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <sys/types.h>
50 #include <sys/un.h>
51 #include <sys/utsname.h>
52 #include <net/if.h>
54 #define GAIH_OKIFUNSPEC 0x0100
55 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
57 #ifndef UNIX_PATH_MAX
58 #define UNIX_PATH_MAX 108
59 #endif
61 struct gaih_service
63 const char *name;
64 int num;
67 struct gaih_servtuple
69 struct gaih_servtuple *next;
70 int socktype;
71 int protocol;
72 int port;
75 static const struct gaih_servtuple nullserv;
77 struct gaih_addrtuple
79 struct gaih_addrtuple *next;
80 int family;
81 char addr[16];
82 uint32_t scopeid;
85 struct gaih_typeproto
87 int socktype;
88 int protocol;
89 char name[4];
90 int protoflag;
93 /* Values for `protoflag'. */
94 #define GAI_PROTO_NOSERVICE 1
95 #define GAI_PROTO_PROTOANY 2
97 static const struct gaih_typeproto gaih_inet_typeproto[] =
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 }
106 struct gaih
108 int family;
109 int (*gaih)(const char *name, const struct gaih_service *service,
110 const struct addrinfo *req, struct addrinfo **pai);
113 #if PF_UNSPEC == 0
114 static const struct addrinfo default_hints;
115 #else
116 static const struct addrinfo default_hints =
117 { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
118 #endif
121 #if 0
122 /* Using Unix sockets this way is a security risk. */
123 static int
124 gaih_local (const char *name, const struct gaih_service *service,
125 const struct addrinfo *req, struct addrinfo **pai)
127 struct utsname utsname;
129 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
130 return GAIH_OKIFUNSPEC | -EAI_NONAME;
132 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
133 if (uname (&utsname) < 0)
134 return -EAI_SYSTEM;
136 if (name != NULL)
138 if (strcmp(name, "localhost") &&
139 strcmp(name, "local") &&
140 strcmp(name, "unix") &&
141 strcmp(name, utsname.nodename))
142 return GAIH_OKIFUNSPEC | -EAI_NONAME;
145 if (req->ai_protocol || req->ai_socktype)
147 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
149 while (tp->name[0]
150 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
151 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
152 || (req->ai_protocol != 0
153 && !(tp->protoflag & GAI_PROTO_PROTOANY)
154 && req->ai_protocol != tp->protocol)))
155 ++tp;
157 if (! tp->name[0])
159 if (req->ai_socktype)
160 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
161 else
162 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
166 *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
167 + ((req->ai_flags & AI_CANONNAME)
168 ? (strlen(utsname.nodename) + 1): 0));
169 if (*pai == NULL)
170 return -EAI_MEMORY;
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;
177 (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
178 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
180 #if SALEN
181 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
182 sizeof (struct sockaddr_un);
183 #endif /* SALEN */
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);
188 if (service)
190 struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
192 if (strchr (service->name, '/') != NULL)
194 if (strlen (service->name) >= sizeof (sunp->sun_path))
195 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
197 strcpy (sunp->sun_path, service->name);
199 else
201 if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
202 sizeof (sunp->sun_path))
203 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
205 __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
208 else
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;
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)
219 return -EAI_SYSTEM;
222 if (req->ai_flags & AI_CANONNAME)
223 (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
224 + sizeof (struct sockaddr_un),
225 utsname.nodename);
226 else
227 (*pai)->ai_canonname = NULL;
228 return 0;
230 #endif /* 0 */
232 static int
233 gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
234 const struct addrinfo *req, struct gaih_servtuple *st)
236 struct servent *s;
237 size_t tmpbuflen = 1024;
238 struct servent ts;
239 char *tmpbuf;
240 int r;
244 tmpbuf = __alloca (tmpbuflen);
246 r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
247 &s);
248 if (r != 0 || s == NULL)
250 if (r == ERANGE)
251 tmpbuflen *= 2;
252 else
253 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
256 while (r);
258 st->next = NULL;
259 st->socktype = tp->socktype;
260 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
261 ? req->ai_protocol : tp->protocol);
262 st->port = s->s_port;
264 return 0;
267 #define gethosts(_family, _type) \
269 int i, herrno; \
270 size_t tmpbuflen; \
271 struct hostent th; \
272 char *tmpbuf; \
273 tmpbuflen = 512; \
274 no_data = 0; \
275 do { \
276 tmpbuflen *= 2; \
277 tmpbuf = __alloca (tmpbuflen); \
278 rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \
279 tmpbuflen, &h, &herrno); \
280 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
281 if (rc != 0) \
283 if (herrno == NETDB_INTERNAL) \
285 __set_h_errno (herrno); \
286 return -EAI_SYSTEM; \
288 if (herrno == TRY_AGAIN) \
289 no_data = EAI_AGAIN; \
290 else \
291 no_data = herrno == NO_DATA; \
293 else if (h != NULL) \
295 for (i = 0; h->h_addr_list[i]; i++) \
297 if (*pat == NULL) { \
298 *pat = __alloca (sizeof(struct gaih_addrtuple)); \
299 (*pat)->scopeid = 0; \
301 (*pat)->next = NULL; \
302 (*pat)->family = _family; \
303 memcpy ((*pat)->addr, h->h_addr_list[i], \
304 sizeof(_type)); \
305 pat = &((*pat)->next); \
310 static int
311 gaih_inet (const char *name, const struct gaih_service *service,
312 const struct addrinfo *req, struct addrinfo **pai)
314 const struct gaih_typeproto *tp = gaih_inet_typeproto;
315 struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
316 struct gaih_addrtuple *at = NULL;
317 int rc;
319 if (req->ai_protocol || req->ai_socktype)
321 ++tp;
323 while (tp->name[0]
324 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
325 || (req->ai_protocol != 0
326 && !(tp->protoflag & GAI_PROTO_PROTOANY)
327 && req->ai_protocol != tp->protocol)))
328 ++tp;
330 if (! tp->name[0])
332 if (req->ai_socktype)
333 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
334 else
335 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
339 if (service != NULL)
341 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
342 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
344 if (service->num < 0)
346 if (tp->name[0])
348 st = (struct gaih_servtuple *)
349 __alloca (sizeof (struct gaih_servtuple));
351 if ((rc = gaih_inet_serv (service->name, tp, req, st)))
352 return rc;
354 else
356 struct gaih_servtuple **pst = &st;
357 for (tp++; tp->name[0]; tp++)
359 struct gaih_servtuple *newp;
361 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
362 continue;
364 if (req->ai_socktype != 0
365 && req->ai_socktype != tp->socktype)
366 continue;
367 if (req->ai_protocol != 0
368 && !(tp->protoflag & GAI_PROTO_PROTOANY)
369 && req->ai_protocol != tp->protocol)
370 continue;
372 newp = (struct gaih_servtuple *)
373 __alloca (sizeof (struct gaih_servtuple));
375 if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
377 if (rc & GAIH_OKIFUNSPEC)
378 continue;
379 return rc;
382 *pst = newp;
383 pst = &(newp->next);
385 if (st == (struct gaih_servtuple *) &nullserv)
386 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
389 else
391 st = __alloca (sizeof (struct gaih_servtuple));
392 st->next = NULL;
393 st->socktype = tp->socktype;
394 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
395 ? req->ai_protocol : tp->protocol);
396 st->port = htons (service->num);
399 else if (req->ai_socktype || req->ai_protocol)
401 st = __alloca (sizeof (struct gaih_servtuple));
402 st->next = NULL;
403 st->socktype = tp->socktype;
404 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
405 ? req->ai_protocol : tp->protocol);
406 st->port = 0;
408 else
410 /* Neither socket type nor protocol is set. Return all socket types
411 we know about. */
412 struct gaih_servtuple **lastp = &st;
413 for (++tp; tp->name[0]; ++tp)
415 struct gaih_servtuple *newp;
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;
423 *lastp = newp;
424 lastp = &newp->next;
428 if (name != NULL)
430 at = __alloca (sizeof (struct gaih_addrtuple));
432 at->family = AF_UNSPEC;
433 at->scopeid = 0;
434 at->next = NULL;
436 if (inet_pton (AF_INET, name, at->addr) > 0)
438 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
439 at->family = AF_INET;
440 else
441 return -EAI_ADDRFAMILY;
444 if (at->family == AF_UNSPEC)
446 char *namebuf = strdupa (name);
447 char *scope_delim;
449 scope_delim = strchr (namebuf, SCOPE_DELIMITER);
450 if (scope_delim != NULL)
451 *scope_delim = '\0';
453 if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
455 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
456 at->family = AF_INET6;
457 else
458 return -EAI_ADDRFAMILY;
460 if (scope_delim != NULL)
462 int try_numericscope = 0;
463 if (IN6_IS_ADDR_LINKLOCAL (at->addr)
464 || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
466 at->scopeid = if_nametoindex (scope_delim + 1);
467 if (at->scopeid == 0)
468 try_numericscope = 1;
470 else
471 try_numericscope = 1;
473 if (try_numericscope != 0)
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;
486 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
488 struct hostent *h;
489 struct gaih_addrtuple **pat = &at;
490 int no_data = 0;
491 int no_inet6_data;
492 int old_res_options = _res.options;
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;
501 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
502 gethosts (AF_INET6, struct in6_addr);
503 no_inet6_data = no_data;
505 if (req->ai_family == AF_UNSPEC)
506 _res.options = old_res_options;
508 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
509 gethosts (AF_INET, struct in_addr);
511 if (no_data != 0 && no_inet6_data != 0)
513 /* If both requests timed out report this. */
514 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
515 return -EAI_AGAIN;
517 /* We made requests but they turned out no data. The name
518 is known, though. */
519 return (GAIH_OKIFUNSPEC | -EAI_NODATA);
523 if (at->family == AF_UNSPEC)
524 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
526 else
528 struct gaih_addrtuple *atr;
529 atr = at = __alloca (sizeof (struct gaih_addrtuple));
530 memset (at, '\0', sizeof (struct gaih_addrtuple));
532 if (req->ai_family == 0)
534 at->next = __alloca (sizeof (struct gaih_addrtuple));
535 memset (at->next, '\0', sizeof (struct gaih_addrtuple));
538 if (req->ai_family == 0 || req->ai_family == AF_INET6)
540 at->family = AF_INET6;
541 if ((req->ai_flags & AI_PASSIVE) == 0)
542 memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
543 atr = at->next;
546 if (req->ai_family == 0 || req->ai_family == AF_INET)
548 atr->family = AF_INET;
549 if ((req->ai_flags & AI_PASSIVE) == 0)
550 *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
554 if (pai == NULL)
555 return 0;
558 const char *c = NULL;
559 struct gaih_servtuple *st2;
560 struct gaih_addrtuple *at2 = at;
561 size_t socklen, namelen;
562 sa_family_t family;
565 buffer is the size of an unformatted IPv6 address in printable format.
567 while (at2 != NULL)
569 if (req->ai_flags & AI_CANONNAME)
571 struct hostent *h = NULL;
573 int herrno;
574 struct hostent th;
575 size_t tmpbuflen = 512;
576 char *tmpbuf;
580 tmpbuflen *= 2;
581 tmpbuf = __alloca (tmpbuflen);
583 rc = __gethostbyaddr_r (at2->addr,
584 ((at2->family == AF_INET6)
585 ? sizeof(struct in6_addr)
586 : sizeof(struct in_addr)),
587 at2->family, &th, tmpbuf, tmpbuflen,
588 &h, &herrno);
591 while (rc == errno && herrno == NETDB_INTERNAL);
593 if (rc != 0 && herrno == NETDB_INTERNAL)
595 __set_h_errno (herrno);
596 return -EAI_SYSTEM;
599 if (h != NULL)
600 c = h->h_name;
601 else
603 /* We have to try to get the canonical in some other
604 way. If we are looking for either AF_INET or
605 AF_INET6 try the other line. */
606 if (req->ai_family == AF_UNSPEC)
608 struct addrinfo *p = NULL;
609 struct addrinfo **end = &p;
610 struct addrinfo localreq = *req;
611 struct addrinfo *runp;
613 localreq.ai_family = AF_INET + AF_INET6 - at2->family;
614 (void) gaih_inet (name, service, &localreq, end);
616 runp = p;
617 while (runp != NULL)
619 if (p->ai_canonname != name)
621 c = strdupa (p->ai_canonname);
622 break;
624 runp = runp->ai_next;
627 freeaddrinfo (p);
630 /* If this code is used the missing canonical name is
631 substituted with the name passed in by the user. */
632 if (c == NULL)
633 c = name;
636 if (c == NULL)
637 return GAIH_OKIFUNSPEC | -EAI_NONAME;
639 namelen = strlen (c) + 1;
641 else
642 namelen = 0;
644 if (at2->family == AF_INET6)
646 family = AF_INET6;
647 socklen = sizeof (struct sockaddr_in6);
649 else
651 family = AF_INET;
652 socklen = sizeof (struct sockaddr_in);
655 for (st2 = st; st2 != NULL; st2 = st2->next)
657 *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
658 if (*pai == NULL)
659 return -EAI_MEMORY;
661 (*pai)->ai_flags = req->ai_flags;
662 (*pai)->ai_family = family;
663 (*pai)->ai_socktype = st2->socktype;
664 (*pai)->ai_protocol = st2->protocol;
665 (*pai)->ai_addrlen = socklen;
666 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
667 #if SALEN
668 (*pai)->ai_addr->sa_len = socklen;
669 #endif /* SALEN */
670 (*pai)->ai_addr->sa_family = family;
672 if (family == AF_INET6)
674 struct sockaddr_in6 *sin6p =
675 (struct sockaddr_in6 *) (*pai)->ai_addr;
677 sin6p->sin6_flowinfo = 0;
678 memcpy (&sin6p->sin6_addr,
679 at2->addr, sizeof (struct in6_addr));
680 sin6p->sin6_port = st2->port;
681 sin6p->sin6_scope_id = at2->scopeid;
683 else
685 struct sockaddr_in *sinp =
686 (struct sockaddr_in *) (*pai)->ai_addr;
687 memcpy (&sinp->sin_addr,
688 at2->addr, sizeof (struct in_addr));
689 sinp->sin_port = st2->port;
690 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
693 if (c)
695 (*pai)->ai_canonname = ((void *) (*pai) +
696 sizeof (struct addrinfo) + socklen);
697 strcpy ((*pai)->ai_canonname, c);
699 else
700 (*pai)->ai_canonname = NULL;
702 (*pai)->ai_next = NULL;
703 pai = &((*pai)->ai_next);
706 at2 = at2->next;
709 return 0;
712 static struct gaih gaih[] =
714 { PF_INET6, gaih_inet },
715 { PF_INET, gaih_inet },
716 #if 0
717 { PF_LOCAL, gaih_local },
718 #endif
719 { PF_UNSPEC, NULL }
723 getaddrinfo (const char *name, const char *service,
724 const struct addrinfo *hints, struct addrinfo **pai)
726 int i = 0, j = 0, last_i = 0;
727 struct addrinfo *p = NULL, **end;
728 struct gaih *g = gaih, *pg = NULL;
729 struct gaih_service gaih_service, *pservice;
731 if (name != NULL && name[0] == '*' && name[1] == 0)
732 name = NULL;
734 if (service != NULL && service[0] == '*' && service[1] == 0)
735 service = NULL;
737 if (name == NULL && service == NULL)
738 return EAI_NONAME;
740 if (hints == NULL)
741 hints = &default_hints;
743 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST))
744 return EAI_BADFLAGS;
746 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
747 return EAI_BADFLAGS;
749 if (service && service[0])
751 char *c;
752 gaih_service.name = service;
753 gaih_service.num = strtoul (gaih_service.name, &c, 10);
754 if (*c)
755 gaih_service.num = -1;
756 else
757 /* Can't specify a numerical socket unless a protocol family was
758 given. */
759 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
760 return EAI_SERVICE;
761 pservice = &gaih_service;
763 else
764 pservice = NULL;
766 if (pai)
767 end = &p;
768 else
769 end = NULL;
771 while (g->gaih)
773 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
775 j++;
776 if (pg == NULL || pg->gaih != g->gaih)
778 pg = g;
779 i = g->gaih (name, pservice, hints, end);
780 if (i != 0)
782 /* EAI_NODATA is a more specific result as it says that
783 we found a result but it is not usable. */
784 if (last_i != (GAIH_OKIFUNSPEC | -EAI_NODATA))
785 last_i = i;
787 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
789 ++g;
790 continue;
793 freeaddrinfo (p);
795 return -(i & GAIH_EAI);
797 if (end)
798 while(*end) end = &((*end)->ai_next);
801 ++g;
804 if (j == 0)
805 return EAI_FAMILY;
807 if (p)
809 *pai = p;
810 return 0;
813 if (pai == NULL && last_i == 0)
814 return 0;
816 freeaddrinfo (p);
818 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
820 libc_hidden_def (getaddrinfo)
822 void
823 freeaddrinfo (struct addrinfo *ai)
825 struct addrinfo *p;
827 while (ai != NULL)
829 p = ai;
830 ai = ai->ai_next;
831 free (p);
834 libc_hidden_def (freeaddrinfo)