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. All advertising materials mentioning features or use of this software
19 must display the following acknowledgement with the name(s) of the
20 authors as specified in the copyright notice(s) substituted where
23 This product includes software developed by <name(s)>, The Inner
24 Net, and other contributors.
26 5. Neither the name(s) of the author(s) nor the names of its contributors
27 may be used to endorse or promote products derived from this software
28 without specific prior written permission.
30 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
31 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
33 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
37 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 If these license terms cause you a real problem, contact the author. */
43 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
45 /* getaddrinfo() v1.13 */
47 /* To do what POSIX says, even when it's broken: */
48 #define BROKEN_LIKE_POSIX 1
54 #include <sys/types.h>
57 #include <sys/socket.h>
61 #include <sys/utsname.h>
64 #include <netinet/in.h>
67 #include <arpa/inet.h>
70 #define AF_LOCAL AF_UNIX
73 #define PF_LOCAL PF_UNIX
76 #define UNIX_PATH_MAX 108
77 #endif /* UNIX_PATH_MAX */
79 #define GAIH_OKIFUNSPEC 0x0100
80 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
83 struct hostent
*_hostname2addr_hosts(const char *name
, int);
84 struct hostent
*_addr2hostname_hosts(const char *name
, int, int);
85 #endif /* HOSTTABLE */
87 static struct addrinfo nullreq
=
88 { 0, PF_UNSPEC
, 0, 0, 0, NULL
, NULL
, NULL
};
95 struct gaih_servtuple
{
96 struct gaih_servtuple
*next
;
102 static struct gaih_servtuple nullserv
= {
106 struct gaih_addrtuple
{
107 struct gaih_addrtuple
*next
;
112 struct gaih_typeproto
{
119 static int gaih_local(const char *name
, const struct gaih_service
*service
,
120 const struct addrinfo
*req
, struct addrinfo
**pai
)
122 struct utsname utsname
;
124 if (name
|| (req
->ai_flags
& AI_CANONNAME
))
128 if (strcmp(name
, "localhost") && strcmp(name
, "local") && strcmp(name
, "unix") && strcmp(name
, utsname
.nodename
))
129 return (GAIH_OKIFUNSPEC
| -EAI_NONAME
);
132 if (!(*pai
= malloc(sizeof(struct addrinfo
) + sizeof(struct sockaddr_un
) + ((req
->ai_flags
& AI_CANONNAME
) ? (strlen(utsname
.nodename
) + 1): 0))))
135 (*pai
)->ai_next
= NULL
;
136 (*pai
)->ai_flags
= req
->ai_flags
;
137 (*pai
)->ai_family
= AF_LOCAL
;
138 (*pai
)->ai_socktype
= req
->ai_socktype
? req
->ai_socktype
: SOCK_STREAM
;
139 (*pai
)->ai_protocol
= req
->ai_protocol
;
140 (*pai
)->ai_addrlen
= sizeof(struct sockaddr_un
);
141 (*pai
)->ai_addr
= (void *)(*pai
) + sizeof(struct addrinfo
);
143 ((struct sockaddr_un
*)(*pai
)->ai_addr
)->sun_len
= sizeof(struct sockaddr_un
);
145 ((struct sockaddr_un
*)(*pai
)->ai_addr
)->sun_family
= AF_LOCAL
;
146 memset(((struct sockaddr_un
*)(*pai
)->ai_addr
)->sun_path
, 0, UNIX_PATH_MAX
);
149 if (c
= strchr(service
->name
, '/')) {
150 if (strlen(service
->name
) >= sizeof(((struct sockaddr_un
*)(*pai
)->ai_addr
)->sun_path
))
151 return (GAIH_OKIFUNSPEC
| -EAI_SERVICE
);
152 strcpy(((struct sockaddr_un
*)(*pai
)->ai_addr
)->sun_path
, service
->name
);
154 if (strlen(P_tmpdir
"/") + 1 + strlen(service
->name
) >= sizeof(((struct sockaddr_un
*)(*pai
)->ai_addr
)->sun_path
))
155 return (GAIH_OKIFUNSPEC
| -EAI_SERVICE
);
156 strcpy(((struct sockaddr_un
*)(*pai
)->ai_addr
)->sun_path
, P_tmpdir
"/");
157 strcat(((struct sockaddr_un
*)(*pai
)->ai_addr
)->sun_path
, service
->name
);
160 if (!tmpnam(((struct sockaddr_un
*)(*pai
)->ai_addr
)->sun_path
))
163 if (req
->ai_flags
& AI_CANONNAME
)
164 strcpy((*pai
)->ai_canonname
= (char *)(*pai
) + sizeof(struct addrinfo
) + sizeof(struct sockaddr_un
), utsname
.nodename
);
166 (*pai
)->ai_canonname
= NULL
;
171 static struct gaih_typeproto gaih_inet_typeproto
[] =
174 { SOCK_STREAM
, IPPROTO_TCP
, (char *) "tcp" },
175 { SOCK_DGRAM
, IPPROTO_UDP
, (char *) "udp" },
179 static int gaih_inet_serv(char *servicename
, struct gaih_typeproto
*tp
, struct gaih_servtuple
**st
)
182 int tmpbuflen
= 1024;
184 char *tmpbuf
= __alloca (tmpbuflen
);
185 while (__getservbyname_r (servicename
, tp
->name
, &ts
, tmpbuf
, tmpbuflen
, &s
))
190 tmpbuf
= __alloca (tmpbuflen
);
194 return GAIH_OKIFUNSPEC
| -EAI_SERVICE
;
198 if (!(*st
= malloc (sizeof (struct gaih_servtuple
))))
202 (*st
)->socktype
= tp
->socktype
;
203 (*st
)->protocol
= tp
->protocol
;
204 (*st
)->port
= s
->s_port
;
209 static int gaih_inet(const char *name
, const struct gaih_service
*service
,
210 const struct addrinfo
*req
, struct addrinfo
**pai
)
212 struct gaih_typeproto
*tp
= gaih_inet_typeproto
;
213 struct gaih_servtuple
*st
= &nullserv
;
214 struct gaih_addrtuple
*at
= NULL
;
217 if (req
->ai_protocol
|| req
->ai_socktype
) {
218 for (tp
++; tp
->name
&&
219 ((req
->ai_socktype
!= tp
->socktype
) || !req
->ai_socktype
) &&
220 ((req
->ai_protocol
!= tp
->protocol
) || !req
->ai_protocol
); tp
++);
222 if (req
->ai_socktype
)
223 return (GAIH_OKIFUNSPEC
| -EAI_SOCKTYPE
);
225 return (GAIH_OKIFUNSPEC
| -EAI_SERVICE
);
229 if (service
->num
< 0) {
231 if (i
= gaih_inet_serv(service
->name
, tp
, &st
))
234 struct gaih_servtuple
**pst
= &st
;
235 for (tp
++; tp
->name
; tp
++) {
236 if (i
= gaih_inet_serv(service
->name
, tp
, pst
)) {
237 if (i
& GAIH_OKIFUNSPEC
)
241 pst
= &((*pst
)->next
);
243 if (st
== &nullserv
) {
244 i
= (GAIH_OKIFUNSPEC
| -EAI_SERVICE
);
249 if (!(st
= malloc(sizeof(struct gaih_servtuple
))))
253 st
->socktype
= tp
->socktype
;
254 st
->protocol
= tp
->protocol
;
255 st
->port
= htons(service
->num
);
260 if (!(at
= malloc(sizeof(struct gaih_addrtuple
)))) {
268 if (!at
->family
|| !req
->ai_family
|| (req
->ai_family
== AF_INET
))
269 if (inet_pton(AF_INET
, name
, at
->addr
) > 0)
270 at
->family
= AF_INET
;
273 if (!at
->family
&& (!req
->ai_family
|| (req
->ai_family
== AF_INET6
)))
274 if (inet_pton(AF_INET6
, name
, at
->addr
) > 0)
275 at
->family
= AF_INET6
;
281 struct gaih_addrtuple
**pat
= &at
;
284 if (!req
->ai_family
|| (req
->ai_family
== AF_INET6
))
285 if (h
= _hostname2addr_hosts(name
, AF_INET6
)) {
286 for (i
= 0; h
->h_addr_list
[i
]; i
++) {
288 if (!(*pat
= malloc(sizeof(struct gaih_addrtuple
)))) {
294 (*pat
)->family
= AF_INET6
;
295 memcpy((*pat
)->addr
, h
->h_addr_list
[i
], sizeof(struct in6_addr
));
296 pat
= &((*pat
)->next
);
301 if (!req
->ai_family
|| (req
->ai_family
== AF_INET
))
302 if (h
= _hostname2addr_hosts(name
, AF_INET
)) {
303 for (i
= 0; h
->h_addr_list
[i
]; i
++) {
305 if (!(*pat
= malloc(sizeof(struct gaih_addrtuple
)))) {
311 (*pat
)->family
= AF_INET
;
312 memcpy((*pat
)->addr
, h
->h_addr_list
[i
], sizeof(struct in_addr
));
313 pat
= &((*pat
)->next
);
317 #endif /* HOSTTABLE */
322 struct gaih_addrtuple
**pat
= &at
;
325 if (!req
->ai_family
|| (req
->ai_family
== AF_INET6
)) {
327 int tmpbuflen
= 1024;
329 char *tmpbuf
= __alloca(tmpbuflen
);
330 while (__gethostbyname2_r(name
, AF_INET6
, &th
, tmpbuf
, tmpbuflen
,
332 if (herrno
== NETDB_INTERNAL
) {
333 if (errno
== ERANGE
) {
334 /* Need more buffer */
336 tmpbuf
= __alloca(tmpbuflen
);
339 __set_h_errno(herrno
);
348 for (i
= 0; h
->h_addr_list
[i
]; i
++) {
350 if (!(*pat
= malloc(sizeof(struct gaih_addrtuple
)))) {
356 (*pat
)->family
= AF_INET6
;
357 memcpy((*pat
)->addr
, h
->h_addr_list
[i
], sizeof(struct in6_addr
));
358 pat
= &((*pat
)->next
);
364 if (!req
->ai_family
|| (req
->ai_family
== AF_INET
)) {
367 int tmpbuflen
= 1024;
368 char *tmpbuf
= __alloca(tmpbuflen
);
369 while (__gethostbyname2_r(name
, AF_INET
, &th
, tmpbuf
, tmpbuflen
,
371 if (herrno
== NETDB_INTERNAL
) {
372 if (errno
== ERANGE
) {
373 /* Need more buffer */
375 tmpbuf
= __alloca(tmpbuflen
);
378 __set_h_errno(herrno
);
387 for (i
= 0; h
->h_addr_list
[i
]; i
++) {
389 if (!(*pat
= malloc(sizeof(struct gaih_addrtuple
)))) {
395 (*pat
)->family
= AF_INET
;
396 memcpy((*pat
)->addr
, h
->h_addr_list
[i
], sizeof(struct in_addr
));
397 pat
= &((*pat
)->next
);
402 #endif /* RESOLVER */
405 return (GAIH_OKIFUNSPEC
| -EAI_NONAME
);
407 if (!(at
= malloc(sizeof(struct gaih_addrtuple
)))) {
412 memset(at
, 0, sizeof(struct gaih_addrtuple
));
415 if (!(at
->next
= malloc(sizeof(struct gaih_addrtuple
)))) {
420 at
->family
= AF_INET6
;
422 memset(at
->next
, 0, sizeof(struct gaih_addrtuple
));
423 at
->next
->family
= AF_INET
;
425 at
->family
= AF_INET
;
435 const char *c
= NULL
;
436 struct gaih_servtuple
*st2
;
437 struct gaih_addrtuple
*at2
= at
;
440 buffer is the size of an unformatted IPv6 address in printable format.
442 char buffer
[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
445 if (req
->ai_flags
& AI_CANONNAME
) {
446 struct hostent
*h
= NULL
;
451 int tmpbuflen
= 1024;
452 char *tmpbuf
= __alloca(tmpbuflen
);
453 while (__gethostbyaddr_r(at2
->addr
,
455 (at2
->family
== AF_INET6
) ? sizeof(struct in6_addr
) :
457 sizeof(struct in_addr
), at2
->family
,
458 &th
, tmpbuf
, tmpbuflen
, &h
, &herrno
)) {
459 if (herrno
== NETDB_INTERNAL
) {
460 if (errno
== ERANGE
) {
461 /* Need more buffer */
463 tmpbuf
= __alloca(tmpbuflen
);
466 __set_h_errno(herrno
);
474 #endif /* RESOLVER */
477 h
= _addr2hostname_hosts(at2
->addr
,
479 (at2
->family
== AF_INET6
) ? sizeof(struct in6_addr
) :
481 sizeof(struct in_addr
), at2
->family
);
482 #endif /* HOSTTABLE */
485 c
= inet_ntop(at2
->family
, at2
->addr
, buffer
, sizeof(buffer
));
490 i
= (GAIH_OKIFUNSPEC
| -EAI_NONAME
);
499 if (at2
->family
== AF_INET6
)
500 i
= sizeof(struct sockaddr_in6
);
503 i
= sizeof(struct sockaddr_in
);
507 if (!(*pai
= malloc(sizeof(struct addrinfo
) + i
+ j
))) {
511 (*pai
)->ai_flags
= req
->ai_flags
;
512 (*pai
)->ai_family
= at2
->family
;
513 (*pai
)->ai_socktype
= st2
->socktype
;
514 (*pai
)->ai_protocol
= st2
->protocol
;
515 (*pai
)->ai_addrlen
= i
;
516 (*pai
)->ai_addr
= (void *)(*pai
) + sizeof(struct addrinfo
);
518 ((struct sockaddr_in
*)(*pai
)->ai_addr
)->sin_len
= i
;
520 ((struct sockaddr_in
*)(*pai
)->ai_addr
)->sin_family
= at2
->family
;
521 ((struct sockaddr_in
*)(*pai
)->ai_addr
)->sin_port
= st2
->port
;
524 if (at2
->family
== AF_INET6
) {
525 ((struct sockaddr_in6
*)(*pai
)->ai_addr
)->sin6_flowinfo
= 0;
526 memcpy(&((struct sockaddr_in6
*)(*pai
)->ai_addr
)->sin6_addr
, at2
->addr
, sizeof(struct in6_addr
));
530 memcpy(&((struct sockaddr_in
*)(*pai
)->ai_addr
)->sin_addr
, at2
->addr
, sizeof(struct in_addr
));
531 memset(((struct sockaddr_in
*)(*pai
)->ai_addr
)->sin_zero
, 0, sizeof(((struct sockaddr_in
*)(*pai
)->ai_addr
)->sin_zero
));
535 (*pai
)->ai_canonname
= (void *)(*pai
) + sizeof(struct addrinfo
) + i
;
536 strcpy((*pai
)->ai_canonname
, c
);
538 (*pai
)->ai_canonname
= NULL
;
539 (*pai
)->ai_next
= NULL
;
541 pai
= &((*pai
)->ai_next
);
552 if (st
!= &nullserv
) {
553 struct gaih_servtuple
*st2
= st
;
561 struct gaih_addrtuple
*at2
= at
;
573 int (*gaih
)(const char *name
, const struct gaih_service
*service
,
574 const struct addrinfo
*req
, struct addrinfo
**pai
);
577 static struct gaih gaih
[] = {
579 { PF_INET6
, gaih_inet
},
581 { PF_INET
, gaih_inet
},
583 { PF_LOCAL
, gaih_local
},
588 int getaddrinfo(const char *name
, const char *service
,
589 const struct addrinfo
*req
, struct addrinfo
**pai
)
592 struct addrinfo
*p
= NULL
, **end
;
593 struct gaih
*g
= gaih
, *pg
= NULL
;
594 struct gaih_service gaih_service
, *pservice
;
596 if (name
&& (name
[0] == '*') && !name
[1])
599 if (service
&& (service
[0] == '*') && !service
[1])
602 #if BROKEN_LIKE_POSIX
603 if (!name
&& !service
)
605 #endif /* BROKEN_LIKE_POSIX */
610 if (req
->ai_flags
& ~3)
613 if ((req
->ai_flags
& AI_CANONNAME
) && !name
)
616 if (service
&& *service
) {
618 gaih_service
.num
= strtoul(gaih_service
.name
= (void *)service
, &c
, 10);
620 gaih_service
.num
= -1;
622 #if BROKEN_LIKE_POSIX
624 if (!req
->ai_socktype
)
626 #endif /* BROKEN_LIKE_POSIX */
627 pservice
= &gaih_service
;
637 if ((req
->ai_family
== g
->family
) || !req
->ai_family
) {
639 if (!((pg
&& (pg
->gaih
== g
->gaih
)))) {
641 if (i
= g
->gaih(name
, pservice
, req
, end
)) {
642 if (!req
->ai_family
&& (i
& GAIH_OKIFUNSPEC
))
647 while(*end
) end
= &((*end
)->ai_next
);
669 return -(i
& GAIH_EAI
);
674 void freeaddrinfo(struct addrinfo
*ai
)