xref: /minix3/crypto/external/bsd/heimdal/dist/lib/roken/getaddrinfo.c (revision ebfedea0ce5bbe81e252ddf32d732e40fb633fae)
1*ebfedea0SLionel Sambuc /*	$NetBSD: getaddrinfo.c,v 1.1.1.1 2011/04/13 18:15:41 elric Exp $	*/
2*ebfedea0SLionel Sambuc 
3*ebfedea0SLionel Sambuc /*
4*ebfedea0SLionel Sambuc  * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
5*ebfedea0SLionel Sambuc  * (Royal Institute of Technology, Stockholm, Sweden).
6*ebfedea0SLionel Sambuc  * All rights reserved.
7*ebfedea0SLionel Sambuc  *
8*ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
9*ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
10*ebfedea0SLionel Sambuc  * are met:
11*ebfedea0SLionel Sambuc  *
12*ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
13*ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
14*ebfedea0SLionel Sambuc  *
15*ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
16*ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
17*ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
18*ebfedea0SLionel Sambuc  *
19*ebfedea0SLionel Sambuc  * 3. Neither the name of the Institute nor the names of its contributors
20*ebfedea0SLionel Sambuc  *    may be used to endorse or promote products derived from this software
21*ebfedea0SLionel Sambuc  *    without specific prior written permission.
22*ebfedea0SLionel Sambuc  *
23*ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24*ebfedea0SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25*ebfedea0SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26*ebfedea0SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27*ebfedea0SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28*ebfedea0SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29*ebfedea0SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30*ebfedea0SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31*ebfedea0SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32*ebfedea0SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33*ebfedea0SLionel Sambuc  * SUCH DAMAGE.
34*ebfedea0SLionel Sambuc  */
35*ebfedea0SLionel Sambuc 
36*ebfedea0SLionel Sambuc #include <config.h>
37*ebfedea0SLionel Sambuc 
38*ebfedea0SLionel Sambuc #include <krb5/roken.h>
39*ebfedea0SLionel Sambuc 
40*ebfedea0SLionel Sambuc /*
41*ebfedea0SLionel Sambuc  * uses hints->ai_socktype and hints->ai_protocol
42*ebfedea0SLionel Sambuc  */
43*ebfedea0SLionel Sambuc 
44*ebfedea0SLionel Sambuc static int
get_port_protocol_socktype(const char * servname,const struct addrinfo * hints,int * port,int * protocol,int * socktype)45*ebfedea0SLionel Sambuc get_port_protocol_socktype (const char *servname,
46*ebfedea0SLionel Sambuc 			    const struct addrinfo *hints,
47*ebfedea0SLionel Sambuc 			    int *port,
48*ebfedea0SLionel Sambuc 			    int *protocol,
49*ebfedea0SLionel Sambuc 			    int *socktype)
50*ebfedea0SLionel Sambuc {
51*ebfedea0SLionel Sambuc     struct servent *se;
52*ebfedea0SLionel Sambuc     const char *proto_str = NULL;
53*ebfedea0SLionel Sambuc 
54*ebfedea0SLionel Sambuc     *socktype = 0;
55*ebfedea0SLionel Sambuc 
56*ebfedea0SLionel Sambuc     if (hints != NULL && hints->ai_protocol != 0) {
57*ebfedea0SLionel Sambuc 	struct protoent *protoent = getprotobynumber (hints->ai_protocol);
58*ebfedea0SLionel Sambuc 
59*ebfedea0SLionel Sambuc 	if (protoent == NULL)
60*ebfedea0SLionel Sambuc 	    return EAI_SOCKTYPE; /* XXX */
61*ebfedea0SLionel Sambuc 
62*ebfedea0SLionel Sambuc 	proto_str = protoent->p_name;
63*ebfedea0SLionel Sambuc 	*protocol = protoent->p_proto;
64*ebfedea0SLionel Sambuc     }
65*ebfedea0SLionel Sambuc 
66*ebfedea0SLionel Sambuc     if (hints != NULL)
67*ebfedea0SLionel Sambuc 	*socktype = hints->ai_socktype;
68*ebfedea0SLionel Sambuc 
69*ebfedea0SLionel Sambuc     if (*socktype == SOCK_STREAM) {
70*ebfedea0SLionel Sambuc 	se = getservbyname (servname, proto_str ? proto_str : "tcp");
71*ebfedea0SLionel Sambuc 	if (proto_str == NULL)
72*ebfedea0SLionel Sambuc 	    *protocol = IPPROTO_TCP;
73*ebfedea0SLionel Sambuc     } else if (*socktype == SOCK_DGRAM) {
74*ebfedea0SLionel Sambuc 	se = getservbyname (servname, proto_str ? proto_str : "udp");
75*ebfedea0SLionel Sambuc 	if (proto_str == NULL)
76*ebfedea0SLionel Sambuc 	    *protocol = IPPROTO_UDP;
77*ebfedea0SLionel Sambuc     } else if (*socktype == 0) {
78*ebfedea0SLionel Sambuc 	if (proto_str != NULL) {
79*ebfedea0SLionel Sambuc 	    se = getservbyname (servname, proto_str);
80*ebfedea0SLionel Sambuc 	} else {
81*ebfedea0SLionel Sambuc 	    se = getservbyname (servname, "tcp");
82*ebfedea0SLionel Sambuc 	    *protocol = IPPROTO_TCP;
83*ebfedea0SLionel Sambuc 	    *socktype = SOCK_STREAM;
84*ebfedea0SLionel Sambuc 	    if (se == NULL) {
85*ebfedea0SLionel Sambuc 		se = getservbyname (servname, "udp");
86*ebfedea0SLionel Sambuc 		*protocol = IPPROTO_UDP;
87*ebfedea0SLionel Sambuc 		*socktype = SOCK_DGRAM;
88*ebfedea0SLionel Sambuc 	    }
89*ebfedea0SLionel Sambuc 	}
90*ebfedea0SLionel Sambuc     } else
91*ebfedea0SLionel Sambuc 	return EAI_SOCKTYPE;
92*ebfedea0SLionel Sambuc 
93*ebfedea0SLionel Sambuc     if (se == NULL) {
94*ebfedea0SLionel Sambuc 	char *endstr;
95*ebfedea0SLionel Sambuc 
96*ebfedea0SLionel Sambuc 	*port = htons(strtol (servname, &endstr, 10));
97*ebfedea0SLionel Sambuc 	if (servname == endstr)
98*ebfedea0SLionel Sambuc 	    return EAI_NONAME;
99*ebfedea0SLionel Sambuc     } else {
100*ebfedea0SLionel Sambuc 	*port = se->s_port;
101*ebfedea0SLionel Sambuc     }
102*ebfedea0SLionel Sambuc     return 0;
103*ebfedea0SLionel Sambuc }
104*ebfedea0SLionel Sambuc 
105*ebfedea0SLionel Sambuc static int
add_one(int port,int protocol,int socktype,struct addrinfo *** ptr,int (* func)(struct addrinfo *,void * data,int port),void * data,char * canonname)106*ebfedea0SLionel Sambuc add_one (int port, int protocol, int socktype,
107*ebfedea0SLionel Sambuc 	 struct addrinfo ***ptr,
108*ebfedea0SLionel Sambuc 	 int (*func)(struct addrinfo *, void *data, int port),
109*ebfedea0SLionel Sambuc 	 void *data,
110*ebfedea0SLionel Sambuc 	 char *canonname)
111*ebfedea0SLionel Sambuc {
112*ebfedea0SLionel Sambuc     struct addrinfo *a;
113*ebfedea0SLionel Sambuc     int ret;
114*ebfedea0SLionel Sambuc 
115*ebfedea0SLionel Sambuc     a = malloc (sizeof (*a));
116*ebfedea0SLionel Sambuc     if (a == NULL)
117*ebfedea0SLionel Sambuc 	return EAI_MEMORY;
118*ebfedea0SLionel Sambuc     memset (a, 0, sizeof(*a));
119*ebfedea0SLionel Sambuc     a->ai_flags     = 0;
120*ebfedea0SLionel Sambuc     a->ai_next      = NULL;
121*ebfedea0SLionel Sambuc     a->ai_protocol  = protocol;
122*ebfedea0SLionel Sambuc     a->ai_socktype  = socktype;
123*ebfedea0SLionel Sambuc     a->ai_canonname = canonname;
124*ebfedea0SLionel Sambuc     ret = (*func)(a, data, port);
125*ebfedea0SLionel Sambuc     if (ret) {
126*ebfedea0SLionel Sambuc 	free (a);
127*ebfedea0SLionel Sambuc 	return ret;
128*ebfedea0SLionel Sambuc     }
129*ebfedea0SLionel Sambuc     **ptr = a;
130*ebfedea0SLionel Sambuc     *ptr = &a->ai_next;
131*ebfedea0SLionel Sambuc     return 0;
132*ebfedea0SLionel Sambuc }
133*ebfedea0SLionel Sambuc 
134*ebfedea0SLionel Sambuc static int
const_v4(struct addrinfo * a,void * data,int port)135*ebfedea0SLionel Sambuc const_v4 (struct addrinfo *a, void *data, int port)
136*ebfedea0SLionel Sambuc {
137*ebfedea0SLionel Sambuc     struct sockaddr_in *sin4;
138*ebfedea0SLionel Sambuc     struct in_addr *addr = (struct in_addr *)data;
139*ebfedea0SLionel Sambuc 
140*ebfedea0SLionel Sambuc     a->ai_family  = PF_INET;
141*ebfedea0SLionel Sambuc     a->ai_addrlen = sizeof(*sin4);
142*ebfedea0SLionel Sambuc     a->ai_addr    = malloc (sizeof(*sin4));
143*ebfedea0SLionel Sambuc     if (a->ai_addr == NULL)
144*ebfedea0SLionel Sambuc 	return EAI_MEMORY;
145*ebfedea0SLionel Sambuc     sin4 = (struct sockaddr_in *)a->ai_addr;
146*ebfedea0SLionel Sambuc     memset (sin4, 0, sizeof(*sin4));
147*ebfedea0SLionel Sambuc     sin4->sin_family = AF_INET;
148*ebfedea0SLionel Sambuc     sin4->sin_port   = port;
149*ebfedea0SLionel Sambuc     sin4->sin_addr   = *addr;
150*ebfedea0SLionel Sambuc     return 0;
151*ebfedea0SLionel Sambuc }
152*ebfedea0SLionel Sambuc 
153*ebfedea0SLionel Sambuc #ifdef HAVE_IPV6
154*ebfedea0SLionel Sambuc static int
const_v6(struct addrinfo * a,void * data,int port)155*ebfedea0SLionel Sambuc const_v6 (struct addrinfo *a, void *data, int port)
156*ebfedea0SLionel Sambuc {
157*ebfedea0SLionel Sambuc     struct sockaddr_in6 *sin6;
158*ebfedea0SLionel Sambuc     struct in6_addr *addr = (struct in6_addr *)data;
159*ebfedea0SLionel Sambuc 
160*ebfedea0SLionel Sambuc     a->ai_family  = PF_INET6;
161*ebfedea0SLionel Sambuc     a->ai_addrlen = sizeof(*sin6);
162*ebfedea0SLionel Sambuc     a->ai_addr    = malloc (sizeof(*sin6));
163*ebfedea0SLionel Sambuc     if (a->ai_addr == NULL)
164*ebfedea0SLionel Sambuc 	return EAI_MEMORY;
165*ebfedea0SLionel Sambuc     sin6 = (struct sockaddr_in6 *)a->ai_addr;
166*ebfedea0SLionel Sambuc     memset (sin6, 0, sizeof(*sin6));
167*ebfedea0SLionel Sambuc     sin6->sin6_family = AF_INET6;
168*ebfedea0SLionel Sambuc     sin6->sin6_port   = port;
169*ebfedea0SLionel Sambuc     sin6->sin6_addr   = *addr;
170*ebfedea0SLionel Sambuc     return 0;
171*ebfedea0SLionel Sambuc }
172*ebfedea0SLionel Sambuc #endif
173*ebfedea0SLionel Sambuc 
174*ebfedea0SLionel Sambuc /* this is mostly a hack for some versions of AIX that has a prototype
175*ebfedea0SLionel Sambuc    for in6addr_loopback but no actual symbol in libc */
176*ebfedea0SLionel Sambuc #if defined(HAVE_IPV6) && !defined(HAVE_IN6ADDR_LOOPBACK) && defined(IN6ADDR_LOOPBACK_INIT)
177*ebfedea0SLionel Sambuc #define in6addr_loopback _roken_in6addr_loopback
178*ebfedea0SLionel Sambuc struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
179*ebfedea0SLionel Sambuc #endif
180*ebfedea0SLionel Sambuc 
181*ebfedea0SLionel Sambuc static int
get_null(const struct addrinfo * hints,int port,int protocol,int socktype,struct addrinfo ** res)182*ebfedea0SLionel Sambuc get_null (const struct addrinfo *hints,
183*ebfedea0SLionel Sambuc 	  int port, int protocol, int socktype,
184*ebfedea0SLionel Sambuc 	  struct addrinfo **res)
185*ebfedea0SLionel Sambuc {
186*ebfedea0SLionel Sambuc     struct in_addr v4_addr;
187*ebfedea0SLionel Sambuc #ifdef HAVE_IPV6
188*ebfedea0SLionel Sambuc     struct in6_addr v6_addr;
189*ebfedea0SLionel Sambuc #endif
190*ebfedea0SLionel Sambuc     struct addrinfo *first = NULL;
191*ebfedea0SLionel Sambuc     struct addrinfo **current = &first;
192*ebfedea0SLionel Sambuc     int family = PF_UNSPEC;
193*ebfedea0SLionel Sambuc     int ret;
194*ebfedea0SLionel Sambuc 
195*ebfedea0SLionel Sambuc     if (hints != NULL)
196*ebfedea0SLionel Sambuc 	family = hints->ai_family;
197*ebfedea0SLionel Sambuc 
198*ebfedea0SLionel Sambuc     if (hints && hints->ai_flags & AI_PASSIVE) {
199*ebfedea0SLionel Sambuc 	v4_addr.s_addr = INADDR_ANY;
200*ebfedea0SLionel Sambuc #ifdef HAVE_IPV6
201*ebfedea0SLionel Sambuc 	v6_addr        = in6addr_any;
202*ebfedea0SLionel Sambuc #endif
203*ebfedea0SLionel Sambuc     } else {
204*ebfedea0SLionel Sambuc 	v4_addr.s_addr = htonl(INADDR_LOOPBACK);
205*ebfedea0SLionel Sambuc #ifdef HAVE_IPV6
206*ebfedea0SLionel Sambuc 	v6_addr        = in6addr_loopback;
207*ebfedea0SLionel Sambuc #endif
208*ebfedea0SLionel Sambuc     }
209*ebfedea0SLionel Sambuc 
210*ebfedea0SLionel Sambuc #ifdef HAVE_IPV6
211*ebfedea0SLionel Sambuc     if (family == PF_INET6 || family == PF_UNSPEC) {
212*ebfedea0SLionel Sambuc 	ret = add_one (port, protocol, socktype,
213*ebfedea0SLionel Sambuc 		       &current, const_v6, &v6_addr, NULL);
214*ebfedea0SLionel Sambuc     }
215*ebfedea0SLionel Sambuc #endif
216*ebfedea0SLionel Sambuc     if (family == PF_INET || family == PF_UNSPEC) {
217*ebfedea0SLionel Sambuc 	ret = add_one (port, protocol, socktype,
218*ebfedea0SLionel Sambuc 		       &current, const_v4, &v4_addr, NULL);
219*ebfedea0SLionel Sambuc     }
220*ebfedea0SLionel Sambuc     *res = first;
221*ebfedea0SLionel Sambuc     return 0;
222*ebfedea0SLionel Sambuc }
223*ebfedea0SLionel Sambuc 
224*ebfedea0SLionel Sambuc static int
add_hostent(int port,int protocol,int socktype,struct addrinfo *** current,int (* func)(struct addrinfo *,void * data,int port),struct hostent * he,int * flags)225*ebfedea0SLionel Sambuc add_hostent (int port, int protocol, int socktype,
226*ebfedea0SLionel Sambuc 	     struct addrinfo ***current,
227*ebfedea0SLionel Sambuc 	     int (*func)(struct addrinfo *, void *data, int port),
228*ebfedea0SLionel Sambuc 	     struct hostent *he, int *flags)
229*ebfedea0SLionel Sambuc {
230*ebfedea0SLionel Sambuc     int ret;
231*ebfedea0SLionel Sambuc     char *canonname = NULL;
232*ebfedea0SLionel Sambuc     char **h;
233*ebfedea0SLionel Sambuc 
234*ebfedea0SLionel Sambuc     if (*flags & AI_CANONNAME) {
235*ebfedea0SLionel Sambuc 	struct hostent *he2 = NULL;
236*ebfedea0SLionel Sambuc 	const char *tmp_canon;
237*ebfedea0SLionel Sambuc 
238*ebfedea0SLionel Sambuc 	tmp_canon = hostent_find_fqdn (he);
239*ebfedea0SLionel Sambuc 	if (strchr (tmp_canon, '.') == NULL) {
240*ebfedea0SLionel Sambuc 	    int error;
241*ebfedea0SLionel Sambuc 
242*ebfedea0SLionel Sambuc 	    he2 = getipnodebyaddr (he->h_addr_list[0], he->h_length,
243*ebfedea0SLionel Sambuc 				   he->h_addrtype, &error);
244*ebfedea0SLionel Sambuc 	    if (he2 != NULL) {
245*ebfedea0SLionel Sambuc 		const char *tmp = hostent_find_fqdn (he2);
246*ebfedea0SLionel Sambuc 
247*ebfedea0SLionel Sambuc 		if (strchr (tmp, '.') != NULL)
248*ebfedea0SLionel Sambuc 		    tmp_canon = tmp;
249*ebfedea0SLionel Sambuc 	    }
250*ebfedea0SLionel Sambuc 	}
251*ebfedea0SLionel Sambuc 
252*ebfedea0SLionel Sambuc 	canonname = strdup (tmp_canon);
253*ebfedea0SLionel Sambuc 	if (he2 != NULL)
254*ebfedea0SLionel Sambuc 	    freehostent (he2);
255*ebfedea0SLionel Sambuc 	if (canonname == NULL)
256*ebfedea0SLionel Sambuc 	    return EAI_MEMORY;
257*ebfedea0SLionel Sambuc     }
258*ebfedea0SLionel Sambuc 
259*ebfedea0SLionel Sambuc     for (h = he->h_addr_list; *h != NULL; ++h) {
260*ebfedea0SLionel Sambuc 	ret = add_one (port, protocol, socktype,
261*ebfedea0SLionel Sambuc 		       current, func, *h, canonname);
262*ebfedea0SLionel Sambuc 	if (ret)
263*ebfedea0SLionel Sambuc 	    return ret;
264*ebfedea0SLionel Sambuc 	if (*flags & AI_CANONNAME) {
265*ebfedea0SLionel Sambuc 	    *flags &= ~AI_CANONNAME;
266*ebfedea0SLionel Sambuc 	    canonname = NULL;
267*ebfedea0SLionel Sambuc 	}
268*ebfedea0SLionel Sambuc     }
269*ebfedea0SLionel Sambuc     return 0;
270*ebfedea0SLionel Sambuc }
271*ebfedea0SLionel Sambuc 
272*ebfedea0SLionel Sambuc static int
get_number(const char * nodename,const struct addrinfo * hints,int port,int protocol,int socktype,struct addrinfo ** res)273*ebfedea0SLionel Sambuc get_number (const char *nodename,
274*ebfedea0SLionel Sambuc 	    const struct addrinfo *hints,
275*ebfedea0SLionel Sambuc 	    int port, int protocol, int socktype,
276*ebfedea0SLionel Sambuc 	    struct addrinfo **res)
277*ebfedea0SLionel Sambuc {
278*ebfedea0SLionel Sambuc     struct addrinfo *first = NULL;
279*ebfedea0SLionel Sambuc     struct addrinfo **current = &first;
280*ebfedea0SLionel Sambuc     int family = PF_UNSPEC;
281*ebfedea0SLionel Sambuc     int ret;
282*ebfedea0SLionel Sambuc 
283*ebfedea0SLionel Sambuc     if (hints != NULL) {
284*ebfedea0SLionel Sambuc 	family = hints->ai_family;
285*ebfedea0SLionel Sambuc     }
286*ebfedea0SLionel Sambuc 
287*ebfedea0SLionel Sambuc #ifdef HAVE_IPV6
288*ebfedea0SLionel Sambuc     if (family == PF_INET6 || family == PF_UNSPEC) {
289*ebfedea0SLionel Sambuc 	struct in6_addr v6_addr;
290*ebfedea0SLionel Sambuc 
291*ebfedea0SLionel Sambuc 	if (inet_pton (PF_INET6, nodename, &v6_addr) == 1) {
292*ebfedea0SLionel Sambuc 	    ret = add_one (port, protocol, socktype,
293*ebfedea0SLionel Sambuc 			   &current, const_v6, &v6_addr, NULL);
294*ebfedea0SLionel Sambuc 	    *res = first;
295*ebfedea0SLionel Sambuc 	    return ret;
296*ebfedea0SLionel Sambuc 	}
297*ebfedea0SLionel Sambuc     }
298*ebfedea0SLionel Sambuc #endif
299*ebfedea0SLionel Sambuc     if (family == PF_INET || family == PF_UNSPEC) {
300*ebfedea0SLionel Sambuc 	struct in_addr v4_addr;
301*ebfedea0SLionel Sambuc 
302*ebfedea0SLionel Sambuc 	if (inet_pton (PF_INET, nodename, &v4_addr) == 1) {
303*ebfedea0SLionel Sambuc 	    ret = add_one (port, protocol, socktype,
304*ebfedea0SLionel Sambuc 			   &current, const_v4, &v4_addr, NULL);
305*ebfedea0SLionel Sambuc 	    *res = first;
306*ebfedea0SLionel Sambuc 	    return ret;
307*ebfedea0SLionel Sambuc 	}
308*ebfedea0SLionel Sambuc     }
309*ebfedea0SLionel Sambuc     return EAI_NONAME;
310*ebfedea0SLionel Sambuc }
311*ebfedea0SLionel Sambuc 
312*ebfedea0SLionel Sambuc static int
get_nodes(const char * nodename,const struct addrinfo * hints,int port,int protocol,int socktype,struct addrinfo ** res)313*ebfedea0SLionel Sambuc get_nodes (const char *nodename,
314*ebfedea0SLionel Sambuc 	   const struct addrinfo *hints,
315*ebfedea0SLionel Sambuc 	   int port, int protocol, int socktype,
316*ebfedea0SLionel Sambuc 	   struct addrinfo **res)
317*ebfedea0SLionel Sambuc {
318*ebfedea0SLionel Sambuc     struct addrinfo *first = NULL;
319*ebfedea0SLionel Sambuc     struct addrinfo **current = &first;
320*ebfedea0SLionel Sambuc     int family = PF_UNSPEC;
321*ebfedea0SLionel Sambuc     int flags  = 0;
322*ebfedea0SLionel Sambuc     int ret = EAI_NONAME;
323*ebfedea0SLionel Sambuc     int error;
324*ebfedea0SLionel Sambuc 
325*ebfedea0SLionel Sambuc     if (hints != NULL) {
326*ebfedea0SLionel Sambuc 	family = hints->ai_family;
327*ebfedea0SLionel Sambuc 	flags  = hints->ai_flags;
328*ebfedea0SLionel Sambuc     }
329*ebfedea0SLionel Sambuc 
330*ebfedea0SLionel Sambuc #ifdef HAVE_IPV6
331*ebfedea0SLionel Sambuc     if (family == PF_INET6 || family == PF_UNSPEC) {
332*ebfedea0SLionel Sambuc 	struct hostent *he;
333*ebfedea0SLionel Sambuc 
334*ebfedea0SLionel Sambuc 	he = getipnodebyname (nodename, PF_INET6, 0, &error);
335*ebfedea0SLionel Sambuc 
336*ebfedea0SLionel Sambuc 	if (he != NULL) {
337*ebfedea0SLionel Sambuc 	    ret = add_hostent (port, protocol, socktype,
338*ebfedea0SLionel Sambuc 			       &current, const_v6, he, &flags);
339*ebfedea0SLionel Sambuc 	    freehostent (he);
340*ebfedea0SLionel Sambuc 	}
341*ebfedea0SLionel Sambuc     }
342*ebfedea0SLionel Sambuc #endif
343*ebfedea0SLionel Sambuc     if (family == PF_INET || family == PF_UNSPEC) {
344*ebfedea0SLionel Sambuc 	struct hostent *he;
345*ebfedea0SLionel Sambuc 
346*ebfedea0SLionel Sambuc 	he = getipnodebyname (nodename, PF_INET, 0, &error);
347*ebfedea0SLionel Sambuc 
348*ebfedea0SLionel Sambuc 	if (he != NULL) {
349*ebfedea0SLionel Sambuc 	    ret = add_hostent (port, protocol, socktype,
350*ebfedea0SLionel Sambuc 			       &current, const_v4, he, &flags);
351*ebfedea0SLionel Sambuc 	    freehostent (he);
352*ebfedea0SLionel Sambuc 	}
353*ebfedea0SLionel Sambuc     }
354*ebfedea0SLionel Sambuc     *res = first;
355*ebfedea0SLionel Sambuc     return ret;
356*ebfedea0SLionel Sambuc }
357*ebfedea0SLionel Sambuc 
358*ebfedea0SLionel Sambuc /*
359*ebfedea0SLionel Sambuc  * hints:
360*ebfedea0SLionel Sambuc  *
361*ebfedea0SLionel Sambuc  * struct addrinfo {
362*ebfedea0SLionel Sambuc  *     int    ai_flags;
363*ebfedea0SLionel Sambuc  *     int    ai_family;
364*ebfedea0SLionel Sambuc  *     int    ai_socktype;
365*ebfedea0SLionel Sambuc  *     int    ai_protocol;
366*ebfedea0SLionel Sambuc  * ...
367*ebfedea0SLionel Sambuc  * };
368*ebfedea0SLionel Sambuc  */
369*ebfedea0SLionel Sambuc 
370*ebfedea0SLionel Sambuc ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
getaddrinfo(const char * nodename,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)371*ebfedea0SLionel Sambuc getaddrinfo(const char *nodename,
372*ebfedea0SLionel Sambuc 	    const char *servname,
373*ebfedea0SLionel Sambuc 	    const struct addrinfo *hints,
374*ebfedea0SLionel Sambuc 	    struct addrinfo **res)
375*ebfedea0SLionel Sambuc {
376*ebfedea0SLionel Sambuc     int ret;
377*ebfedea0SLionel Sambuc     int port     = 0;
378*ebfedea0SLionel Sambuc     int protocol = 0;
379*ebfedea0SLionel Sambuc     int socktype = 0;
380*ebfedea0SLionel Sambuc 
381*ebfedea0SLionel Sambuc     *res = NULL;
382*ebfedea0SLionel Sambuc 
383*ebfedea0SLionel Sambuc     if (servname == NULL && nodename == NULL)
384*ebfedea0SLionel Sambuc 	return EAI_NONAME;
385*ebfedea0SLionel Sambuc 
386*ebfedea0SLionel Sambuc     if (hints != NULL
387*ebfedea0SLionel Sambuc 	&& hints->ai_family != PF_UNSPEC
388*ebfedea0SLionel Sambuc 	&& hints->ai_family != PF_INET
389*ebfedea0SLionel Sambuc #ifdef HAVE_IPV6
390*ebfedea0SLionel Sambuc 	&& hints->ai_family != PF_INET6
391*ebfedea0SLionel Sambuc #endif
392*ebfedea0SLionel Sambuc 	)
393*ebfedea0SLionel Sambuc 	return EAI_FAMILY;
394*ebfedea0SLionel Sambuc 
395*ebfedea0SLionel Sambuc     if (servname != NULL) {
396*ebfedea0SLionel Sambuc 	ret = get_port_protocol_socktype (servname, hints,
397*ebfedea0SLionel Sambuc 					  &port, &protocol, &socktype);
398*ebfedea0SLionel Sambuc 	if (ret)
399*ebfedea0SLionel Sambuc 	    return ret;
400*ebfedea0SLionel Sambuc     }
401*ebfedea0SLionel Sambuc     if (nodename != NULL) {
402*ebfedea0SLionel Sambuc 	ret = get_number (nodename, hints, port, protocol, socktype, res);
403*ebfedea0SLionel Sambuc 	if (ret) {
404*ebfedea0SLionel Sambuc 	    if(hints && hints->ai_flags & AI_NUMERICHOST)
405*ebfedea0SLionel Sambuc 		ret = EAI_NONAME;
406*ebfedea0SLionel Sambuc 	    else
407*ebfedea0SLionel Sambuc 		ret = get_nodes (nodename, hints, port, protocol, socktype,
408*ebfedea0SLionel Sambuc 				 res);
409*ebfedea0SLionel Sambuc 	}
410*ebfedea0SLionel Sambuc     } else {
411*ebfedea0SLionel Sambuc 	ret = get_null (hints, port, protocol, socktype, res);
412*ebfedea0SLionel Sambuc     }
413*ebfedea0SLionel Sambuc     if (ret)
414*ebfedea0SLionel Sambuc 	freeaddrinfo (*res);
415*ebfedea0SLionel Sambuc     return ret;
416*ebfedea0SLionel Sambuc }
417