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. */
57 #ifdef __UCLIBC_HAS_TLS__
65 #include <arpa/inet.h>
66 #include <sys/socket.h>
67 #include <netinet/in.h>
68 #include <sys/types.h>
70 #include <sys/utsname.h>
74 #define GAIH_OKIFUNSPEC 0x0100
75 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
78 #define UNIX_PATH_MAX 108
81 /* Useful for having small structure members/global variables */
82 typedef int8_t socktype_t;
83 typedef int8_t family_t;
84 typedef int8_t protocol_t;
85 struct BUG_too_small {
86 char BUG_socktype_t_too_small[(0
91 char BUG_family_t_too_small[(0
96 char BUG_protocol_t_too_small[(0
102 struct gaih_service {
107 struct gaih_servtuple {
108 struct gaih_servtuple *next;
114 struct gaih_addrtuple {
115 struct gaih_addrtuple *next;
121 struct gaih_typeproto {
127 /* Values for `protoflag'. */
128 #define GAI_PROTO_NOSERVICE 1
129 #define GAI_PROTO_PROTOANY 2
131 static const struct gaih_typeproto gaih_inet_typeproto[] = {
133 { SOCK_STREAM, IPPROTO_TCP, 0, "tcp" },
134 { SOCK_DGRAM , IPPROTO_UDP, 0, "udp" },
135 { SOCK_RAW , 0 , GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE, "raw" },
141 int (*gaih)(const char *name, const struct gaih_service *service,
142 const struct addrinfo *req, struct addrinfo **pai);
148 static unsigned __check_pf(void)
152 #if defined __UCLIBC_SUPPORT_AI_ADDRCONFIG__
155 struct ifaddrs *runp;
157 /* Get the interface list via getifaddrs. */
158 if (getifaddrs(&ifa) != 0) {
159 /* We cannot determine what interfaces are available.
161 #if defined __UCLIBC_HAS_IPV4__
164 #if defined __UCLIBC_HAS_IPV6__
170 for (runp = ifa; runp != NULL; runp = runp->ifa_next) {
171 if (runp->ifa_addr == NULL)
173 #if defined __UCLIBC_HAS_IPV4__
174 if (runp->ifa_addr->sa_family == PF_INET)
177 #if defined __UCLIBC_HAS_IPV6__
178 if (runp->ifa_addr->sa_family == PF_INET6)
186 /* AI_ADDRCONFIG is disabled, assume both ipv4 and ipv6 available. */
187 #if defined __UCLIBC_HAS_IPV4__
190 #if defined __UCLIBC_HAS_IPV6__
194 #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
199 static int addrconfig(sa_family_t af)
203 int saved_errno = errno;
207 #if defined __UCLIBC_HAS_IPV4__
209 ret = seen & SEEN_IPV4;
212 #if defined __UCLIBC_HAS_IPV6__
214 ret = seen & SEEN_IPV6;
218 s = socket(af, SOCK_DGRAM, 0);
219 ret = 1; /* Assume PF_UNIX. */
226 __set_errno(saved_errno);
231 /* Using Unix sockets this way is a security risk. */
233 gaih_local(const char *name, const struct gaih_service *service,
234 const struct addrinfo *req, struct addrinfo **pai)
236 struct utsname utsname;
237 struct addrinfo *ai = *pai;
239 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
240 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
242 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
243 if (uname(&utsname) < 0)
247 if (strcmp(name, "localhost") &&
248 strcmp(name, "local") &&
249 strcmp(name, "unix") &&
250 strcmp(name, utsname.nodename))
251 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
254 if (req->ai_protocol || req->ai_socktype) {
255 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
258 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
259 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
260 || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY) && req->ai_protocol != tp->protocol))
265 if (req->ai_socktype)
266 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
267 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
271 *pai = ai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_un)
272 + ((req->ai_flags & AI_CANONNAME)
273 ? (strlen(utsname.nodename) + 1) : 0));
278 ai->ai_flags = req->ai_flags;
279 ai->ai_family = AF_LOCAL;
280 ai->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
281 ai->ai_protocol = req->ai_protocol;
282 ai->ai_addrlen = sizeof(struct sockaddr_un);
283 ai->ai_addr = (void *)ai + sizeof(struct addrinfo);
285 ((struct sockaddr_un *)ai->ai_addr)->sun_len = sizeof(struct sockaddr_un);
288 ((struct sockaddr_un *)ai->ai_addr)->sun_family = AF_LOCAL;
289 memset(((struct sockaddr_un *)ai->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
292 struct sockaddr_un *sunp = (struct sockaddr_un *)ai->ai_addr;
294 if (strchr(service->name, '/') != NULL) {
295 if (strlen(service->name) >= sizeof(sunp->sun_path))
296 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
297 strcpy(sunp->sun_path, service->name);
299 if (strlen(P_tmpdir "/") + 1 + strlen(service->name) >= sizeof(sunp->sun_path))
300 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
301 stpcpy(stpcpy(sunp->sun_path, P_tmpdir "/"), service->name);
304 /* This is a dangerous use of the interface since there is a time
305 window between the test for the file and the actual creation
306 (done by the caller) in which a file with the same name could
308 char *buf = ((struct sockaddr_un *)ai->ai_addr)->sun_path;
310 if (__path_search(buf, L_tmpnam, NULL, NULL, 0) != 0
311 || __gen_tempname(buf, __GT_NOCREATE, 0, 0) != 0
317 ai->ai_canonname = NULL;
318 if (req->ai_flags & AI_CANONNAME)
319 ai->ai_canonname = strcpy((char *)(ai + 1) + sizeof(struct sockaddr_un),
326 gaih_inet_serv(const char *servicename, const struct gaih_typeproto *tp,
327 const struct addrinfo *req, struct gaih_servtuple *st)
330 size_t tmpbuflen = 1024;
336 tmpbuf = alloca(tmpbuflen);
337 r = getservbyname_r(servicename, tp->name, &ts, tmpbuf, tmpbuflen, &s);
338 if (r == 0 && s != NULL)
341 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
345 st->socktype = tp->socktype;
346 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) ? req->ai_protocol : tp->protocol);
347 st->port = s->s_port;
351 /* NB: also uses h,pat,rc,no_data variables */
352 #define gethosts(_family, _type) \
363 tmpbuf = alloca(tmpbuflen); \
364 rc = gethostbyname2_r(name, _family, &th, tmpbuf, \
365 tmpbuflen, &h, &herrno); \
366 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
368 if (herrno == NETDB_INTERNAL) { \
369 __set_h_errno(herrno); \
370 return -EAI_SYSTEM; \
372 if (herrno == TRY_AGAIN) \
373 no_data = EAI_AGAIN; \
375 no_data = (herrno == NO_DATA); \
376 } else if (h != NULL) { \
377 for (i = 0; h->h_addr_list[i]; i++) { \
378 if (*pat == NULL) { \
379 *pat = alloca(sizeof(struct gaih_addrtuple)); \
380 (*pat)->scopeid = 0; \
382 (*pat)->next = NULL; \
383 (*pat)->family = _family; \
384 memcpy((*pat)->addr, h->h_addr_list[i], sizeof(_type)); \
385 pat = &((*pat)->next); \
391 gaih_inet(const char *name, const struct gaih_service *service,
392 const struct addrinfo *req, struct addrinfo **pai)
394 struct gaih_servtuple nullserv;
396 const struct gaih_typeproto *tp;
397 struct gaih_servtuple *st;
398 struct gaih_addrtuple *at;
400 int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6)
401 && (req->ai_flags & AI_V4MAPPED);
403 if (req->ai_flags & AI_ADDRCONFIG) {
404 /* "seen" is only used when AI_ADDRCONFIG is specified.
405 Avoid unnecessary call to __check_pf() otherwise
406 since it can be costly especially when RSBAC-Net is enabled. */
410 memset(&nullserv, 0, sizeof(nullserv));
412 tp = gaih_inet_typeproto;
413 if (req->ai_protocol || req->ai_socktype) {
415 while (tp->name[0]) {
416 if ((req->ai_socktype == 0 || req->ai_socktype == tp->socktype)
417 && (req->ai_protocol == 0 || req->ai_protocol == tp->protocol || (tp->protoflag & GAI_PROTO_PROTOANY))
423 if (req->ai_socktype)
424 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
425 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
430 if (service != NULL) {
431 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
432 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
434 if (service->num < 0) {
436 st = alloca(sizeof(struct gaih_servtuple));
437 rc = gaih_inet_serv(service->name, tp, req, st);
441 struct gaih_servtuple **pst = &st;
442 for (tp++; tp->name[0]; tp++) {
443 struct gaih_servtuple *newp;
445 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
448 if (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
450 if (req->ai_protocol != 0
451 && !(tp->protoflag & GAI_PROTO_PROTOANY)
452 && req->ai_protocol != tp->protocol)
455 newp = alloca(sizeof(struct gaih_servtuple));
456 rc = gaih_inet_serv(service->name, tp, req, newp);
458 if (rc & GAIH_OKIFUNSPEC)
467 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
470 st = alloca(sizeof(struct gaih_servtuple));
472 st->socktype = tp->socktype;
473 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
474 ? req->ai_protocol : tp->protocol);
475 st->port = htons(service->num);
477 } else if (req->ai_socktype || req->ai_protocol) {
478 st = alloca(sizeof(struct gaih_servtuple));
480 st->socktype = tp->socktype;
481 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
482 ? req->ai_protocol : tp->protocol);
486 * Neither socket type nor protocol is set. Return all socket types
489 struct gaih_servtuple **lastp = &st;
490 for (++tp; tp->name[0]; ++tp) {
491 struct gaih_servtuple *newp;
493 newp = alloca(sizeof(struct gaih_servtuple));
495 newp->socktype = tp->socktype;
496 newp->protocol = tp->protocol;
506 at = alloca(sizeof(struct gaih_addrtuple));
507 at->family = AF_UNSPEC;
511 if (inet_pton(AF_INET, name, at->addr) > 0) {
512 if (req->ai_family != AF_UNSPEC && req->ai_family != AF_INET && !v4mapped)
514 at->family = AF_INET;
517 #if defined __UCLIBC_HAS_IPV6__
518 if (at->family == AF_UNSPEC) {
519 char *namebuf = strdupa(name);
522 scope_delim = strchr(namebuf, SCOPE_DELIMITER);
523 if (scope_delim != NULL)
526 if (inet_pton(AF_INET6, namebuf, at->addr) > 0) {
527 if (req->ai_family != AF_UNSPEC && req->ai_family != AF_INET6)
529 at->family = AF_INET6;
530 if (scope_delim != NULL) {
531 int try_numericscope = 0;
532 uint32_t *a32 = (uint32_t*)at->addr;
533 if (IN6_IS_ADDR_LINKLOCAL(a32) || IN6_IS_ADDR_MC_LINKLOCAL(at->addr)) {
534 at->scopeid = if_nametoindex(scope_delim + 1);
535 if (at->scopeid == 0)
536 try_numericscope = 1;
538 try_numericscope = 1;
540 if (try_numericscope != 0) {
542 assert(sizeof(uint32_t) <= sizeof(unsigned long));
543 at->scopeid = (uint32_t)strtoul(scope_delim + 1, &end, 10);
545 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
552 if (at->family == AF_UNSPEC && !(req->ai_flags & AI_NUMERICHOST)) {
554 struct gaih_addrtuple **pat = &at;
559 * If we are looking for both IPv4 and IPv6 address we don't want
560 * the lookup functions to automatically promote IPv4 addresses to
563 #if defined __UCLIBC_HAS_IPV6__
564 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
565 if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV6))
566 gethosts(AF_INET6, struct in6_addr);
568 no_inet6_data = no_data;
570 if (req->ai_family == AF_INET
571 || (!v4mapped && req->ai_family == AF_UNSPEC)
572 || (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL)))
574 if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV4))
575 gethosts(AF_INET, struct in_addr);
578 if (no_data != 0 && no_inet6_data != 0) {
579 /* If both requests timed out report this. */
580 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
583 * We made requests but they turned out no data.
584 * The name is known, though.
586 return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
590 if (at->family == AF_UNSPEC)
591 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
593 struct gaih_addrtuple *atr;
595 atr = at = alloca(sizeof(struct gaih_addrtuple));
596 memset(at, '\0', sizeof(struct gaih_addrtuple));
597 if (req->ai_family == 0) {
598 at->next = alloca(sizeof(struct gaih_addrtuple));
599 memset(at->next, '\0', sizeof(struct gaih_addrtuple));
601 #if defined __UCLIBC_HAS_IPV6__
602 if (req->ai_family == 0 || req->ai_family == AF_INET6) {
603 at->family = AF_INET6;
604 if ((req->ai_flags & AI_PASSIVE) == 0)
605 memcpy(at->addr, &in6addr_loopback, sizeof(struct in6_addr));
609 if (req->ai_family == 0 || req->ai_family == AF_INET) {
610 atr->family = AF_INET;
611 if ((req->ai_flags & AI_PASSIVE) == 0) {
612 uint32_t *a = (uint32_t*)atr->addr;
613 *a = htonl(INADDR_LOOPBACK);
622 const char *c = NULL;
623 struct gaih_servtuple *st2;
624 struct gaih_addrtuple *at2 = at;
625 size_t socklen, namelen;
629 * buffer is the size of an unformatted IPv6 address in
632 char buffer[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
634 while (at2 != NULL) {
635 c = inet_ntop(at2->family, at2->addr, buffer, sizeof(buffer));
637 namelen = strlen(c) + 1;
638 } else if (req->ai_flags & AI_CANONNAME) {
639 struct hostent *h = NULL;
642 size_t tmpbuflen = 512;
645 /* Hint says numeric, but address is not */
646 if (req->ai_flags & AI_NUMERICHOST)
651 tmpbuf = alloca(tmpbuflen);
652 rc = gethostbyaddr_r(at2->addr,
653 #ifdef __UCLIBC_HAS_IPV6__
654 ((at2->family == AF_INET6)
655 ? sizeof(struct in6_addr)
656 : sizeof(struct in_addr)),
658 sizeof(struct in_addr),
661 &th, tmpbuf, tmpbuflen,
663 } while (rc == ERANGE && herrno == NETDB_INTERNAL);
665 if (rc != 0 && herrno == NETDB_INTERNAL) {
666 __set_h_errno(herrno);
674 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
676 namelen = strlen(c) + 1;
680 #if defined __UCLIBC_HAS_IPV6__
681 if (at2->family == AF_INET6 || v4mapped) {
683 socklen = sizeof(struct sockaddr_in6);
686 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
689 #if defined __UCLIBC_HAS_IPV4__
692 socklen = sizeof(struct sockaddr_in);
695 for (st2 = st; st2 != NULL; st2 = st2->next) {
696 if (req->ai_flags & AI_ADDRCONFIG) {
697 if (family == AF_INET && !(seen & SEEN_IPV4))
699 #if defined __UCLIBC_HAS_IPV6__
700 else if (family == AF_INET6 && !(seen & SEEN_IPV6))
704 *pai = malloc(sizeof(struct addrinfo) + socklen + namelen);
708 (*pai)->ai_flags = req->ai_flags;
709 (*pai)->ai_family = family;
710 (*pai)->ai_socktype = st2->socktype;
711 (*pai)->ai_protocol = st2->protocol;
712 (*pai)->ai_addrlen = socklen;
713 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
715 (*pai)->ai_addr->sa_len = socklen;
717 (*pai)->ai_addr->sa_family = family;
719 #if defined __UCLIBC_HAS_IPV6__
720 if (family == AF_INET6) {
721 struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) (*pai)->ai_addr;
723 sin6p->sin6_flowinfo = 0;
724 if (at2->family == AF_INET6) {
725 memcpy(&sin6p->sin6_addr,
726 at2->addr, sizeof(struct in6_addr));
728 sin6p->sin6_addr.s6_addr32[0] = 0;
729 sin6p->sin6_addr.s6_addr32[1] = 0;
730 sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
731 memcpy(&sin6p->sin6_addr.s6_addr32[3],
732 at2->addr, sizeof(sin6p->sin6_addr.s6_addr32[3]));
734 sin6p->sin6_port = st2->port;
735 sin6p->sin6_scope_id = at2->scopeid;
738 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
741 #if defined __UCLIBC_HAS_IPV4__
743 struct sockaddr_in *sinp = (struct sockaddr_in *) (*pai)->ai_addr;
745 memcpy(&sinp->sin_addr, at2->addr, sizeof(struct in_addr));
746 sinp->sin_port = st2->port;
747 memset(sinp->sin_zero, '\0', sizeof(sinp->sin_zero));
751 (*pai)->ai_canonname = ((void *) (*pai) +
752 sizeof(struct addrinfo) + socklen);
753 strcpy((*pai)->ai_canonname, c);
755 (*pai)->ai_canonname = NULL;
757 (*pai)->ai_next = NULL;
758 pai = &((*pai)->ai_next);
767 static const struct gaih gaih[] = {
768 #if defined __UCLIBC_HAS_IPV6__
769 { PF_INET6, gaih_inet },
771 { PF_INET, gaih_inet },
773 { PF_LOCAL, gaih_local },
779 freeaddrinfo(struct addrinfo *ai)
789 libc_hidden_def(freeaddrinfo)
792 getaddrinfo(const char *name, const char *service,
793 const struct addrinfo *hints, struct addrinfo **pai)
796 struct addrinfo *p, **end;
797 const struct gaih *g, *pg;
798 struct gaih_service gaih_service, *pservice;
799 struct addrinfo default_hints;
801 if (name != NULL && name[0] == '*' && name[1] == 0)
804 if (service != NULL && service[0] == '*' && service[1] == 0)
807 if (name == NULL && service == NULL)
811 memset(&default_hints, 0, sizeof(default_hints));
813 default_hints.ai_family = AF_UNSPEC;
814 hints = &default_hints;
817 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
818 AI_ADDRCONFIG|AI_V4MAPPED|AI_NUMERICSERV|AI_ALL))
821 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
824 if (service && service[0]) {
826 gaih_service.name = service;
827 gaih_service.num = strtoul(gaih_service.name, &c, 10);
829 if (hints->ai_flags & AI_NUMERICSERV)
831 gaih_service.num = -1;
833 pservice = &gaih_service;
847 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC) {
848 if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family)) {
853 if (pg == NULL || pg->gaih != g->gaih) {
855 i = g->gaih(name, pservice, hints, end);
858 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
860 /*if (p) - freeaddrinfo works ok on NULL too */
862 return -(i & GAIH_EAI);
866 end = &((*end)->ai_next);
880 if (pai == NULL && last_i == 0)
883 /* if (p) - never happens, see above */
884 /* freeaddrinfo(p); */
886 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
888 libc_hidden_def(getaddrinfo)