2 * Copyright (c) 1999 - 2000 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
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
;
176 get_null (const struct addrinfo
*hints
,
177 int port
, int protocol
, int socktype
,
178 struct addrinfo
**res
)
180 struct in_addr v4_addr
;
182 struct in6_addr v6_addr
;
184 struct addrinfo
*first
= NULL
;
185 struct addrinfo
**current
= &first
;
186 int family
= PF_UNSPEC
;
190 family
= hints
->ai_family
;
192 if (hints
&& hints
->ai_flags
& AI_PASSIVE
) {
193 v4_addr
.s_addr
= INADDR_ANY
;
195 v6_addr
= in6addr_any
;
198 v4_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
200 v6_addr
= in6addr_loopback
;
205 if (family
== PF_INET6
|| family
== PF_UNSPEC
) {
206 ret
= add_one (port
, protocol
, socktype
,
207 ¤t
, const_v6
, &v6_addr
, NULL
);
210 if (family
== PF_INET
|| family
== PF_UNSPEC
) {
211 ret
= add_one (port
, protocol
, socktype
,
212 ¤t
, const_v4
, &v4_addr
, NULL
);
219 * Try to find a fqdn (with `.') in he if possible, else return h_name
223 find_fqdn (const struct hostent
*he
)
225 char *ret
= he
->h_name
;
228 if (strchr (ret
, '.') == NULL
)
229 for (h
= he
->h_aliases
; *h
; ++h
) {
230 if (strchr (*h
, '.') != NULL
) {
239 add_hostent (int port
, int protocol
, int socktype
,
240 struct addrinfo
***current
,
241 int (*func
)(struct addrinfo
*, void *data
, int port
),
242 struct hostent
*he
, int *flags
)
245 char *canonname
= NULL
;
248 if (*flags
& AI_CANONNAME
) {
249 struct hostent
*he2
= NULL
;
251 canonname
= find_fqdn (he
);
252 if (strchr (canonname
, '.') == NULL
) {
255 he2
= getipnodebyaddr (he
->h_addr_list
[0], he
->h_length
,
256 he
->h_addrtype
, &error
);
258 char *tmp
= find_fqdn (he2
);
260 if (strchr (tmp
, '.') != NULL
)
265 canonname
= strdup (canonname
);
268 if (canonname
== NULL
)
272 for (h
= he
->h_addr_list
; *h
!= NULL
; ++h
) {
273 ret
= add_one (port
, protocol
, socktype
,
274 current
, func
, *h
, canonname
);
277 if (*flags
& AI_CANONNAME
) {
278 *flags
&= ~AI_CANONNAME
;
286 get_number (const char *nodename
,
287 const struct addrinfo
*hints
,
288 int port
, int protocol
, int socktype
,
289 struct addrinfo
**res
)
291 struct addrinfo
*first
= NULL
;
292 struct addrinfo
**current
= &first
;
293 int family
= PF_UNSPEC
;
297 family
= hints
->ai_family
;
301 if (family
== PF_INET6
|| family
== PF_UNSPEC
) {
302 struct in6_addr v6_addr
;
304 if (inet_pton (PF_INET6
, nodename
, &v6_addr
) == 1) {
305 ret
= add_one (port
, protocol
, socktype
,
306 ¤t
, const_v6
, &v6_addr
, NULL
);
312 if (family
== PF_INET
|| family
== PF_UNSPEC
) {
313 struct in_addr v4_addr
;
315 if (inet_pton (PF_INET
, nodename
, &v4_addr
) == 1) {
316 ret
= add_one (port
, protocol
, socktype
,
317 ¤t
, const_v4
, &v4_addr
, NULL
);
326 get_nodes (const char *nodename
,
327 const struct addrinfo
*hints
,
328 int port
, int protocol
, int socktype
,
329 struct addrinfo
**res
)
331 struct addrinfo
*first
= NULL
;
332 struct addrinfo
**current
= &first
;
333 int family
= PF_UNSPEC
;
335 int ret
= EAI_NONAME
;
339 family
= hints
->ai_family
;
340 flags
= hints
->ai_flags
;
344 if (family
== PF_INET6
|| family
== PF_UNSPEC
) {
347 he
= getipnodebyname (nodename
, PF_INET6
, 0, &error
);
350 ret
= add_hostent (port
, protocol
, socktype
,
351 ¤t
, const_v6
, he
, &flags
);
356 if (family
== PF_INET
|| family
== PF_UNSPEC
) {
359 he
= getipnodebyname (nodename
, PF_INET
, 0, &error
);
362 ret
= add_hostent (port
, protocol
, socktype
,
363 ¤t
, const_v4
, he
, &flags
);
384 getaddrinfo(const char *nodename
,
385 const char *servname
,
386 const struct addrinfo
*hints
,
387 struct addrinfo
**res
)
396 if (servname
== NULL
&& nodename
== NULL
)
400 && hints
->ai_family
!= PF_UNSPEC
401 && hints
->ai_family
!= PF_INET
403 && hints
->ai_family
!= PF_INET6
408 if (servname
!= NULL
) {
409 ret
= get_port_protocol_socktype (servname
, hints
,
410 &port
, &protocol
, &socktype
);
414 if (nodename
!= NULL
) {
415 ret
= get_number (nodename
, hints
, port
, protocol
, socktype
, res
);
417 if(hints
&& hints
->ai_flags
& AI_NUMERICHOST
)
420 ret
= get_nodes (nodename
, hints
, port
, protocol
, socktype
,
424 ret
= get_null (hints
, port
, protocol
, socktype
, res
);