2 * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 RCSID("$Id: getaddrinfo.c,v 1.12 2001/08/17 13:06:57 joda Exp $");
42 * uses hints->ai_socktype and hints->ai_protocol
46 get_port_protocol_socktype (const char *servname
,
47 const struct addrinfo
*hints
,
53 const char *proto_str
= NULL
;
57 if (hints
!= NULL
&& hints
->ai_protocol
!= 0) {
58 struct protoent
*protoent
= getprotobynumber (hints
->ai_protocol
);
61 return EAI_SOCKTYPE
; /* XXX */
63 proto_str
= protoent
->p_name
;
64 *protocol
= protoent
->p_proto
;
68 *socktype
= hints
->ai_socktype
;
70 if (*socktype
== SOCK_STREAM
) {
71 se
= getservbyname (servname
, proto_str
? proto_str
: "tcp");
72 if (proto_str
== NULL
)
73 *protocol
= IPPROTO_TCP
;
74 } else if (*socktype
== SOCK_DGRAM
) {
75 se
= getservbyname (servname
, proto_str
? proto_str
: "udp");
76 if (proto_str
== NULL
)
77 *protocol
= IPPROTO_UDP
;
78 } else if (*socktype
== 0) {
79 if (proto_str
!= NULL
) {
80 se
= getservbyname (servname
, proto_str
);
82 se
= getservbyname (servname
, "tcp");
83 *protocol
= IPPROTO_TCP
;
84 *socktype
= SOCK_STREAM
;
86 se
= getservbyname (servname
, "udp");
87 *protocol
= IPPROTO_UDP
;
88 *socktype
= SOCK_DGRAM
;
97 *port
= htons(strtol (servname
, &endstr
, 10));
98 if (servname
== endstr
)
107 add_one (int port
, int protocol
, int socktype
,
108 struct addrinfo
***ptr
,
109 int (*func
)(struct addrinfo
*, void *data
, int port
),
116 a
= malloc (sizeof (*a
));
119 memset (a
, 0, sizeof(*a
));
122 a
->ai_protocol
= protocol
;
123 a
->ai_socktype
= socktype
;
124 a
->ai_canonname
= canonname
;
125 ret
= (*func
)(a
, data
, port
);
136 const_v4 (struct addrinfo
*a
, void *data
, int port
)
138 struct sockaddr_in
*sin
;
139 struct in_addr
*addr
= (struct in_addr
*)data
;
141 a
->ai_family
= PF_INET
;
142 a
->ai_addrlen
= sizeof(*sin
);
143 a
->ai_addr
= malloc (sizeof(*sin
));
144 if (a
->ai_addr
== NULL
)
146 sin
= (struct sockaddr_in
*)a
->ai_addr
;
147 memset (sin
, 0, sizeof(*sin
));
148 sin
->sin_family
= AF_INET
;
149 sin
->sin_port
= port
;
150 sin
->sin_addr
= *addr
;
156 const_v6 (struct addrinfo
*a
, void *data
, int port
)
158 struct sockaddr_in6
*sin6
;
159 struct in6_addr
*addr
= (struct in6_addr
*)data
;
161 a
->ai_family
= PF_INET6
;
162 a
->ai_addrlen
= sizeof(*sin6
);
163 a
->ai_addr
= malloc (sizeof(*sin6
));
164 if (a
->ai_addr
== NULL
)
166 sin6
= (struct sockaddr_in6
*)a
->ai_addr
;
167 memset (sin6
, 0, sizeof(*sin6
));
168 sin6
->sin6_family
= AF_INET6
;
169 sin6
->sin6_port
= port
;
170 sin6
->sin6_addr
= *addr
;
175 /* this is mostly a hack for some versions of AIX that has a prototype
176 for in6addr_loopback but no actual symbol in libc */
177 #if defined(HAVE_IPV6) && !defined(HAVE_IN6ADDR_LOOPBACK) && defined(IN6ADDR_LOOPBACK_INIT)
178 #define in6addr_loopback _roken_in6addr_loopback
179 struct in6_addr in6addr_loopback
= IN6ADDR_LOOPBACK_INIT
;
183 get_null (const struct addrinfo
*hints
,
184 int port
, int protocol
, int socktype
,
185 struct addrinfo
**res
)
187 struct in_addr v4_addr
;
189 struct in6_addr v6_addr
;
191 struct addrinfo
*first
= NULL
;
192 struct addrinfo
**current
= &first
;
193 int family
= PF_UNSPEC
;
197 family
= hints
->ai_family
;
199 if (hints
&& hints
->ai_flags
& AI_PASSIVE
) {
200 v4_addr
.s_addr
= INADDR_ANY
;
202 v6_addr
= in6addr_any
;
205 v4_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
207 v6_addr
= in6addr_loopback
;
212 if (family
== PF_INET6
|| family
== PF_UNSPEC
) {
213 ret
= add_one (port
, protocol
, socktype
,
214 ¤t
, const_v6
, &v6_addr
, NULL
);
217 if (family
== PF_INET
|| family
== PF_UNSPEC
) {
218 ret
= add_one (port
, protocol
, socktype
,
219 ¤t
, const_v4
, &v4_addr
, NULL
);
226 add_hostent (int port
, int protocol
, int socktype
,
227 struct addrinfo
***current
,
228 int (*func
)(struct addrinfo
*, void *data
, int port
),
229 struct hostent
*he
, int *flags
)
232 char *canonname
= NULL
;
235 if (*flags
& AI_CANONNAME
) {
236 struct hostent
*he2
= NULL
;
237 const char *tmp_canon
;
239 tmp_canon
= hostent_find_fqdn (he
);
240 if (strchr (tmp_canon
, '.') == NULL
) {
243 he2
= getipnodebyaddr (he
->h_addr_list
[0], he
->h_length
,
244 he
->h_addrtype
, &error
);
246 const char *tmp
= hostent_find_fqdn (he2
);
248 if (strchr (tmp
, '.') != NULL
)
253 canonname
= strdup (tmp_canon
);
256 if (canonname
== NULL
)
260 for (h
= he
->h_addr_list
; *h
!= NULL
; ++h
) {
261 ret
= add_one (port
, protocol
, socktype
,
262 current
, func
, *h
, canonname
);
265 if (*flags
& AI_CANONNAME
) {
266 *flags
&= ~AI_CANONNAME
;
274 get_number (const char *nodename
,
275 const struct addrinfo
*hints
,
276 int port
, int protocol
, int socktype
,
277 struct addrinfo
**res
)
279 struct addrinfo
*first
= NULL
;
280 struct addrinfo
**current
= &first
;
281 int family
= PF_UNSPEC
;
285 family
= hints
->ai_family
;
289 if (family
== PF_INET6
|| family
== PF_UNSPEC
) {
290 struct in6_addr v6_addr
;
292 if (inet_pton (PF_INET6
, nodename
, &v6_addr
) == 1) {
293 ret
= add_one (port
, protocol
, socktype
,
294 ¤t
, const_v6
, &v6_addr
, NULL
);
300 if (family
== PF_INET
|| family
== PF_UNSPEC
) {
301 struct in_addr v4_addr
;
303 if (inet_pton (PF_INET
, nodename
, &v4_addr
) == 1) {
304 ret
= add_one (port
, protocol
, socktype
,
305 ¤t
, const_v4
, &v4_addr
, NULL
);
314 get_nodes (const char *nodename
,
315 const struct addrinfo
*hints
,
316 int port
, int protocol
, int socktype
,
317 struct addrinfo
**res
)
319 struct addrinfo
*first
= NULL
;
320 struct addrinfo
**current
= &first
;
321 int family
= PF_UNSPEC
;
323 int ret
= EAI_NONAME
;
327 family
= hints
->ai_family
;
328 flags
= hints
->ai_flags
;
332 if (family
== PF_INET6
|| family
== PF_UNSPEC
) {
335 he
= getipnodebyname (nodename
, PF_INET6
, 0, &error
);
338 ret
= add_hostent (port
, protocol
, socktype
,
339 ¤t
, const_v6
, he
, &flags
);
344 if (family
== PF_INET
|| family
== PF_UNSPEC
) {
347 he
= getipnodebyname (nodename
, PF_INET
, 0, &error
);
350 ret
= add_hostent (port
, protocol
, socktype
,
351 ¤t
, const_v4
, he
, &flags
);
372 getaddrinfo(const char *nodename
,
373 const char *servname
,
374 const struct addrinfo
*hints
,
375 struct addrinfo
**res
)
384 if (servname
== NULL
&& nodename
== NULL
)
388 && hints
->ai_family
!= PF_UNSPEC
389 && hints
->ai_family
!= PF_INET
391 && hints
->ai_family
!= PF_INET6
396 if (servname
!= NULL
) {
397 ret
= get_port_protocol_socktype (servname
, hints
,
398 &port
, &protocol
, &socktype
);
402 if (nodename
!= NULL
) {
403 ret
= get_number (nodename
, hints
, port
, protocol
, socktype
, res
);
405 if(hints
&& hints
->ai_flags
& AI_NUMERICHOST
)
408 ret
= get_nodes (nodename
, hints
, port
, protocol
, socktype
,
412 ret
= get_null (hints
, port
, protocol
, socktype
, res
);