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
39 * uses hints->ai_socktype and hints->ai_protocol
43 get_port_protocol_socktype (const char *servname
,
44 const struct addrinfo
*hints
,
50 const char *proto_str
= NULL
;
54 if (hints
!= NULL
&& hints
->ai_protocol
!= 0) {
55 struct protoent
*protoent
= getprotobynumber (hints
->ai_protocol
);
58 return EAI_SOCKTYPE
; /* XXX */
60 proto_str
= protoent
->p_name
;
61 *protocol
= protoent
->p_proto
;
65 *socktype
= hints
->ai_socktype
;
67 if (*socktype
== SOCK_STREAM
) {
68 se
= getservbyname (servname
, proto_str
? proto_str
: "tcp");
69 if (proto_str
== NULL
)
70 *protocol
= IPPROTO_TCP
;
71 } else if (*socktype
== SOCK_DGRAM
) {
72 se
= getservbyname (servname
, proto_str
? proto_str
: "udp");
73 if (proto_str
== NULL
)
74 *protocol
= IPPROTO_UDP
;
75 } else if (*socktype
== 0) {
76 if (proto_str
!= NULL
) {
77 se
= getservbyname (servname
, proto_str
);
79 se
= getservbyname (servname
, "tcp");
80 *protocol
= IPPROTO_TCP
;
81 *socktype
= SOCK_STREAM
;
83 se
= getservbyname (servname
, "udp");
84 *protocol
= IPPROTO_UDP
;
85 *socktype
= SOCK_DGRAM
;
94 *port
= htons(strtol (servname
, &endstr
, 10));
95 if (servname
== endstr
)
104 add_one (int port
, int protocol
, int socktype
,
105 struct addrinfo
***ptr
,
106 int (*func
)(struct addrinfo
*, void *data
, int port
),
113 a
= malloc (sizeof (*a
));
116 memset (a
, 0, sizeof(*a
));
119 a
->ai_protocol
= protocol
;
120 a
->ai_socktype
= socktype
;
121 a
->ai_canonname
= canonname
;
122 ret
= (*func
)(a
, data
, port
);
133 const_v4 (struct addrinfo
*a
, void *data
, int port
)
135 struct sockaddr_in
*sin4
;
136 struct in_addr
*addr
= (struct in_addr
*)data
;
138 a
->ai_family
= PF_INET
;
139 a
->ai_addrlen
= sizeof(*sin4
);
140 a
->ai_addr
= malloc (sizeof(*sin4
));
141 if (a
->ai_addr
== NULL
)
143 sin4
= (struct sockaddr_in
*)a
->ai_addr
;
144 memset (sin4
, 0, sizeof(*sin4
));
145 sin4
->sin_family
= AF_INET
;
146 sin4
->sin_port
= port
;
147 sin4
->sin_addr
= *addr
;
153 const_v6 (struct addrinfo
*a
, void *data
, int port
)
155 struct sockaddr_in6
*sin6
;
156 struct in6_addr
*addr
= (struct in6_addr
*)data
;
158 a
->ai_family
= PF_INET6
;
159 a
->ai_addrlen
= sizeof(*sin6
);
160 a
->ai_addr
= malloc (sizeof(*sin6
));
161 if (a
->ai_addr
== NULL
)
163 sin6
= (struct sockaddr_in6
*)a
->ai_addr
;
164 memset (sin6
, 0, sizeof(*sin6
));
165 sin6
->sin6_family
= AF_INET6
;
166 sin6
->sin6_port
= port
;
167 sin6
->sin6_addr
= *addr
;
172 /* this is mostly a hack for some versions of AIX that has a prototype
173 for in6addr_loopback but no actual symbol in libc */
174 #if defined(HAVE_IPV6) && !defined(HAVE_IN6ADDR_LOOPBACK) && defined(IN6ADDR_LOOPBACK_INIT)
175 #define in6addr_loopback _roken_in6addr_loopback
176 struct in6_addr in6addr_loopback
= IN6ADDR_LOOPBACK_INIT
;
180 get_null (const struct addrinfo
*hints
,
181 int port
, int protocol
, int socktype
,
182 struct addrinfo
**res
)
184 struct in_addr v4_addr
;
186 struct in6_addr v6_addr
;
188 struct addrinfo
*first
= NULL
;
189 struct addrinfo
**current
= &first
;
190 int family
= PF_UNSPEC
;
194 family
= hints
->ai_family
;
196 if (hints
&& hints
->ai_flags
& AI_PASSIVE
) {
197 v4_addr
.s_addr
= INADDR_ANY
;
199 v6_addr
= in6addr_any
;
202 v4_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
204 v6_addr
= in6addr_loopback
;
209 if (family
== PF_INET6
|| family
== PF_UNSPEC
) {
210 ret
= add_one (port
, protocol
, socktype
,
211 ¤t
, const_v6
, &v6_addr
, NULL
);
214 if (family
== PF_INET
|| family
== PF_UNSPEC
) {
215 ret
= add_one (port
, protocol
, socktype
,
216 ¤t
, const_v4
, &v4_addr
, NULL
);
223 add_hostent (int port
, int protocol
, int socktype
,
224 struct addrinfo
***current
,
225 int (*func
)(struct addrinfo
*, void *data
, int port
),
226 struct hostent
*he
, int *flags
)
229 char *canonname
= NULL
;
232 if (*flags
& AI_CANONNAME
) {
233 struct hostent
*he2
= NULL
;
234 const char *tmp_canon
;
236 tmp_canon
= hostent_find_fqdn (he
);
237 if (strchr (tmp_canon
, '.') == NULL
) {
240 he2
= getipnodebyaddr (he
->h_addr_list
[0], he
->h_length
,
241 he
->h_addrtype
, &error
);
243 const char *tmp
= hostent_find_fqdn (he2
);
245 if (strchr (tmp
, '.') != NULL
)
250 canonname
= strdup (tmp_canon
);
253 if (canonname
== NULL
)
257 for (h
= he
->h_addr_list
; *h
!= NULL
; ++h
) {
258 ret
= add_one (port
, protocol
, socktype
,
259 current
, func
, *h
, canonname
);
262 if (*flags
& AI_CANONNAME
) {
263 *flags
&= ~AI_CANONNAME
;
271 get_number (const char *nodename
,
272 const struct addrinfo
*hints
,
273 int port
, int protocol
, int socktype
,
274 struct addrinfo
**res
)
276 struct addrinfo
*first
= NULL
;
277 struct addrinfo
**current
= &first
;
278 int family
= PF_UNSPEC
;
282 family
= hints
->ai_family
;
286 if (family
== PF_INET6
|| family
== PF_UNSPEC
) {
287 struct in6_addr v6_addr
;
289 if (inet_pton (PF_INET6
, nodename
, &v6_addr
) == 1) {
290 ret
= add_one (port
, protocol
, socktype
,
291 ¤t
, const_v6
, &v6_addr
, NULL
);
297 if (family
== PF_INET
|| family
== PF_UNSPEC
) {
298 struct in_addr v4_addr
;
300 if (inet_pton (PF_INET
, nodename
, &v4_addr
) == 1) {
301 ret
= add_one (port
, protocol
, socktype
,
302 ¤t
, const_v4
, &v4_addr
, NULL
);
311 get_nodes (const char *nodename
,
312 const struct addrinfo
*hints
,
313 int port
, int protocol
, int socktype
,
314 struct addrinfo
**res
)
316 struct addrinfo
*first
= NULL
;
317 struct addrinfo
**current
= &first
;
318 int family
= PF_UNSPEC
;
320 int ret
= EAI_NONAME
;
324 family
= hints
->ai_family
;
325 flags
= hints
->ai_flags
;
329 if (family
== PF_INET6
|| family
== PF_UNSPEC
) {
332 he
= getipnodebyname (nodename
, PF_INET6
, 0, &error
);
335 ret
= add_hostent (port
, protocol
, socktype
,
336 ¤t
, const_v6
, he
, &flags
);
341 if (family
== PF_INET
|| family
== PF_UNSPEC
) {
344 he
= getipnodebyname (nodename
, PF_INET
, 0, &error
);
347 ret
= add_hostent (port
, protocol
, socktype
,
348 ¤t
, const_v4
, he
, &flags
);
368 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
369 getaddrinfo(const char *nodename
,
370 const char *servname
,
371 const struct addrinfo
*hints
,
372 struct addrinfo
**res
)
381 if (servname
== NULL
&& nodename
== NULL
)
385 && hints
->ai_family
!= PF_UNSPEC
386 && hints
->ai_family
!= PF_INET
388 && hints
->ai_family
!= PF_INET6
393 if (servname
!= NULL
) {
394 ret
= get_port_protocol_socktype (servname
, hints
,
395 &port
, &protocol
, &socktype
);
399 if (nodename
!= NULL
) {
400 ret
= get_number (nodename
, hints
, port
, protocol
, socktype
, res
);
402 if(hints
&& hints
->ai_flags
& AI_NUMERICHOST
)
405 ret
= get_nodes (nodename
, hints
, port
, protocol
, socktype
,
409 ret
= get_null (hints
, port
, protocol
, socktype
, res
);