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
11 1. All terms of the all other applicable copyrights and licenses must be
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. */
46 #include <arpa/inet.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <sys/types.h>
51 #include <sys/utsname.h>
56 #define GAIH_OKIFUNSPEC 0x0100
57 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
60 #define UNIX_PATH_MAX 108
71 struct gaih_servtuple
*next
;
77 static const struct gaih_servtuple nullserv
;
81 struct gaih_addrtuple
*next
;
95 /* Values for `protoflag'. */
96 #define GAI_PROTO_NOSERVICE 1
97 #define GAI_PROTO_PROTOANY 2
99 static const struct gaih_typeproto gaih_inet_typeproto
[] =
102 { SOCK_STREAM
, IPPROTO_TCP
, "tcp", 0 },
103 { SOCK_DGRAM
, IPPROTO_UDP
, "udp", 0 },
104 { SOCK_RAW
, 0, "raw", GAI_PROTO_PROTOANY
|GAI_PROTO_NOSERVICE
},
111 int (*gaih
)(const char *name
, const struct gaih_service
*service
,
112 const struct addrinfo
*req
, struct addrinfo
**pai
);
116 static const struct addrinfo default_hints
;
118 static const struct addrinfo default_hints
=
119 { 0, PF_UNSPEC
, 0, 0, 0, NULL
, NULL
, NULL
};
124 /* Using Unix sockets this way is a security risk. */
126 gaih_local (const char *name
, const struct gaih_service
*service
,
127 const struct addrinfo
*req
, struct addrinfo
**pai
)
129 struct utsname utsname
;
131 if ((name
!= NULL
) && (req
->ai_flags
& AI_NUMERICHOST
))
132 return GAIH_OKIFUNSPEC
| -EAI_NONAME
;
134 if ((name
!= NULL
) || (req
->ai_flags
& AI_CANONNAME
))
135 if (uname (&utsname
) < 0)
140 if (strcmp(name
, "localhost") &&
141 strcmp(name
, "local") &&
142 strcmp(name
, "unix") &&
143 strcmp(name
, utsname
.nodename
))
144 return GAIH_OKIFUNSPEC
| -EAI_NONAME
;
147 if (req
->ai_protocol
|| req
->ai_socktype
)
149 const struct gaih_typeproto
*tp
= gaih_inet_typeproto
+ 1;
152 && ((tp
->protoflag
& GAI_PROTO_NOSERVICE
) != 0
153 || (req
->ai_socktype
!= 0 && req
->ai_socktype
!= tp
->socktype
)
154 || (req
->ai_protocol
!= 0
155 && !(tp
->protoflag
& GAI_PROTO_PROTOANY
)
156 && req
->ai_protocol
!= tp
->protocol
)))
161 if (req
->ai_socktype
)
162 return (GAIH_OKIFUNSPEC
| -EAI_SOCKTYPE
);
164 return (GAIH_OKIFUNSPEC
| -EAI_SERVICE
);
168 *pai
= malloc (sizeof (struct addrinfo
) + sizeof (struct sockaddr_un
)
169 + ((req
->ai_flags
& AI_CANONNAME
)
170 ? (strlen(utsname
.nodename
) + 1): 0));
174 (*pai
)->ai_next
= NULL
;
175 (*pai
)->ai_flags
= req
->ai_flags
;
176 (*pai
)->ai_family
= AF_LOCAL
;
177 (*pai
)->ai_socktype
= req
->ai_socktype
? req
->ai_socktype
: SOCK_STREAM
;
178 (*pai
)->ai_protocol
= req
->ai_protocol
;
179 (*pai
)->ai_addrlen
= sizeof (struct sockaddr_un
);
180 (*pai
)->ai_addr
= (void *) (*pai
) + sizeof (struct addrinfo
);
183 ((struct sockaddr_un
*) (*pai
)->ai_addr
)->sun_len
=
184 sizeof (struct sockaddr_un
);
187 ((struct sockaddr_un
*)(*pai
)->ai_addr
)->sun_family
= AF_LOCAL
;
188 memset(((struct sockaddr_un
*)(*pai
)->ai_addr
)->sun_path
, 0, UNIX_PATH_MAX
);
192 struct sockaddr_un
*sunp
= (struct sockaddr_un
*) (*pai
)->ai_addr
;
194 if (strchr (service
->name
, '/') != NULL
)
196 if (strlen (service
->name
) >= sizeof (sunp
->sun_path
))
197 return GAIH_OKIFUNSPEC
| -EAI_SERVICE
;
199 strcpy (sunp
->sun_path
, service
->name
);
203 if (strlen (P_tmpdir
"/") + 1 + strlen (service
->name
) >=
204 sizeof (sunp
->sun_path
))
205 return GAIH_OKIFUNSPEC
| -EAI_SERVICE
;
207 __stpcpy (__stpcpy (sunp
->sun_path
, P_tmpdir
"/"), service
->name
);
212 /* This is a dangerous use of the interface since there is a time
213 window between the test for the file and the actual creation
214 (done by the caller) in which a file with the same name could
216 char *buf
= ((struct sockaddr_un
*) (*pai
)->ai_addr
)->sun_path
;
218 if (__builtin_expect (__path_search (buf
, L_tmpnam
, NULL
, NULL
, 0),
220 || __builtin_expect (__gen_tempname (buf
, __GT_NOCREATE
), 0) != 0)
224 if (req
->ai_flags
& AI_CANONNAME
)
225 (*pai
)->ai_canonname
= strcpy ((char *) *pai
+ sizeof (struct addrinfo
)
226 + sizeof (struct sockaddr_un
),
229 (*pai
)->ai_canonname
= NULL
;
235 gaih_inet_serv (const char *servicename
, const struct gaih_typeproto
*tp
,
236 const struct addrinfo
*req
, struct gaih_servtuple
*st
)
239 size_t tmpbuflen
= 1024;
246 tmpbuf
= __alloca (tmpbuflen
);
248 r
= __getservbyname_r (servicename
, tp
->name
, &ts
, tmpbuf
, tmpbuflen
,
250 if (r
!= 0 || s
== NULL
)
255 return GAIH_OKIFUNSPEC
| -EAI_SERVICE
;
261 st
->socktype
= tp
->socktype
;
262 st
->protocol
= ((tp
->protoflag
& GAI_PROTO_PROTOANY
)
263 ? req
->ai_protocol
: tp
->protocol
);
264 st
->port
= s
->s_port
;
269 #define gethosts(_family, _type) \
274 char *tmpbuf = NULL; \
278 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \
279 rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \
280 tmpbuflen, &h, &herrno); \
281 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
284 if (herrno == NETDB_INTERNAL) \
286 __set_h_errno (herrno); \
287 return -EAI_SYSTEM; \
289 if (herrno == TRY_AGAIN) \
290 no_data = EAI_AGAIN; \
292 no_data = herrno == NO_DATA; \
294 else if (h != NULL) \
296 for (i = 0; h->h_addr_list[i]; i++) \
298 if (*pat == NULL) { \
299 *pat = __alloca (sizeof (struct gaih_addrtuple)); \
300 (*pat)->scopeid = 0; \
302 (*pat)->next = NULL; \
303 (*pat)->family = _family; \
304 memcpy ((*pat)->addr, h->h_addr_list[i], \
306 pat = &((*pat)->next); \
311 #define gethosts2(_family, _type) \
316 char *tmpbuf = NULL; \
320 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \
322 status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf, \
323 tmpbuflen, &rc, &herrno)); \
324 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
325 if (status == NSS_STATUS_SUCCESS && rc == 0) \
331 if (herrno == NETDB_INTERNAL) \
333 __set_h_errno (herrno); \
334 return -EAI_SYSTEM; \
336 if (herrno == TRY_AGAIN) \
337 no_data = EAI_AGAIN; \
339 no_data = herrno == NO_DATA; \
341 else if (h != NULL) \
343 for (i = 0; h->h_addr_list[i]; i++) \
345 if (*pat == NULL) { \
346 *pat = __alloca (sizeof (struct gaih_addrtuple)); \
347 (*pat)->scopeid = 0; \
349 (*pat)->next = NULL; \
350 (*pat)->family = _family; \
351 memcpy ((*pat)->addr, h->h_addr_list[i], \
353 pat = &((*pat)->next); \
358 typedef enum nss_status (*nss_gethostbyname2_r
)
359 (const char *name
, int af
, struct hostent
*host
,
360 char *buffer
, size_t buflen
, int *errnop
,
362 extern service_user
*__nss_hosts_database attribute_hidden
;
365 gaih_inet (const char *name
, const struct gaih_service
*service
,
366 const struct addrinfo
*req
, struct addrinfo
**pai
)
368 const struct gaih_typeproto
*tp
= gaih_inet_typeproto
;
369 struct gaih_servtuple
*st
= (struct gaih_servtuple
*) &nullserv
;
370 struct gaih_addrtuple
*at
= NULL
;
373 if (req
->ai_protocol
|| req
->ai_socktype
)
378 && ((req
->ai_socktype
!= 0 && req
->ai_socktype
!= tp
->socktype
)
379 || (req
->ai_protocol
!= 0
380 && !(tp
->protoflag
& GAI_PROTO_PROTOANY
)
381 && req
->ai_protocol
!= tp
->protocol
)))
386 if (req
->ai_socktype
)
387 return (GAIH_OKIFUNSPEC
| -EAI_SOCKTYPE
);
389 return (GAIH_OKIFUNSPEC
| -EAI_SERVICE
);
395 if ((tp
->protoflag
& GAI_PROTO_NOSERVICE
) != 0)
396 return (GAIH_OKIFUNSPEC
| -EAI_SERVICE
);
398 if (service
->num
< 0)
402 st
= (struct gaih_servtuple
*)
403 __alloca (sizeof (struct gaih_servtuple
));
405 if ((rc
= gaih_inet_serv (service
->name
, tp
, req
, st
)))
410 struct gaih_servtuple
**pst
= &st
;
411 for (tp
++; tp
->name
[0]; tp
++)
413 struct gaih_servtuple
*newp
;
415 if ((tp
->protoflag
& GAI_PROTO_NOSERVICE
) != 0)
418 if (req
->ai_socktype
!= 0
419 && req
->ai_socktype
!= tp
->socktype
)
421 if (req
->ai_protocol
!= 0
422 && !(tp
->protoflag
& GAI_PROTO_PROTOANY
)
423 && req
->ai_protocol
!= tp
->protocol
)
426 newp
= (struct gaih_servtuple
*)
427 __alloca (sizeof (struct gaih_servtuple
));
429 if ((rc
= gaih_inet_serv (service
->name
, tp
, req
, newp
)))
431 if (rc
& GAIH_OKIFUNSPEC
)
439 if (st
== (struct gaih_servtuple
*) &nullserv
)
440 return (GAIH_OKIFUNSPEC
| -EAI_SERVICE
);
445 st
= __alloca (sizeof (struct gaih_servtuple
));
447 st
->socktype
= tp
->socktype
;
448 st
->protocol
= ((tp
->protoflag
& GAI_PROTO_PROTOANY
)
449 ? req
->ai_protocol
: tp
->protocol
);
450 st
->port
= htons (service
->num
);
453 else if (req
->ai_socktype
|| req
->ai_protocol
)
455 st
= __alloca (sizeof (struct gaih_servtuple
));
457 st
->socktype
= tp
->socktype
;
458 st
->protocol
= ((tp
->protoflag
& GAI_PROTO_PROTOANY
)
459 ? req
->ai_protocol
: tp
->protocol
);
464 /* Neither socket type nor protocol is set. Return all socket types
466 struct gaih_servtuple
**lastp
= &st
;
467 for (++tp
; tp
->name
[0]; ++tp
)
469 struct gaih_servtuple
*newp
;
471 newp
= __alloca (sizeof (struct gaih_servtuple
));
473 newp
->socktype
= tp
->socktype
;
474 newp
->protocol
= tp
->protocol
;
484 at
= __alloca (sizeof (struct gaih_addrtuple
));
486 at
->family
= AF_UNSPEC
;
490 if (req
->ai_flags
& AI_IDN
)
493 rc
= idna_to_ascii_lz (name
, &p
, 0);
494 if (rc
!= IDNA_SUCCESS
)
495 return -EAI_IDN_ENCODE
;
496 name
= p
; /* XXX memory leak */
499 if (inet_pton (AF_INET
, name
, at
->addr
) > 0)
501 if (req
->ai_family
== AF_UNSPEC
|| req
->ai_family
== AF_INET
)
502 at
->family
= AF_INET
;
504 return -EAI_ADDRFAMILY
;
507 if (at
->family
== AF_UNSPEC
)
509 char *namebuf
= strdupa (name
);
512 scope_delim
= strchr (namebuf
, SCOPE_DELIMITER
);
513 if (scope_delim
!= NULL
)
516 if (inet_pton (AF_INET6
, namebuf
, at
->addr
) > 0)
518 if (req
->ai_family
== AF_UNSPEC
|| req
->ai_family
== AF_INET6
)
519 at
->family
= AF_INET6
;
521 return -EAI_ADDRFAMILY
;
523 if (scope_delim
!= NULL
)
525 int try_numericscope
= 0;
526 if (IN6_IS_ADDR_LINKLOCAL (at
->addr
)
527 || IN6_IS_ADDR_MC_LINKLOCAL (at
->addr
))
529 at
->scopeid
= if_nametoindex (scope_delim
+ 1);
530 if (at
->scopeid
== 0)
531 try_numericscope
= 1;
534 try_numericscope
= 1;
536 if (try_numericscope
!= 0)
539 assert (sizeof (uint32_t) <= sizeof (unsigned long));
540 at
->scopeid
= (uint32_t) strtoul (scope_delim
+ 1, &end
,
543 return GAIH_OKIFUNSPEC
| -EAI_NONAME
;
549 if (at
->family
== AF_UNSPEC
&& (req
->ai_flags
& AI_NUMERICHOST
) == 0)
552 struct gaih_addrtuple
**pat
= &at
;
554 int no_inet6_data
= 0;
555 int old_res_options
= _res
.options
;
557 /* If we are looking for both IPv4 and IPv6 address we don't
558 want the lookup functions to automatically promote IPv4
559 addresses to IPv6 addresses. Currently this is decided
560 by setting the RES_USE_INET6 bit in _res.options. */
561 if (req
->ai_family
== AF_UNSPEC
)
563 service_user
*nip
= NULL
;
564 enum nss_status inet6_status
, status
= NSS_STATUS_UNAVAIL
;
566 nss_gethostbyname2_r fct
;
568 if (__nss_hosts_database
!= NULL
)
571 nip
= __nss_hosts_database
;
574 no_more
= __nss_database_lookup ("hosts", NULL
,
575 "dns [!UNAVAIL=return] files", &nip
);
577 _res
.options
&= ~RES_USE_INET6
;
581 fct
= __nss_lookup_function (nip
, "gethostbyname2_r");
585 gethosts2 (AF_INET6
, struct in6_addr
);
586 no_inet6_data
= no_data
;
587 inet6_status
= status
;
588 gethosts2 (AF_INET
, struct in_addr
);
590 /* If we found one address for AF_INET or AF_INET6,
591 don't continue the search. */
592 if (inet6_status
== NSS_STATUS_SUCCESS
||
593 status
== NSS_STATUS_SUCCESS
)
596 /* We can have different states for AF_INET
597 and AF_INET6. Try to find a usefull one for
599 if (inet6_status
== NSS_STATUS_TRYAGAIN
)
600 status
= NSS_STATUS_TRYAGAIN
;
601 else if (status
== NSS_STATUS_UNAVAIL
&&
602 inet6_status
!= NSS_STATUS_UNAVAIL
)
603 status
= inet6_status
;
606 if (nss_next_action (nip
, status
) == NSS_ACTION_RETURN
)
609 if (nip
->next
== NULL
)
615 _res
.options
= old_res_options
;
617 else if (req
->ai_family
== AF_INET6
)
619 gethosts (AF_INET6
, struct in6_addr
);
620 no_inet6_data
= no_data
;
622 else if (req
->ai_family
== AF_INET
)
623 gethosts (AF_INET
, struct in_addr
);
625 if (no_data
!= 0 && no_inet6_data
!= 0)
627 /* If both requests timed out report this. */
628 if (no_data
== EAI_AGAIN
&& no_inet6_data
== EAI_AGAIN
)
631 /* We made requests but they turned out no data. The name
633 return (GAIH_OKIFUNSPEC
| -EAI_NODATA
);
637 if (at
->family
== AF_UNSPEC
)
638 return (GAIH_OKIFUNSPEC
| -EAI_NONAME
);
642 struct gaih_addrtuple
*atr
;
643 atr
= at
= __alloca (sizeof (struct gaih_addrtuple
));
644 memset (at
, '\0', sizeof (struct gaih_addrtuple
));
646 if (req
->ai_family
== 0)
648 at
->next
= __alloca (sizeof (struct gaih_addrtuple
));
649 memset (at
->next
, '\0', sizeof (struct gaih_addrtuple
));
652 if (req
->ai_family
== 0 || req
->ai_family
== AF_INET6
)
654 at
->family
= AF_INET6
;
655 if ((req
->ai_flags
& AI_PASSIVE
) == 0)
656 memcpy (at
->addr
, &in6addr_loopback
, sizeof (struct in6_addr
));
660 if (req
->ai_family
== 0 || req
->ai_family
== AF_INET
)
662 atr
->family
= AF_INET
;
663 if ((req
->ai_flags
& AI_PASSIVE
) == 0)
664 *(uint32_t *) atr
->addr
= htonl (INADDR_LOOPBACK
);
672 const char *c
= NULL
;
673 struct gaih_servtuple
*st2
;
674 struct gaih_addrtuple
*at2
= at
;
675 size_t socklen
, namelen
;
679 buffer is the size of an unformatted IPv6 address in printable format.
683 if (req
->ai_flags
& AI_CANONNAME
)
685 struct hostent
*h
= NULL
;
689 size_t tmpbuflen
= 512;
695 tmpbuf
= __alloca (tmpbuflen
);
697 rc
= __gethostbyaddr_r (at2
->addr
,
698 ((at2
->family
== AF_INET6
)
699 ? sizeof(struct in6_addr
)
700 : sizeof(struct in_addr
)),
701 at2
->family
, &th
, tmpbuf
, tmpbuflen
,
705 while (rc
== errno
&& herrno
== NETDB_INTERNAL
);
707 if (rc
!= 0 && herrno
== NETDB_INTERNAL
)
709 __set_h_errno (herrno
);
717 /* We have to try to get the canonical in some other
718 way. If we are looking for either AF_INET or
719 AF_INET6 try the other line. */
720 if (req
->ai_family
== AF_UNSPEC
)
722 struct addrinfo
*p
= NULL
;
723 struct addrinfo
**end
= &p
;
724 struct addrinfo localreq
= *req
;
725 struct addrinfo
*runp
;
727 localreq
.ai_family
= AF_INET
+ AF_INET6
- at2
->family
;
728 (void) gaih_inet (name
, service
, &localreq
, end
);
733 if (p
->ai_canonname
!= name
)
735 c
= strdupa (p
->ai_canonname
);
738 runp
= runp
->ai_next
;
744 /* If this code is used the missing canonical name is
745 substituted with the name passed in by the user. */
751 return GAIH_OKIFUNSPEC
| -EAI_NONAME
;
753 namelen
= strlen (c
) + 1;
758 if (at2
->family
== AF_INET6
)
761 socklen
= sizeof (struct sockaddr_in6
);
766 socklen
= sizeof (struct sockaddr_in
);
769 for (st2
= st
; st2
!= NULL
; st2
= st2
->next
)
771 *pai
= malloc (sizeof (struct addrinfo
) + socklen
+ namelen
);
775 (*pai
)->ai_flags
= req
->ai_flags
;
776 (*pai
)->ai_family
= family
;
777 (*pai
)->ai_socktype
= st2
->socktype
;
778 (*pai
)->ai_protocol
= st2
->protocol
;
779 (*pai
)->ai_addrlen
= socklen
;
780 (*pai
)->ai_addr
= (void *) (*pai
) + sizeof(struct addrinfo
);
782 (*pai
)->ai_addr
->sa_len
= socklen
;
784 (*pai
)->ai_addr
->sa_family
= family
;
786 if (family
== AF_INET6
)
788 struct sockaddr_in6
*sin6p
=
789 (struct sockaddr_in6
*) (*pai
)->ai_addr
;
791 sin6p
->sin6_flowinfo
= 0;
792 memcpy (&sin6p
->sin6_addr
,
793 at2
->addr
, sizeof (struct in6_addr
));
794 sin6p
->sin6_port
= st2
->port
;
795 sin6p
->sin6_scope_id
= at2
->scopeid
;
799 struct sockaddr_in
*sinp
=
800 (struct sockaddr_in
*) (*pai
)->ai_addr
;
801 memcpy (&sinp
->sin_addr
,
802 at2
->addr
, sizeof (struct in_addr
));
803 sinp
->sin_port
= st2
->port
;
804 memset (sinp
->sin_zero
, '\0', sizeof (sinp
->sin_zero
));
809 (*pai
)->ai_canonname
= ((void *) (*pai
) +
810 sizeof (struct addrinfo
) + socklen
);
811 strcpy ((*pai
)->ai_canonname
, c
);
814 (*pai
)->ai_canonname
= NULL
;
816 (*pai
)->ai_next
= NULL
;
817 pai
= &((*pai
)->ai_next
);
826 static struct gaih gaih
[] =
828 { PF_INET6
, gaih_inet
},
829 { PF_INET
, gaih_inet
},
831 { PF_LOCAL
, gaih_local
},
837 getaddrinfo (const char *name
, const char *service
,
838 const struct addrinfo
*hints
, struct addrinfo
**pai
)
840 int i
= 0, j
= 0, last_i
= 0;
841 struct addrinfo
*p
= NULL
, **end
;
842 struct gaih
*g
= gaih
, *pg
= NULL
;
843 struct gaih_service gaih_service
, *pservice
;
845 if (name
!= NULL
&& name
[0] == '*' && name
[1] == 0)
848 if (service
!= NULL
&& service
[0] == '*' && service
[1] == 0)
851 if (name
== NULL
&& service
== NULL
)
855 hints
= &default_hints
;
857 if (hints
->ai_flags
& ~(AI_PASSIVE
|AI_CANONNAME
|AI_NUMERICHOST
|AI_IDN
))
860 if ((hints
->ai_flags
& (AI_CANONNAME
|AI_IDN
)) && name
== NULL
)
863 if (service
&& service
[0])
866 gaih_service
.name
= service
;
867 gaih_service
.num
= strtoul (gaih_service
.name
, &c
, 10);
869 gaih_service
.num
= -1;
871 /* Can't specify a numerical socket unless a protocol family was
873 if (hints
->ai_socktype
== 0 && hints
->ai_protocol
== 0)
875 pservice
= &gaih_service
;
887 if (hints
->ai_family
== g
->family
|| hints
->ai_family
== AF_UNSPEC
)
890 if (pg
== NULL
|| pg
->gaih
!= g
->gaih
)
893 i
= g
->gaih (name
, pservice
, hints
, end
);
896 /* EAI_NODATA is a more specific result as it says that
897 we found a result but it is not usable. */
898 if (last_i
!= (GAIH_OKIFUNSPEC
| -EAI_NODATA
))
901 if (hints
->ai_family
== AF_UNSPEC
&& (i
& GAIH_OKIFUNSPEC
))
909 return -(i
& GAIH_EAI
);
912 while(*end
) end
= &((*end
)->ai_next
);
927 if (pai
== NULL
&& last_i
== 0)
932 return last_i
? -(last_i
& GAIH_EAI
) : EAI_NONAME
;
934 libc_hidden_def (getaddrinfo
)
937 freeaddrinfo (struct addrinfo
*ai
)
948 libc_hidden_def (freeaddrinfo
)