2 * Copyright 1996 by Craig Metz
3 * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
4 * Portions from the GNU C library,
5 * Copyright (C) 2003, 2006 Free Software Foundation, Inc.
7 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
10 /* $USAGI: getaddrinfo.c,v 1.16 2001/10/04 09:52:03 sekiya Exp $ */
12 /* The Inner Net License, Version 2.00
14 The author(s) grant permission for redistribution and use in source and
15 binary forms, with or without modification, of the software and documentation
16 provided that the following conditions are met:
18 0. If you receive a version of the software that is specifically labelled
19 as not being for redistribution (check the version message and/or README),
20 you are not permitted to redistribute that version of the software in any
22 1. All terms of the all other applicable copyrights and licenses must be
24 2. Redistributions of source code must retain the authors' copyright
25 notice(s), this list of conditions, and the following disclaimer.
26 3. Redistributions in binary form must reproduce the authors' copyright
27 notice(s), this list of conditions, and the following disclaimer in the
28 documentation and/or other materials provided with the distribution.
29 4. All advertising materials mentioning features or use of this software
30 must display the following acknowledgement with the name(s) of the
31 authors as specified in the copyright notice(s) substituted where
34 This product includes software developed by <name(s)>, The Inner
35 Net, and other contributors.
37 5. Neither the name(s) of the author(s) nor the names of its contributors
38 may be used to endorse or promote products derived from this software
39 without specific prior written permission.
41 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
42 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
43 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
45 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
48 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 If these license terms cause you a real problem, contact the author. */
59 #ifdef __UCLIBC_HAS_TLS__
67 #include <arpa/inet.h>
68 #include <sys/socket.h>
69 #include <netinet/in.h>
70 #include <sys/types.h>
72 #include <sys/utsname.h>
76 #define GAIH_OKIFUNSPEC 0x0100
77 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
80 #define UNIX_PATH_MAX 108
83 /* Useful for having small structure members/global variables */
84 typedef int8_t socktype_t;
85 typedef int8_t family_t;
86 typedef int8_t protocol_t;
87 struct BUG_too_small {
88 char BUG_socktype_t_too_small[(0
93 char BUG_family_t_too_small[(0
98 char BUG_protocol_t_too_small[(0
104 struct gaih_service {
109 struct gaih_servtuple {
110 struct gaih_servtuple *next;
116 struct gaih_addrtuple {
117 struct gaih_addrtuple *next;
123 struct gaih_typeproto {
129 /* Values for `protoflag'. */
130 #define GAI_PROTO_NOSERVICE 1
131 #define GAI_PROTO_PROTOANY 2
133 static const struct gaih_typeproto gaih_inet_typeproto[] = {
135 { SOCK_STREAM, IPPROTO_TCP, 0, "tcp" },
136 { SOCK_DGRAM , IPPROTO_UDP, 0, "udp" },
137 { SOCK_RAW , 0 , GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE, "raw" },
143 int (*gaih)(const char *name, const struct gaih_service *service,
144 const struct addrinfo *req, struct addrinfo **pai);
150 static unsigned __check_pf(void)
154 #if defined __UCLIBC_SUPPORT_AI_ADDRCONFIG__
157 struct ifaddrs *runp;
159 /* Get the interface list via getifaddrs. */
160 if (getifaddrs(&ifa) != 0) {
161 /* We cannot determine what interfaces are available.
163 #if defined __UCLIBC_HAS_IPV4__
166 #if defined __UCLIBC_HAS_IPV6__
172 for (runp = ifa; runp != NULL; runp = runp->ifa_next) {
173 if (runp->ifa_addr == NULL)
175 #if defined __UCLIBC_HAS_IPV4__
176 if (runp->ifa_addr->sa_family == PF_INET)
179 #if defined __UCLIBC_HAS_IPV6__
180 if (runp->ifa_addr->sa_family == PF_INET6)
188 /* AI_ADDRCONFIG is disabled, assume both ipv4 and ipv6 available. */
189 #if defined __UCLIBC_HAS_IPV4__
192 #if defined __UCLIBC_HAS_IPV6__
196 #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
201 static int addrconfig(sa_family_t af)
205 int saved_errno = errno;
209 #if defined __UCLIBC_HAS_IPV4__
211 ret = seen & SEEN_IPV4;
214 #if defined __UCLIBC_HAS_IPV6__
216 ret = seen & SEEN_IPV6;
220 s = socket(af, SOCK_DGRAM, 0);
221 ret = 1; /* Assume PF_UNIX. */
228 __set_errno(saved_errno);
233 /* Using Unix sockets this way is a security risk. */
235 gaih_local(const char *name, const struct gaih_service *service,
236 const struct addrinfo *req, struct addrinfo **pai)
238 struct utsname utsname;
239 struct addrinfo *ai = *pai;
241 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
242 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
244 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
245 if (uname(&utsname) < 0)
249 if (strcmp(name, "localhost") &&
250 strcmp(name, "local") &&
251 strcmp(name, "unix") &&
252 strcmp(name, utsname.nodename))
253 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
256 if (req->ai_protocol || req->ai_socktype) {
257 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
260 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
261 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
262 || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY) && req->ai_protocol != tp->protocol))
267 if (req->ai_socktype)
268 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
269 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
273 *pai = ai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_un)
274 + ((req->ai_flags & AI_CANONNAME)
275 ? (strlen(utsname.nodename) + 1) : 0));
280 ai->ai_flags = req->ai_flags;
281 ai->ai_family = AF_LOCAL;
282 ai->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
283 ai->ai_protocol = req->ai_protocol;
284 ai->ai_addrlen = sizeof(struct sockaddr_un);
285 ai->ai_addr = (void *)ai + sizeof(struct addrinfo);
287 ((struct sockaddr_un *)ai->ai_addr)->sun_len = sizeof(struct sockaddr_un);
290 ((struct sockaddr_un *)ai->ai_addr)->sun_family = AF_LOCAL;
291 memset(((struct sockaddr_un *)ai->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
294 struct sockaddr_un *sunp = (struct sockaddr_un *)ai->ai_addr;
296 if (strchr(service->name, '/') != NULL) {
297 if (strlen(service->name) >= sizeof(sunp->sun_path))
298 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
299 strcpy(sunp->sun_path, service->name);
301 if (strlen(P_tmpdir "/") + 1 + strlen(service->name) >= sizeof(sunp->sun_path))
302 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
303 stpcpy(stpcpy(sunp->sun_path, P_tmpdir "/"), service->name);
306 /* This is a dangerous use of the interface since there is a time
307 window between the test for the file and the actual creation
308 (done by the caller) in which a file with the same name could
310 char *buf = ((struct sockaddr_un *)ai->ai_addr)->sun_path;
312 if (__path_search(buf, L_tmpnam, NULL, NULL, 0) != 0
313 || __gen_tempname(buf, __GT_NOCREATE, 0) != 0
319 ai->ai_canonname = NULL;
320 if (req->ai_flags & AI_CANONNAME)
321 ai->ai_canonname = strcpy((char *)(ai + 1) + sizeof(struct sockaddr_un),
328 gaih_inet_serv(const char *servicename, const struct gaih_typeproto *tp,
329 const struct addrinfo *req, struct gaih_servtuple *st)
332 size_t tmpbuflen = 1024;
338 tmpbuf = alloca(tmpbuflen);
339 r = getservbyname_r(servicename, tp->name, &ts, tmpbuf, tmpbuflen, &s);
340 if (r == 0 && s != NULL)
343 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
347 st->socktype = tp->socktype;
348 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) ? req->ai_protocol : tp->protocol);
349 st->port = s->s_port;
353 /* NB: also uses h,pat,rc,no_data variables */
354 #define gethosts(_family, _type) \
365 tmpbuf = alloca(tmpbuflen); \
366 rc = gethostbyname2_r(name, _family, &th, tmpbuf, \
367 tmpbuflen, &h, &herrno); \
368 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
370 if (herrno == NETDB_INTERNAL) { \
371 __set_h_errno(herrno); \
372 return -EAI_SYSTEM; \
374 if (herrno == TRY_AGAIN) \
375 no_data = EAI_AGAIN; \
377 no_data = (herrno == NO_DATA); \
378 } else if (h != NULL) { \
379 for (i = 0; h->h_addr_list[i]; i++) { \
380 if (*pat == NULL) { \
381 *pat = alloca(sizeof(struct gaih_addrtuple)); \
382 (*pat)->scopeid = 0; \
384 (*pat)->next = NULL; \
385 (*pat)->family = _family; \
386 memcpy((*pat)->addr, h->h_addr_list[i], sizeof(_type)); \
387 pat = &((*pat)->next); \
393 gaih_inet(const char *name, const struct gaih_service *service,
394 const struct addrinfo *req, struct addrinfo **pai)
396 struct gaih_servtuple nullserv;
398 const struct gaih_typeproto *tp;
399 struct gaih_servtuple *st;
400 struct gaih_addrtuple *at;
402 int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6)
403 && (req->ai_flags & AI_V4MAPPED);
404 unsigned seen = __check_pf();
406 memset(&nullserv, 0, sizeof(nullserv));
408 tp = gaih_inet_typeproto;
409 if (req->ai_protocol || req->ai_socktype) {
411 while (tp->name[0]) {
412 if ((req->ai_socktype == 0 || req->ai_socktype == tp->socktype)
413 && (req->ai_protocol == 0 || req->ai_protocol == tp->protocol || (tp->protoflag & GAI_PROTO_PROTOANY))
419 if (req->ai_socktype)
420 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
421 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
426 if (service != NULL) {
427 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
428 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
430 if (service->num < 0) {
432 st = alloca(sizeof(struct gaih_servtuple));
433 rc = gaih_inet_serv(service->name, tp, req, st);
437 struct gaih_servtuple **pst = &st;
438 for (tp++; tp->name[0]; tp++) {
439 struct gaih_servtuple *newp;
441 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
444 if (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
446 if (req->ai_protocol != 0
447 && !(tp->protoflag & GAI_PROTO_PROTOANY)
448 && req->ai_protocol != tp->protocol)
451 newp = alloca(sizeof(struct gaih_servtuple));
452 rc = gaih_inet_serv(service->name, tp, req, newp);
454 if (rc & GAIH_OKIFUNSPEC)
463 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
466 st = alloca(sizeof(struct gaih_servtuple));
468 st->socktype = tp->socktype;
469 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
470 ? req->ai_protocol : tp->protocol);
471 st->port = htons(service->num);
473 } else if (req->ai_socktype || req->ai_protocol) {
474 st = alloca(sizeof(struct gaih_servtuple));
476 st->socktype = tp->socktype;
477 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
478 ? req->ai_protocol : tp->protocol);
482 * Neither socket type nor protocol is set. Return all socket types
485 struct gaih_servtuple **lastp = &st;
486 for (++tp; tp->name[0]; ++tp) {
487 struct gaih_servtuple *newp;
489 newp = alloca(sizeof(struct gaih_servtuple));
491 newp->socktype = tp->socktype;
492 newp->protocol = tp->protocol;
502 at = alloca(sizeof(struct gaih_addrtuple));
503 at->family = AF_UNSPEC;
507 if (inet_pton(AF_INET, name, at->addr) > 0) {
508 if (req->ai_family != AF_UNSPEC && req->ai_family != AF_INET && !v4mapped)
510 at->family = AF_INET;
513 #if defined __UCLIBC_HAS_IPV6__
514 if (at->family == AF_UNSPEC) {
515 char *namebuf = strdupa(name);
518 scope_delim = strchr(namebuf, SCOPE_DELIMITER);
519 if (scope_delim != NULL)
522 if (inet_pton(AF_INET6, namebuf, at->addr) > 0) {
523 if (req->ai_family != AF_UNSPEC && req->ai_family != AF_INET6)
525 at->family = AF_INET6;
526 if (scope_delim != NULL) {
527 int try_numericscope = 0;
528 uint32_t *a32 = (uint32_t*)at->addr;
529 if (IN6_IS_ADDR_LINKLOCAL(a32) || IN6_IS_ADDR_MC_LINKLOCAL(at->addr)) {
530 at->scopeid = if_nametoindex(scope_delim + 1);
531 if (at->scopeid == 0)
532 try_numericscope = 1;
534 try_numericscope = 1;
536 if (try_numericscope != 0) {
538 assert(sizeof(uint32_t) <= sizeof(unsigned long));
539 at->scopeid = (uint32_t)strtoul(scope_delim + 1, &end, 10);
541 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
548 if (at->family == AF_UNSPEC && !(req->ai_flags & AI_NUMERICHOST)) {
550 struct gaih_addrtuple **pat = &at;
555 * If we are looking for both IPv4 and IPv6 address we don't want
556 * the lookup functions to automatically promote IPv4 addresses to
559 #if defined __UCLIBC_HAS_IPV6__
560 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
561 if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV6))
562 gethosts(AF_INET6, struct in6_addr);
564 no_inet6_data = no_data;
566 if (req->ai_family == AF_INET
567 || (!v4mapped && req->ai_family == AF_UNSPEC)
568 || (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL)))
570 if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV4))
571 gethosts(AF_INET, struct in_addr);
574 if (no_data != 0 && no_inet6_data != 0) {
575 /* If both requests timed out report this. */
576 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
579 * We made requests but they turned out no data.
580 * The name is known, though.
582 return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
586 if (at->family == AF_UNSPEC)
587 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
589 struct gaih_addrtuple *atr;
591 atr = at = alloca(sizeof(struct gaih_addrtuple));
592 memset(at, '\0', sizeof(struct gaih_addrtuple));
593 if (req->ai_family == 0) {
594 at->next = alloca(sizeof(struct gaih_addrtuple));
595 memset(at->next, '\0', sizeof(struct gaih_addrtuple));
597 #if defined __UCLIBC_HAS_IPV6__
598 if (req->ai_family == 0 || req->ai_family == AF_INET6) {
599 at->family = AF_INET6;
600 if ((req->ai_flags & AI_PASSIVE) == 0)
601 memcpy(at->addr, &in6addr_loopback, sizeof(struct in6_addr));
605 if (req->ai_family == 0 || req->ai_family == AF_INET) {
606 atr->family = AF_INET;
607 if ((req->ai_flags & AI_PASSIVE) == 0) {
608 uint32_t *a = (uint32_t*)atr->addr;
609 *a = htonl(INADDR_LOOPBACK);
618 const char *c = NULL;
619 struct gaih_servtuple *st2;
620 struct gaih_addrtuple *at2 = at;
621 size_t socklen, namelen;
625 * buffer is the size of an unformatted IPv6 address in
628 char buffer[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
630 while (at2 != NULL) {
631 if (req->ai_flags & AI_CANONNAME) {
632 struct hostent *h = NULL;
635 size_t tmpbuflen = 512;
640 tmpbuf = alloca(tmpbuflen);
641 rc = gethostbyaddr_r(at2->addr,
642 #ifdef __UCLIBC_HAS_IPV6__
643 ((at2->family == AF_INET6)
644 ? sizeof(struct in6_addr)
645 : sizeof(struct in_addr)),
647 sizeof(struct in_addr),
650 &th, tmpbuf, tmpbuflen,
652 } while (rc == ERANGE && herrno == NETDB_INTERNAL);
654 if (rc != 0 && herrno == NETDB_INTERNAL) {
655 __set_h_errno(herrno);
660 c = inet_ntop(at2->family, at2->addr, buffer, sizeof(buffer));
665 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
667 namelen = strlen(c) + 1;
671 #if defined __UCLIBC_HAS_IPV6__
672 if (at2->family == AF_INET6 || v4mapped) {
674 socklen = sizeof(struct sockaddr_in6);
677 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
680 #if defined __UCLIBC_HAS_IPV4__
683 socklen = sizeof(struct sockaddr_in);
686 for (st2 = st; st2 != NULL; st2 = st2->next) {
687 if (req->ai_flags & AI_ADDRCONFIG) {
688 if (family == AF_INET && !(seen & SEEN_IPV4))
690 #if defined __UCLIBC_HAS_IPV6__
691 else if (family == AF_INET6 && !(seen & SEEN_IPV6))
695 *pai = malloc(sizeof(struct addrinfo) + socklen + namelen);
699 (*pai)->ai_flags = req->ai_flags;
700 (*pai)->ai_family = family;
701 (*pai)->ai_socktype = st2->socktype;
702 (*pai)->ai_protocol = st2->protocol;
703 (*pai)->ai_addrlen = socklen;
704 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
706 (*pai)->ai_addr->sa_len = socklen;
708 (*pai)->ai_addr->sa_family = family;
710 #if defined __UCLIBC_HAS_IPV6__
711 if (family == AF_INET6) {
712 struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) (*pai)->ai_addr;
714 sin6p->sin6_flowinfo = 0;
715 if (at2->family == AF_INET6) {
716 memcpy(&sin6p->sin6_addr,
717 at2->addr, sizeof(struct in6_addr));
719 sin6p->sin6_addr.s6_addr32[0] = 0;
720 sin6p->sin6_addr.s6_addr32[1] = 0;
721 sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
722 memcpy(&sin6p->sin6_addr.s6_addr32[3],
723 at2->addr, sizeof(sin6p->sin6_addr.s6_addr32[3]));
725 sin6p->sin6_port = st2->port;
726 sin6p->sin6_scope_id = at2->scopeid;
729 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
732 #if defined __UCLIBC_HAS_IPV4__
734 struct sockaddr_in *sinp = (struct sockaddr_in *) (*pai)->ai_addr;
736 memcpy(&sinp->sin_addr, at2->addr, sizeof(struct in_addr));
737 sinp->sin_port = st2->port;
738 memset(sinp->sin_zero, '\0', sizeof(sinp->sin_zero));
742 (*pai)->ai_canonname = ((void *) (*pai) +
743 sizeof(struct addrinfo) + socklen);
744 strcpy((*pai)->ai_canonname, c);
746 (*pai)->ai_canonname = NULL;
748 (*pai)->ai_next = NULL;
749 pai = &((*pai)->ai_next);
758 static const struct gaih gaih[] = {
759 #if defined __UCLIBC_HAS_IPV6__
760 { PF_INET6, gaih_inet },
762 { PF_INET, gaih_inet },
764 { PF_LOCAL, gaih_local },
770 freeaddrinfo(struct addrinfo *ai)
780 libc_hidden_def(freeaddrinfo)
783 getaddrinfo(const char *name, const char *service,
784 const struct addrinfo *hints, struct addrinfo **pai)
787 struct addrinfo *p, **end;
788 const struct gaih *g, *pg;
789 struct gaih_service gaih_service, *pservice;
790 struct addrinfo default_hints;
792 if (name != NULL && name[0] == '*' && name[1] == 0)
795 if (service != NULL && service[0] == '*' && service[1] == 0)
798 if (name == NULL && service == NULL)
802 memset(&default_hints, 0, sizeof(default_hints));
804 default_hints.ai_family = AF_UNSPEC;
805 hints = &default_hints;
808 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
809 AI_ADDRCONFIG|AI_V4MAPPED|AI_NUMERICSERV|AI_ALL))
812 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
815 if (service && service[0]) {
817 gaih_service.name = service;
818 gaih_service.num = strtoul(gaih_service.name, &c, 10);
820 if (hints->ai_flags & AI_NUMERICSERV)
822 gaih_service.num = -1;
825 * Can't specify a numerical socket unless a protocol
828 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
831 pservice = &gaih_service;
845 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC) {
846 if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family)) {
851 if (pg == NULL || pg->gaih != g->gaih) {
853 i = g->gaih(name, pservice, hints, end);
856 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
858 /*if (p) - freeaddrinfo works ok on NULL too */
860 return -(i & GAIH_EAI);
864 end = &((*end)->ai_next);
878 if (pai == NULL && last_i == 0)
881 /* if (p) - never happens, see above */
882 /* freeaddrinfo(p); */
884 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
886 libc_hidden_def(getaddrinfo)