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 (runp->ifa_addr == NULL)
194 #if defined __UCLIBC_HAS_IPV4__
195 if (runp->ifa_addr->sa_family == PF_INET)
198 #if defined __UCLIBC_HAS_IPV6__
199 if (runp->ifa_addr->sa_family == PF_INET6)
207 /* AI_ADDRCONFIG is disabled, assume both ipv4 and ipv6 available. */
208 #if defined __UCLIBC_HAS_IPV4__
211 #if defined __UCLIBC_HAS_IPV6__
215 #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
220 static int addrconfig(sa_family_t af)
224 int saved_errno = errno;
228 #if defined __UCLIBC_HAS_IPV4__
230 ret = seen & SEEN_IPV4;
233 #if defined __UCLIBC_HAS_IPV6__
235 ret = seen & SEEN_IPV6;
239 s = socket(af, SOCK_DGRAM, 0);
240 ret = 1; /* Assume PF_UNIX. */
247 __set_errno(saved_errno);
252 /* Using Unix sockets this way is a security risk. */
254 gaih_local(const char *name, const struct gaih_service *service,
255 const struct addrinfo *req, struct addrinfo **pai)
257 struct utsname utsname;
258 struct addrinfo *ai = *pai;
260 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
261 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
263 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
264 if (uname(&utsname) < 0)
268 if (strcmp(name, "localhost") &&
269 strcmp(name, "local") &&
270 strcmp(name, "unix") &&
271 strcmp(name, utsname.nodename))
272 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
275 if (req->ai_protocol || req->ai_socktype) {
276 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
279 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
280 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
281 || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY) && req->ai_protocol != tp->protocol))
286 if (req->ai_socktype)
287 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
288 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
292 *pai = ai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_un)
293 + ((req->ai_flags & AI_CANONNAME)
294 ? (strlen(utsname.nodename) + 1) : 0));
299 ai->ai_flags = req->ai_flags;
300 ai->ai_family = AF_LOCAL;
301 ai->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
302 ai->ai_protocol = req->ai_protocol;
303 ai->ai_addrlen = sizeof(struct sockaddr_un);
304 ai->ai_addr = (void *)ai + sizeof(struct addrinfo);
306 ((struct sockaddr_un *)ai->ai_addr)->sun_len = sizeof(struct sockaddr_un);
309 ((struct sockaddr_un *)ai->ai_addr)->sun_family = AF_LOCAL;
310 memset(((struct sockaddr_un *)ai->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
313 struct sockaddr_un *sunp = (struct sockaddr_un *)ai->ai_addr;
315 if (strchr(service->name, '/') != NULL) {
316 if (strlen(service->name) >= sizeof(sunp->sun_path))
317 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
318 strcpy(sunp->sun_path, service->name);
320 if (strlen(P_tmpdir "/") + 1 + strlen(service->name) >= sizeof(sunp->sun_path))
321 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
322 stpcpy(stpcpy(sunp->sun_path, P_tmpdir "/"), service->name);
325 /* This is a dangerous use of the interface since there is a time
326 window between the test for the file and the actual creation
327 (done by the caller) in which a file with the same name could
329 char *buf = ((struct sockaddr_un *)ai->ai_addr)->sun_path;
331 if (__path_search(buf, L_tmpnam, NULL, NULL, 0) != 0
332 || __gen_tempname(buf, __GT_NOCREATE) != 0
338 ai->ai_canonname = NULL;
339 if (req->ai_flags & AI_CANONNAME)
340 ai->ai_canonname = strcpy((char *)(ai + 1) + sizeof(struct sockaddr_un),
347 gaih_inet_serv(const char *servicename, const struct gaih_typeproto *tp,
348 const struct addrinfo *req, struct gaih_servtuple *st)
351 size_t tmpbuflen = 1024;
357 tmpbuf = alloca(tmpbuflen);
358 r = getservbyname_r(servicename, tp->name, &ts, tmpbuf, tmpbuflen, &s);
359 if (r == 0 && s != NULL)
362 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
366 st->socktype = tp->socktype;
367 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) ? req->ai_protocol : tp->protocol);
368 st->port = s->s_port;
372 /* NB: also uses h,pat,rc,no_data variables */
373 #define gethosts(_family, _type) \
384 tmpbuf = alloca(tmpbuflen); \
385 rc = gethostbyname2_r(name, _family, &th, tmpbuf, \
386 tmpbuflen, &h, &herrno); \
387 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
389 if (herrno == NETDB_INTERNAL) { \
390 __set_h_errno(herrno); \
391 return -EAI_SYSTEM; \
393 if (herrno == TRY_AGAIN) \
394 no_data = EAI_AGAIN; \
396 no_data = (herrno == NO_DATA); \
397 } else if (h != NULL) { \
398 for (i = 0; h->h_addr_list[i]; i++) { \
399 if (*pat == NULL) { \
400 *pat = alloca(sizeof(struct gaih_addrtuple)); \
401 (*pat)->scopeid = 0; \
403 (*pat)->next = NULL; \
404 (*pat)->family = _family; \
405 memcpy((*pat)->addr, h->h_addr_list[i], sizeof(_type)); \
406 pat = &((*pat)->next); \
412 gaih_inet(const char *name, const struct gaih_service *service,
413 const struct addrinfo *req, struct addrinfo **pai)
415 struct gaih_servtuple nullserv;
417 const struct gaih_typeproto *tp = gaih_inet_typeproto;
418 struct gaih_servtuple *st = &nullserv;
419 struct gaih_addrtuple *at = NULL;
421 int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6)
422 && (req->ai_flags & AI_V4MAPPED);
423 unsigned seen = __check_pf();
425 memset(&nullserv, 0, sizeof(nullserv));
427 if (req->ai_protocol || req->ai_socktype) {
430 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
431 || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY) && req->ai_protocol != tp->protocol)
437 if (req->ai_socktype)
438 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
439 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
443 if (service != NULL) {
444 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
445 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
447 if (service->num < 0) {
449 st = alloca(sizeof(struct gaih_servtuple));
450 rc = gaih_inet_serv(service->name, tp, req, st);
454 struct gaih_servtuple **pst = &st;
455 for (tp++; tp->name[0]; tp++) {
456 struct gaih_servtuple *newp;
458 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
461 if (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
463 if (req->ai_protocol != 0
464 && !(tp->protoflag & GAI_PROTO_PROTOANY)
465 && req->ai_protocol != tp->protocol)
468 newp = alloca(sizeof(struct gaih_servtuple));
469 rc = gaih_inet_serv(service->name, tp, req, newp);
471 if (rc & GAIH_OKIFUNSPEC)
480 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
483 st = alloca(sizeof(struct gaih_servtuple));
485 st->socktype = tp->socktype;
486 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
487 ? req->ai_protocol : tp->protocol);
488 st->port = htons(service->num);
490 } else if (req->ai_socktype || req->ai_protocol) {
491 st = alloca(sizeof(struct gaih_servtuple));
493 st->socktype = tp->socktype;
494 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
495 ? req->ai_protocol : tp->protocol);
499 * Neither socket type nor protocol is set. Return all socket types
502 struct gaih_servtuple **lastp = &st;
503 for (++tp; tp->name[0]; ++tp) {
504 struct gaih_servtuple *newp;
506 newp = alloca(sizeof(struct gaih_servtuple));
508 newp->socktype = tp->socktype;
509 newp->protocol = tp->protocol;
518 at = alloca(sizeof(struct gaih_addrtuple));
519 at->family = AF_UNSPEC;
523 if (inet_pton(AF_INET, name, at->addr) > 0) {
524 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped)
525 at->family = AF_INET;
530 #if defined __UCLIBC_HAS_IPV6__
531 if (at->family == AF_UNSPEC) {
532 char *namebuf = strdupa(name);
535 scope_delim = strchr(namebuf, SCOPE_DELIMITER);
536 if (scope_delim != NULL)
539 if (inet_pton(AF_INET6, namebuf, at->addr) > 0) {
540 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
541 at->family = AF_INET6;
545 if (scope_delim != NULL) {
546 int try_numericscope = 0;
547 if (IN6_IS_ADDR_LINKLOCAL(at->addr) || IN6_IS_ADDR_MC_LINKLOCAL(at->addr)) {
548 at->scopeid = if_nametoindex(scope_delim + 1);
549 if (at->scopeid == 0)
550 try_numericscope = 1;
552 try_numericscope = 1;
554 if (try_numericscope != 0) {
556 assert(sizeof(uint32_t) <= sizeof(unsigned long));
557 at->scopeid = (uint32_t)strtoul(scope_delim + 1, &end, 10);
559 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
566 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0) {
568 struct gaih_addrtuple **pat = &at;
573 * If we are looking for both IPv4 and IPv6 address we don't want
574 * the lookup functions to automatically promote IPv4 addresses to
577 #if defined __UCLIBC_HAS_IPV6__
578 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
579 if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV6))
580 gethosts(AF_INET6, struct in6_addr);
582 no_inet6_data = no_data;
584 if (req->ai_family == AF_INET
585 || (!v4mapped && req->ai_family == AF_UNSPEC)
586 || (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL)))
588 if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV4))
589 gethosts(AF_INET, struct in_addr);
592 if (no_data != 0 && no_inet6_data != 0) {
593 /* If both requests timed out report this. */
594 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
597 * We made requests but they turned out no data.
598 * The name is known, though.
600 return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
604 if (at->family == AF_UNSPEC)
605 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
607 struct gaih_addrtuple *atr;
609 atr = at = alloca(sizeof(struct gaih_addrtuple));
610 memset(at, '\0', sizeof(struct gaih_addrtuple));
611 if (req->ai_family == 0) {
612 at->next = alloca(sizeof(struct gaih_addrtuple));
613 memset(at->next, '\0', sizeof(struct gaih_addrtuple));
615 #if defined __UCLIBC_HAS_IPV6__
616 if (req->ai_family == 0 || req->ai_family == AF_INET6) {
617 at->family = AF_INET6;
618 if ((req->ai_flags & AI_PASSIVE) == 0)
619 memcpy(at->addr, &in6addr_loopback, sizeof(struct in6_addr));
623 if (req->ai_family == 0 || req->ai_family == AF_INET) {
624 atr->family = AF_INET;
625 if ((req->ai_flags & AI_PASSIVE) == 0)
626 *(uint32_t*)atr->addr = htonl(INADDR_LOOPBACK);
634 const char *c = NULL;
635 struct gaih_servtuple *st2;
636 struct gaih_addrtuple *at2 = at;
637 size_t socklen, namelen;
641 * buffer is the size of an unformatted IPv6 address in
644 char buffer[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
646 while (at2 != NULL) {
647 if (req->ai_flags & AI_CANONNAME) {
648 struct hostent *h = NULL;
651 size_t tmpbuflen = 512;
656 tmpbuf = alloca(tmpbuflen);
657 //if (tmpbuf == NULL)
658 // return -EAI_MEMORY;
659 rc = gethostbyaddr_r(at2->addr,
660 ((at2->family == AF_INET6)
661 ? sizeof(struct in6_addr)
662 : sizeof(struct in_addr)),
664 &th, tmpbuf, tmpbuflen,
666 } while (rc == errno && herrno == NETDB_INTERNAL);
668 if (rc != 0 && herrno == NETDB_INTERNAL) {
669 __set_h_errno(herrno);
674 c = inet_ntop(at2->family, at2->addr, buffer, sizeof(buffer));
679 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
681 namelen = strlen(c) + 1;
685 #if defined __UCLIBC_HAS_IPV6__
686 if (at2->family == AF_INET6 || v4mapped) {
688 socklen = sizeof(struct sockaddr_in6);
691 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
694 #if defined __UCLIBC_HAS_IPV4__
697 socklen = sizeof(struct sockaddr_in);
700 for (st2 = st; st2 != NULL; st2 = st2->next) {
701 if (req->ai_flags & AI_ADDRCONFIG) {
702 if (family == AF_INET && !(seen & SEEN_IPV4))
704 #if defined __UCLIBC_HAS_IPV6__
705 else if (family == AF_INET6 && !(seen & SEEN_IPV6))
709 *pai = malloc(sizeof(struct addrinfo) + socklen + namelen);
713 (*pai)->ai_flags = req->ai_flags;
714 (*pai)->ai_family = family;
715 (*pai)->ai_socktype = st2->socktype;
716 (*pai)->ai_protocol = st2->protocol;
717 (*pai)->ai_addrlen = socklen;
718 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
720 (*pai)->ai_addr->sa_len = socklen;
722 (*pai)->ai_addr->sa_family = family;
724 #if defined __UCLIBC_HAS_IPV6__
725 if (family == AF_INET6) {
726 struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) (*pai)->ai_addr;
728 sin6p->sin6_flowinfo = 0;
729 if (at2->family == AF_INET6) {
730 memcpy(&sin6p->sin6_addr,
731 at2->addr, sizeof(struct in6_addr));
733 sin6p->sin6_addr.s6_addr32[0] = 0;
734 sin6p->sin6_addr.s6_addr32[1] = 0;
735 sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
736 memcpy(&sin6p->sin6_addr.s6_addr32[3],
737 at2->addr, sizeof(sin6p->sin6_addr.s6_addr32[3]));
739 sin6p->sin6_port = st2->port;
740 sin6p->sin6_scope_id = at2->scopeid;
743 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
746 #if defined __UCLIBC_HAS_IPV4__
748 struct sockaddr_in *sinp = (struct sockaddr_in *) (*pai)->ai_addr;
750 memcpy(&sinp->sin_addr, at2->addr, sizeof(struct in_addr));
751 sinp->sin_port = st2->port;
752 memset(sinp->sin_zero, '\0', sizeof(sinp->sin_zero));
756 (*pai)->ai_canonname = ((void *) (*pai) +
757 sizeof(struct addrinfo) + socklen);
758 strcpy((*pai)->ai_canonname, c);
760 (*pai)->ai_canonname = NULL;
762 (*pai)->ai_next = NULL;
763 pai = &((*pai)->ai_next);
772 static const struct gaih gaih[] = {
773 #if defined __UCLIBC_HAS_IPV6__
774 { PF_INET6, gaih_inet },
776 { PF_INET, gaih_inet },
778 { PF_LOCAL, gaih_local },
783 /* libc_hidden_proto(freeaddrinfo) */
785 freeaddrinfo(struct addrinfo *ai)
795 libc_hidden_def(freeaddrinfo)
797 /* libc_hidden_proto(getaddrinfo) */
799 getaddrinfo(const char *name, const char *service,
800 const struct addrinfo *hints, struct addrinfo **pai)
802 int i = 0, j, last_i = 0;
803 struct addrinfo *p = NULL, **end;
804 const struct gaih *g = gaih, *pg = NULL;
805 struct gaih_service gaih_service, *pservice;
806 struct addrinfo default_hints;
808 if (name != NULL && name[0] == '*' && name[1] == 0)
811 if (service != NULL && service[0] == '*' && service[1] == 0)
814 if (name == NULL && service == NULL)
818 memset(&default_hints, 0, sizeof(default_hints));
820 default_hints.ai_family = AF_UNSPEC;
821 hints = &default_hints;
824 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
825 AI_ADDRCONFIG|AI_V4MAPPED|AI_NUMERICSERV|AI_ALL))
828 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
831 if (service && service[0]) {
833 gaih_service.name = service;
834 gaih_service.num = strtoul(gaih_service.name, &c, 10);
836 if (hints->ai_flags & AI_NUMERICSERV)
838 gaih_service.num = -1;
841 * Can't specify a numerical socket unless a protocol
844 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
847 pservice = &gaih_service;
857 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC) {
858 if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family)) {
863 if (pg == NULL || pg->gaih != g->gaih) {
865 i = g->gaih(name, pservice, hints, end);
868 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
872 return -(i & GAIH_EAI);
876 end = &((*end)->ai_next);
890 if (pai == NULL && last_i == 0)
893 /* if (p) - never happens, see above */
894 /* freeaddrinfo(p); */
896 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
898 libc_hidden_def(getaddrinfo)