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. */
64 #include <arpa/inet.h>
65 #include <sys/socket.h>
66 #include <netinet/in.h>
67 #include <sys/types.h>
69 #include <sys/utsname.h>
73 /* Experimentally off - libc_hidden_proto(memcpy) */
74 /* Experimentally off - libc_hidden_proto(memset) */
75 /* libc_hidden_proto(strcmp) */
76 /* libc_hidden_proto(stpcpy) */
77 /* Experimentally off - libc_hidden_proto(strchr) */
78 /* Experimentally off - libc_hidden_proto(strcpy) */
79 /* Experimentally off - libc_hidden_proto(strlen) */
80 /* libc_hidden_proto(socket) */
81 /* libc_hidden_proto(close) */
82 /* libc_hidden_proto(getservbyname_r) */
83 /* libc_hidden_proto(gethostbyname2_r) */
84 /* libc_hidden_proto(gethostbyaddr_r) */
85 /* libc_hidden_proto(inet_pton) */
86 /* libc_hidden_proto(inet_ntop) */
87 /* libc_hidden_proto(strtoul) */
88 /* libc_hidden_proto(if_nametoindex) */
89 /* libc_hidden_proto(__h_errno_location) */
90 /* libc_hidden_proto(uname) */
91 #ifdef __UCLIBC_HAS_IPV6__
92 /* libc_hidden_proto(in6addr_loopback) */
95 #define GAIH_OKIFUNSPEC 0x0100
96 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
99 #define UNIX_PATH_MAX 108
102 /* Useful for having small structure members/global variables */
103 typedef int8_t socktype_t;
104 typedef int8_t family_t;
105 typedef int8_t protocol_t;
106 struct BUG_too_small {
107 char BUG_socktype_t_too_small[(0
112 char BUG_family_t_too_small[(0
117 char BUG_protocol_t_too_small[(0
123 struct gaih_service {
128 struct gaih_servtuple {
129 struct gaih_servtuple *next;
135 struct gaih_addrtuple {
136 struct gaih_addrtuple *next;
142 struct gaih_typeproto {
148 /* Values for `protoflag'. */
149 #define GAI_PROTO_NOSERVICE 1
150 #define GAI_PROTO_PROTOANY 2
152 static const struct gaih_typeproto gaih_inet_typeproto[] = {
154 { SOCK_STREAM, IPPROTO_TCP, 0, "tcp" },
155 { SOCK_DGRAM , IPPROTO_UDP, 0, "udp" },
156 { SOCK_RAW , 0 , GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE, "raw" },
162 int (*gaih)(const char *name, const struct gaih_service *service,
163 const struct addrinfo *req, struct addrinfo **pai);
169 static unsigned __check_pf(void)
173 #if defined __UCLIBC_SUPPORT_AI_ADDRCONFIG__
176 struct ifaddrs *runp;
178 /* Get the interface list via getifaddrs. */
179 if (getifaddrs(&ifa) != 0) {
180 /* We cannot determine what interfaces are available.
182 #if defined __UCLIBC_HAS_IPV4__
185 #if defined __UCLIBC_HAS_IPV6__
191 for (runp = ifa; runp != NULL; runp = runp->ifa_next) {
192 #if defined __UCLIBC_HAS_IPV4__
193 if (runp->ifa_addr->sa_family == PF_INET)
196 #if defined __UCLIBC_HAS_IPV6__
197 if (runp->ifa_addr->sa_family == PF_INET6)
205 /* AI_ADDRCONFIG is disabled, assume both ipv4 and ipv6 available. */
206 #if defined __UCLIBC_HAS_IPV4__
209 #if defined __UCLIBC_HAS_IPV6__
213 #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
218 static int addrconfig(sa_family_t af)
222 int saved_errno = errno;
226 #if defined __UCLIBC_HAS_IPV4__
228 ret = seen & SEEN_IPV4;
231 #if defined __UCLIBC_HAS_IPV6__
233 ret = seen & SEEN_IPV6;
237 s = socket(af, SOCK_DGRAM, 0);
238 ret = 1; /* Assume PF_UNIX. */
245 __set_errno(saved_errno);
250 /* Using Unix sockets this way is a security risk. */
252 gaih_local(const char *name, const struct gaih_service *service,
253 const struct addrinfo *req, struct addrinfo **pai)
255 struct utsname utsname;
256 struct addrinfo *ai = *pai;
258 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
259 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
261 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
262 if (uname(&utsname) < 0)
266 if (strcmp(name, "localhost") &&
267 strcmp(name, "local") &&
268 strcmp(name, "unix") &&
269 strcmp(name, utsname.nodename))
270 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
273 if (req->ai_protocol || req->ai_socktype) {
274 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
277 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
278 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
279 || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY) && req->ai_protocol != tp->protocol))
284 if (req->ai_socktype)
285 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
286 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
290 *pai = ai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_un)
291 + ((req->ai_flags & AI_CANONNAME)
292 ? (strlen(utsname.nodename) + 1) : 0));
297 ai->ai_flags = req->ai_flags;
298 ai->ai_family = AF_LOCAL;
299 ai->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
300 ai->ai_protocol = req->ai_protocol;
301 ai->ai_addrlen = sizeof(struct sockaddr_un);
302 ai->ai_addr = (void *)ai + sizeof(struct addrinfo);
304 ((struct sockaddr_un *)ai->ai_addr)->sun_len = sizeof(struct sockaddr_un);
307 ((struct sockaddr_un *)ai->ai_addr)->sun_family = AF_LOCAL;
308 memset(((struct sockaddr_un *)ai->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
311 struct sockaddr_un *sunp = (struct sockaddr_un *)ai->ai_addr;
313 if (strchr(service->name, '/') != NULL) {
314 if (strlen(service->name) >= sizeof(sunp->sun_path))
315 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
316 strcpy(sunp->sun_path, service->name);
318 if (strlen(P_tmpdir "/") + 1 + strlen(service->name) >= sizeof(sunp->sun_path))
319 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
320 stpcpy(stpcpy(sunp->sun_path, P_tmpdir "/"), service->name);
323 /* This is a dangerous use of the interface since there is a time
324 window between the test for the file and the actual creation
325 (done by the caller) in which a file with the same name could
327 char *buf = ((struct sockaddr_un *)ai->ai_addr)->sun_path;
329 if (__path_search(buf, L_tmpnam, NULL, NULL, 0) != 0
330 || __gen_tempname(buf, __GT_NOCREATE) != 0
336 ai->ai_canonname = NULL;
337 if (req->ai_flags & AI_CANONNAME)
338 ai->ai_canonname = strcpy((char *)(ai + 1) + sizeof(struct sockaddr_un),
345 gaih_inet_serv(const char *servicename, const struct gaih_typeproto *tp,
346 const struct addrinfo *req, struct gaih_servtuple *st)
349 size_t tmpbuflen = 1024;
355 tmpbuf = alloca(tmpbuflen);
356 r = getservbyname_r(servicename, tp->name, &ts, tmpbuf, tmpbuflen, &s);
357 if (r == 0 && s != NULL)
360 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
364 st->socktype = tp->socktype;
365 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) ? req->ai_protocol : tp->protocol);
366 st->port = s->s_port;
370 /* NB: also uses h,pat,rc,no_data variables */
371 #define gethosts(_family, _type) \
382 tmpbuf = alloca(tmpbuflen); \
383 rc = gethostbyname2_r(name, _family, &th, tmpbuf, \
384 tmpbuflen, &h, &herrno); \
385 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
387 if (herrno == NETDB_INTERNAL) { \
388 __set_h_errno(herrno); \
389 return -EAI_SYSTEM; \
391 if (herrno == TRY_AGAIN) \
392 no_data = EAI_AGAIN; \
394 no_data = (herrno == NO_DATA); \
395 } else if (h != NULL) { \
396 for (i = 0; h->h_addr_list[i]; i++) { \
397 if (*pat == NULL) { \
398 *pat = alloca(sizeof(struct gaih_addrtuple)); \
399 (*pat)->scopeid = 0; \
401 (*pat)->next = NULL; \
402 (*pat)->family = _family; \
403 memcpy((*pat)->addr, h->h_addr_list[i], sizeof(_type)); \
404 pat = &((*pat)->next); \
410 gaih_inet(const char *name, const struct gaih_service *service,
411 const struct addrinfo *req, struct addrinfo **pai)
413 struct gaih_servtuple nullserv;
415 const struct gaih_typeproto *tp = gaih_inet_typeproto;
416 struct gaih_servtuple *st = &nullserv;
417 struct gaih_addrtuple *at = NULL;
419 int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6)
420 && (req->ai_flags & AI_V4MAPPED);
421 unsigned seen = __check_pf();
423 memset(&nullserv, 0, sizeof(nullserv));
425 if (req->ai_protocol || req->ai_socktype) {
428 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
429 || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY) && req->ai_protocol != tp->protocol)
435 if (req->ai_socktype)
436 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
437 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
441 if (service != NULL) {
442 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
443 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
445 if (service->num < 0) {
447 st = alloca(sizeof(struct gaih_servtuple));
448 rc = gaih_inet_serv(service->name, tp, req, st);
452 struct gaih_servtuple **pst = &st;
453 for (tp++; tp->name[0]; tp++) {
454 struct gaih_servtuple *newp;
456 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
459 if (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
461 if (req->ai_protocol != 0
462 && !(tp->protoflag & GAI_PROTO_PROTOANY)
463 && req->ai_protocol != tp->protocol)
466 newp = alloca(sizeof(struct gaih_servtuple));
467 rc = gaih_inet_serv(service->name, tp, req, newp);
469 if (rc & GAIH_OKIFUNSPEC)
478 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
481 st = alloca(sizeof(struct gaih_servtuple));
483 st->socktype = tp->socktype;
484 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
485 ? req->ai_protocol : tp->protocol);
486 st->port = htons(service->num);
488 } else if (req->ai_socktype || req->ai_protocol) {
489 st = alloca(sizeof(struct gaih_servtuple));
491 st->socktype = tp->socktype;
492 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
493 ? req->ai_protocol : tp->protocol);
497 * Neither socket type nor protocol is set. Return all socket types
500 struct gaih_servtuple **lastp = &st;
501 for (++tp; tp->name[0]; ++tp) {
502 struct gaih_servtuple *newp;
504 newp = alloca(sizeof(struct gaih_servtuple));
506 newp->socktype = tp->socktype;
507 newp->protocol = tp->protocol;
516 at = alloca(sizeof(struct gaih_addrtuple));
517 at->family = AF_UNSPEC;
521 if (inet_pton(AF_INET, name, at->addr) > 0) {
522 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped)
523 at->family = AF_INET;
528 #if defined __UCLIBC_HAS_IPV6__
529 if (at->family == AF_UNSPEC) {
530 char *namebuf = strdupa(name);
533 scope_delim = strchr(namebuf, SCOPE_DELIMITER);
534 if (scope_delim != NULL)
537 if (inet_pton(AF_INET6, namebuf, at->addr) > 0) {
538 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
539 at->family = AF_INET6;
543 if (scope_delim != NULL) {
544 int try_numericscope = 0;
545 if (IN6_IS_ADDR_LINKLOCAL(at->addr) || IN6_IS_ADDR_MC_LINKLOCAL(at->addr)) {
546 at->scopeid = if_nametoindex(scope_delim + 1);
547 if (at->scopeid == 0)
548 try_numericscope = 1;
550 try_numericscope = 1;
552 if (try_numericscope != 0) {
554 assert(sizeof(uint32_t) <= sizeof(unsigned long));
555 at->scopeid = (uint32_t)strtoul(scope_delim + 1, &end, 10);
557 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
564 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0) {
566 struct gaih_addrtuple **pat = &at;
571 * If we are looking for both IPv4 and IPv6 address we don't want
572 * the lookup functions to automatically promote IPv4 addresses to
575 #if defined __UCLIBC_HAS_IPV6__
576 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
577 if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV6))
578 gethosts(AF_INET6, struct in6_addr);
580 no_inet6_data = no_data;
582 if (req->ai_family == AF_INET
583 || (!v4mapped && req->ai_family == AF_UNSPEC)
584 || (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL)))
586 if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV4))
587 gethosts(AF_INET, struct in_addr);
590 if (no_data != 0 && no_inet6_data != 0) {
591 /* If both requests timed out report this. */
592 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
595 * We made requests but they turned out no data.
596 * The name is known, though.
598 return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
602 if (at->family == AF_UNSPEC)
603 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
605 struct gaih_addrtuple *atr;
607 atr = at = alloca(sizeof(struct gaih_addrtuple));
608 memset(at, '\0', sizeof(struct gaih_addrtuple));
609 if (req->ai_family == 0) {
610 at->next = alloca(sizeof(struct gaih_addrtuple));
611 memset(at->next, '\0', sizeof(struct gaih_addrtuple));
613 #if defined __UCLIBC_HAS_IPV6__
614 if (req->ai_family == 0 || req->ai_family == AF_INET6) {
615 at->family = AF_INET6;
616 if ((req->ai_flags & AI_PASSIVE) == 0)
617 memcpy(at->addr, &in6addr_loopback, sizeof(struct in6_addr));
621 if (req->ai_family == 0 || req->ai_family == AF_INET) {
622 atr->family = AF_INET;
623 if ((req->ai_flags & AI_PASSIVE) == 0)
624 *(uint32_t*)atr->addr = htonl(INADDR_LOOPBACK);
632 const char *c = NULL;
633 struct gaih_servtuple *st2;
634 struct gaih_addrtuple *at2 = at;
635 size_t socklen, namelen;
639 * buffer is the size of an unformatted IPv6 address in
642 char buffer[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
644 while (at2 != NULL) {
645 if (req->ai_flags & AI_CANONNAME) {
646 struct hostent *h = NULL;
649 size_t tmpbuflen = 512;
654 tmpbuf = alloca(tmpbuflen);
655 //if (tmpbuf == NULL)
656 // return -EAI_MEMORY;
657 rc = gethostbyaddr_r(at2->addr,
658 ((at2->family == AF_INET6)
659 ? sizeof(struct in6_addr)
660 : sizeof(struct in_addr)),
662 &th, tmpbuf, tmpbuflen,
664 } while (rc == errno && herrno == NETDB_INTERNAL);
666 if (rc != 0 && herrno == NETDB_INTERNAL) {
667 __set_h_errno(herrno);
672 c = inet_ntop(at2->family, at2->addr, buffer, sizeof(buffer));
677 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
679 namelen = strlen(c) + 1;
683 #if defined __UCLIBC_HAS_IPV6__
684 if (at2->family == AF_INET6 || v4mapped) {
686 socklen = sizeof(struct sockaddr_in6);
689 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
692 #if defined __UCLIBC_HAS_IPV4__
695 socklen = sizeof(struct sockaddr_in);
698 for (st2 = st; st2 != NULL; st2 = st2->next) {
699 if (req->ai_flags & AI_ADDRCONFIG) {
700 if (family == AF_INET && !(seen & SEEN_IPV4))
702 #if defined __UCLIBC_HAS_IPV6__
703 else if (family == AF_INET6 && !(seen & SEEN_IPV6))
707 *pai = malloc(sizeof(struct addrinfo) + socklen + namelen);
711 (*pai)->ai_flags = req->ai_flags;
712 (*pai)->ai_family = family;
713 (*pai)->ai_socktype = st2->socktype;
714 (*pai)->ai_protocol = st2->protocol;
715 (*pai)->ai_addrlen = socklen;
716 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
718 (*pai)->ai_addr->sa_len = socklen;
720 (*pai)->ai_addr->sa_family = family;
722 #if defined __UCLIBC_HAS_IPV6__
723 if (family == AF_INET6) {
724 struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) (*pai)->ai_addr;
726 sin6p->sin6_flowinfo = 0;
727 if (at2->family == AF_INET6) {
728 memcpy(&sin6p->sin6_addr,
729 at2->addr, sizeof(struct in6_addr));
731 sin6p->sin6_addr.s6_addr32[0] = 0;
732 sin6p->sin6_addr.s6_addr32[1] = 0;
733 sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
734 memcpy(&sin6p->sin6_addr.s6_addr32[3],
735 at2->addr, sizeof(sin6p->sin6_addr.s6_addr32[3]));
737 sin6p->sin6_port = st2->port;
738 sin6p->sin6_scope_id = at2->scopeid;
741 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
744 #if defined __UCLIBC_HAS_IPV4__
746 struct sockaddr_in *sinp = (struct sockaddr_in *) (*pai)->ai_addr;
748 memcpy(&sinp->sin_addr, at2->addr, sizeof(struct in_addr));
749 sinp->sin_port = st2->port;
750 memset(sinp->sin_zero, '\0', sizeof(sinp->sin_zero));
754 (*pai)->ai_canonname = ((void *) (*pai) +
755 sizeof(struct addrinfo) + socklen);
756 strcpy((*pai)->ai_canonname, c);
758 (*pai)->ai_canonname = NULL;
760 (*pai)->ai_next = NULL;
761 pai = &((*pai)->ai_next);
770 static const struct gaih gaih[] = {
771 #if defined __UCLIBC_HAS_IPV6__
772 { PF_INET6, gaih_inet },
774 { PF_INET, gaih_inet },
776 { PF_LOCAL, gaih_local },
781 /* libc_hidden_proto(freeaddrinfo) */
783 freeaddrinfo(struct addrinfo *ai)
793 libc_hidden_def(freeaddrinfo)
795 /* libc_hidden_proto(getaddrinfo) */
797 getaddrinfo(const char *name, const char *service,
798 const struct addrinfo *hints, struct addrinfo **pai)
800 int i = 0, j, last_i = 0;
801 struct addrinfo *p = NULL, **end;
802 const struct gaih *g = gaih, *pg = NULL;
803 struct gaih_service gaih_service, *pservice;
804 struct addrinfo default_hints;
806 if (name != NULL && name[0] == '*' && name[1] == 0)
809 if (service != NULL && service[0] == '*' && service[1] == 0)
812 if (name == NULL && service == NULL)
816 memset(&default_hints, 0, sizeof(default_hints));
818 default_hints.ai_family = AF_UNSPEC;
819 hints = &default_hints;
822 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
823 AI_ADDRCONFIG|AI_V4MAPPED|AI_NUMERICSERV|AI_ALL))
826 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
829 if (service && service[0]) {
831 gaih_service.name = service;
832 gaih_service.num = strtoul(gaih_service.name, &c, 10);
834 if (hints->ai_flags & AI_NUMERICSERV)
836 gaih_service.num = -1;
839 * Can't specify a numerical socket unless a protocol
842 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
845 pservice = &gaih_service;
855 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC) {
856 if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family)) {
861 if (pg == NULL || pg->gaih != g->gaih) {
863 i = g->gaih(name, pservice, hints, end);
866 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
870 return -(i & GAIH_EAI);
874 end = &((*end)->ai_next);
888 if (pai == NULL && last_i == 0)
891 /* if (p) - never happens, see above */
892 /* freeaddrinfo(p); */
894 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
896 libc_hidden_def(getaddrinfo)