1 /* $NetBSD: getaddrinfo.c,v 1.1.1.1 2011/04/13 18:15:41 elric Exp $ */
4 * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute 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 THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include <krb5/roken.h>
41 * uses hints->ai_socktype and hints->ai_protocol
45 get_port_protocol_socktype (const char *servname
,
46 const struct addrinfo
*hints
,
52 const char *proto_str
= NULL
;
56 if (hints
!= NULL
&& hints
->ai_protocol
!= 0) {
57 struct protoent
*protoent
= getprotobynumber (hints
->ai_protocol
);
60 return EAI_SOCKTYPE
; /* XXX */
62 proto_str
= protoent
->p_name
;
63 *protocol
= protoent
->p_proto
;
67 *socktype
= hints
->ai_socktype
;
69 if (*socktype
== SOCK_STREAM
) {
70 se
= getservbyname (servname
, proto_str
? proto_str
: "tcp");
71 if (proto_str
== NULL
)
72 *protocol
= IPPROTO_TCP
;
73 } else if (*socktype
== SOCK_DGRAM
) {
74 se
= getservbyname (servname
, proto_str
? proto_str
: "udp");
75 if (proto_str
== NULL
)
76 *protocol
= IPPROTO_UDP
;
77 } else if (*socktype
== 0) {
78 if (proto_str
!= NULL
) {
79 se
= getservbyname (servname
, proto_str
);
81 se
= getservbyname (servname
, "tcp");
82 *protocol
= IPPROTO_TCP
;
83 *socktype
= SOCK_STREAM
;
85 se
= getservbyname (servname
, "udp");
86 *protocol
= IPPROTO_UDP
;
87 *socktype
= SOCK_DGRAM
;
96 *port
= htons(strtol (servname
, &endstr
, 10));
97 if (servname
== endstr
)
106 add_one (int port
, int protocol
, int socktype
,
107 struct addrinfo
***ptr
,
108 int (*func
)(struct addrinfo
*, void *data
, int port
),
115 a
= malloc (sizeof (*a
));
118 memset (a
, 0, sizeof(*a
));
121 a
->ai_protocol
= protocol
;
122 a
->ai_socktype
= socktype
;
123 a
->ai_canonname
= canonname
;
124 ret
= (*func
)(a
, data
, port
);
135 const_v4 (struct addrinfo
*a
, void *data
, int port
)
137 struct sockaddr_in
*sin4
;
138 struct in_addr
*addr
= (struct in_addr
*)data
;
140 a
->ai_family
= PF_INET
;
141 a
->ai_addrlen
= sizeof(*sin4
);
142 a
->ai_addr
= malloc (sizeof(*sin4
));
143 if (a
->ai_addr
== NULL
)
145 sin4
= (struct sockaddr_in
*)a
->ai_addr
;
146 memset (sin4
, 0, sizeof(*sin4
));
147 sin4
->sin_family
= AF_INET
;
148 sin4
->sin_port
= port
;
149 sin4
->sin_addr
= *addr
;
155 const_v6 (struct addrinfo
*a
, void *data
, int port
)
157 struct sockaddr_in6
*sin6
;
158 struct in6_addr
*addr
= (struct in6_addr
*)data
;
160 a
->ai_family
= PF_INET6
;
161 a
->ai_addrlen
= sizeof(*sin6
);
162 a
->ai_addr
= malloc (sizeof(*sin6
));
163 if (a
->ai_addr
== NULL
)
165 sin6
= (struct sockaddr_in6
*)a
->ai_addr
;
166 memset (sin6
, 0, sizeof(*sin6
));
167 sin6
->sin6_family
= AF_INET6
;
168 sin6
->sin6_port
= port
;
169 sin6
->sin6_addr
= *addr
;
174 /* this is mostly a hack for some versions of AIX that has a prototype
175 for in6addr_loopback but no actual symbol in libc */
176 #if defined(HAVE_IPV6) && !defined(HAVE_IN6ADDR_LOOPBACK) && defined(IN6ADDR_LOOPBACK_INIT)
177 #define in6addr_loopback _roken_in6addr_loopback
178 struct in6_addr in6addr_loopback
= IN6ADDR_LOOPBACK_INIT
;
182 get_null (const struct addrinfo
*hints
,
183 int port
, int protocol
, int socktype
,
184 struct addrinfo
**res
)
186 struct in_addr v4_addr
;
188 struct in6_addr v6_addr
;
190 struct addrinfo
*first
= NULL
;
191 struct addrinfo
**current
= &first
;
192 int family
= PF_UNSPEC
;
196 family
= hints
->ai_family
;
198 if (hints
&& hints
->ai_flags
& AI_PASSIVE
) {
199 v4_addr
.s_addr
= INADDR_ANY
;
201 v6_addr
= in6addr_any
;
204 v4_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
206 v6_addr
= in6addr_loopback
;
211 if (family
== PF_INET6
|| family
== PF_UNSPEC
) {
212 ret
= add_one (port
, protocol
, socktype
,
213 ¤t
, const_v6
, &v6_addr
, NULL
);
216 if (family
== PF_INET
|| family
== PF_UNSPEC
) {
217 ret
= add_one (port
, protocol
, socktype
,
218 ¤t
, const_v4
, &v4_addr
, NULL
);
225 add_hostent (int port
, int protocol
, int socktype
,
226 struct addrinfo
***current
,
227 int (*func
)(struct addrinfo
*, void *data
, int port
),
228 struct hostent
*he
, int *flags
)
231 char *canonname
= NULL
;
234 if (*flags
& AI_CANONNAME
) {
235 struct hostent
*he2
= NULL
;
236 const char *tmp_canon
;
238 tmp_canon
= hostent_find_fqdn (he
);
239 if (strchr (tmp_canon
, '.') == NULL
) {
242 he2
= getipnodebyaddr (he
->h_addr_list
[0], he
->h_length
,
243 he
->h_addrtype
, &error
);
245 const char *tmp
= hostent_find_fqdn (he2
);
247 if (strchr (tmp
, '.') != NULL
)
252 canonname
= strdup (tmp_canon
);
255 if (canonname
== NULL
)
259 for (h
= he
->h_addr_list
; *h
!= NULL
; ++h
) {
260 ret
= add_one (port
, protocol
, socktype
,
261 current
, func
, *h
, canonname
);
264 if (*flags
& AI_CANONNAME
) {
265 *flags
&= ~AI_CANONNAME
;
273 get_number (const char *nodename
,
274 const struct addrinfo
*hints
,
275 int port
, int protocol
, int socktype
,
276 struct addrinfo
**res
)
278 struct addrinfo
*first
= NULL
;
279 struct addrinfo
**current
= &first
;
280 int family
= PF_UNSPEC
;
284 family
= hints
->ai_family
;
288 if (family
== PF_INET6
|| family
== PF_UNSPEC
) {
289 struct in6_addr v6_addr
;
291 if (inet_pton (PF_INET6
, nodename
, &v6_addr
) == 1) {
292 ret
= add_one (port
, protocol
, socktype
,
293 ¤t
, const_v6
, &v6_addr
, NULL
);
299 if (family
== PF_INET
|| family
== PF_UNSPEC
) {
300 struct in_addr v4_addr
;
302 if (inet_pton (PF_INET
, nodename
, &v4_addr
) == 1) {
303 ret
= add_one (port
, protocol
, socktype
,
304 ¤t
, const_v4
, &v4_addr
, NULL
);
313 get_nodes (const char *nodename
,
314 const struct addrinfo
*hints
,
315 int port
, int protocol
, int socktype
,
316 struct addrinfo
**res
)
318 struct addrinfo
*first
= NULL
;
319 struct addrinfo
**current
= &first
;
320 int family
= PF_UNSPEC
;
322 int ret
= EAI_NONAME
;
326 family
= hints
->ai_family
;
327 flags
= hints
->ai_flags
;
331 if (family
== PF_INET6
|| family
== PF_UNSPEC
) {
334 he
= getipnodebyname (nodename
, PF_INET6
, 0, &error
);
337 ret
= add_hostent (port
, protocol
, socktype
,
338 ¤t
, const_v6
, he
, &flags
);
343 if (family
== PF_INET
|| family
== PF_UNSPEC
) {
346 he
= getipnodebyname (nodename
, PF_INET
, 0, &error
);
349 ret
= add_hostent (port
, protocol
, socktype
,
350 ¤t
, const_v4
, he
, &flags
);
370 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
371 getaddrinfo(const char *nodename
,
372 const char *servname
,
373 const struct addrinfo
*hints
,
374 struct addrinfo
**res
)
383 if (servname
== NULL
&& nodename
== NULL
)
387 && hints
->ai_family
!= PF_UNSPEC
388 && hints
->ai_family
!= PF_INET
390 && hints
->ai_family
!= PF_INET6
395 if (servname
!= NULL
) {
396 ret
= get_port_protocol_socktype (servname
, hints
,
397 &port
, &protocol
, &socktype
);
401 if (nodename
!= NULL
) {
402 ret
= get_number (nodename
, hints
, port
, protocol
, socktype
, res
);
404 if(hints
&& hints
->ai_flags
& AI_NUMERICHOST
)
407 ret
= get_nodes (nodename
, hints
, port
, protocol
, socktype
,
411 ret
= get_null (hints
, port
, protocol
, socktype
, res
);