]>
git.ipfire.org Git - thirdparty/squid.git/blob - lib/getaddrinfo.c
2 * Shamelessly duplicated from the fetchmail public sources
3 * for use by the Squid Project under GNU Public License.
5 * Update/Maintenance History:
7 * 15-Aug-2007 : Copied from fetchmail 6.3.8
8 * - added protection around libray headers
10 * 16-Aug-2007 : Altered configure checks
11 * Un-hacked slightly to use system gethostbyname()
13 * 06-Oct-2007 : Various fixes to allow the build on MinGW
15 * Squid CVS $Id: getaddrinfo.c,v 1.1 2007/12/14 05:03:26 amosjeffries Exp $
17 * Original License and code follows.
22 * This file is part of libESMTP, a library for submission of RFC 2822
23 * formatted electronic mail messages using the SMTP protocol described
26 * Copyright (C) 2001,2002 Brian Stafford <brian@stafford.uklinux.net>
28 * This library is free software; you can redistribute it and/or
29 * modify it under the terms of the GNU Lesser General Public
30 * License as published by the Free Software Foundation; either
31 * version 2.1 of the License, or (at your option) any later version.
33 * This library is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 * Lesser General Public License for more details.
38 * You should have received a copy of the GNU Lesser General Public
39 * License along with this library; if not, write to the Free Software
40 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
43 /* An emulation of the RFC 2553 / Posix getaddrinfo resolver interface.
46 #ifndef HAVE_GETADDRINFO
48 /* Need to turn off Posix features in glibc to build this */
49 #undef _POSIX_C_SOURCE
66 #include <sys/socket.h>
69 #include <netinet/in.h>
72 #include <arpa/inet.h>
82 #include "getaddrinfo.h"
83 #include "inet_pton.h"
85 static struct addrinfo
*
86 dup_addrinfo (struct addrinfo
*info
, void *addr
, size_t addrlen
)
90 ret
= malloc (sizeof (struct addrinfo
));
93 memcpy (ret
, info
, sizeof (struct addrinfo
));
94 ret
->ai_addr
= malloc (addrlen
);
95 if (ret
->ai_addr
== NULL
)
100 memcpy (ret
->ai_addr
, addr
, addrlen
);
101 ret
->ai_addrlen
= addrlen
;
106 xgetaddrinfo (const char *nodename
, const char *servname
,
107 const struct addrinfo
*hints
, struct addrinfo
**res
)
110 struct servent
*servent
;
111 const char *socktype
;
113 struct addrinfo hint
, result
;
114 struct addrinfo
*ai
, *sai
, *eai
;
117 if (servname
== NULL
&& nodename
== NULL
)
120 memset (&result
, 0, sizeof result
);
122 /* default for hints */
125 memset (&hint
, 0, sizeof hint
);
126 hint
.ai_family
= PF_UNSPEC
;
130 if (servname
== NULL
)
133 /* check for tcp or udp sockets only */
134 if (hints
->ai_socktype
== SOCK_STREAM
)
136 else if (hints
->ai_socktype
== SOCK_DGRAM
)
140 result
.ai_socktype
= hints
->ai_socktype
;
142 /* Note: maintain port in host byte order to make debugging easier */
143 if (isdigit (*servname
))
144 port
= strtol (servname
, NULL
, 10);
145 else if ((servent
= getservbyname (servname
, socktype
)) != NULL
)
146 port
= ntohs (servent
->s_port
);
151 /* if nodename == NULL refer to the local host for a client or any
153 if (nodename
== NULL
)
155 struct sockaddr_in sin
;
157 /* check protocol family is PF_UNSPEC or PF_INET - could try harder
158 for IPv6 but that's more code than I'm prepared to write */
159 if (hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET
)
160 result
.ai_family
= AF_INET
;
164 sin
.sin_family
= result
.ai_family
;
165 sin
.sin_port
= htons (port
);
166 if (hints
->ai_flags
& AI_PASSIVE
)
167 sin
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
169 sin
.sin_addr
.s_addr
= htonl (INADDR_LOOPBACK
);
170 /* Duplicate result and addr and return */
171 *res
= dup_addrinfo (&result
, &sin
, sizeof sin
);
172 return (*res
== NULL
) ? EAI_MEMORY
: 0;
175 /* If AI_NUMERIC is specified, use xinet_pton to translate numbers and
177 if (hints
->ai_flags
& AI_NUMERICHOST
)
179 struct sockaddr_in sin
;
181 /* check protocol family is PF_UNSPEC or PF_INET */
182 if (hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET
)
183 result
.ai_family
= AF_INET
;
187 sin
.sin_family
= result
.ai_family
;
188 sin
.sin_port
= htons (port
);
189 if (xinet_pton(result
.ai_family
, nodename
, &sin
.sin_addr
))
191 sin
.sin_addr
.s_addr
= inet_addr (nodename
);
192 /* Duplicate result and addr and return */
193 *res
= dup_addrinfo (&result
, &sin
, sizeof sin
);
194 return (*res
== NULL
) ? EAI_MEMORY
: 0;
199 hp
= gethostbyname(nodename
);
209 case HOST_NOT_FOUND
: return EAI_NODATA
;
210 case NO_DATA
: return EAI_NODATA
;
211 #if defined(NO_ADDRESS) && NO_ADDRESS != NO_DATA
212 case NO_ADDRESS
: return EAI_NODATA
;
214 case NO_RECOVERY
: return EAI_FAIL
;
215 case TRY_AGAIN
: return EAI_AGAIN
;
216 default: return EAI_FAIL
;
221 /* Check that the address family is acceptable.
223 switch (hp
->h_addrtype
)
226 if (!(hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET
))
231 if (!(hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET6
))
239 /* For each element pointed to by hp, create an element in the
240 result linked list. */
242 for (addrs
= hp
->h_addr_list
; *addrs
!= NULL
; addrs
++)
247 if (hp
->h_length
< 1)
249 sa
.sa_family
= hp
->h_addrtype
;
250 switch (hp
->h_addrtype
)
253 ((struct sockaddr_in
*) &sa
)->sin_port
= htons (port
);
254 memcpy (&((struct sockaddr_in
*) &sa
)->sin_addr
,
255 *addrs
, hp
->h_length
);
256 addrlen
= sizeof (struct sockaddr_in
);
261 ((struct sockaddr_in6
*) &sa
)->sin6_len
= hp
->h_length
;
263 ((struct sockaddr_in6
*) &sa
)->sin6_port
= htons (port
);
264 memcpy (&((struct sockaddr_in6
*) &sa
)->sin6_addr
,
265 *addrs
, hp
->h_length
);
266 addrlen
= sizeof (struct sockaddr_in6
);
273 result
.ai_family
= hp
->h_addrtype
;
274 ai
= dup_addrinfo (&result
, &sa
, addrlen
);
292 if (hints
->ai_flags
& AI_CANONNAME
)
294 sai
->ai_canonname
= malloc (strlen (hp
->h_name
) + 1);
295 if (sai
->ai_canonname
== NULL
)
300 strcpy (sai
->ai_canonname
, hp
->h_name
);
308 xfreeaddrinfo (struct addrinfo
*ai
)
310 struct addrinfo
*next
;
315 if (ai
->ai_canonname
!= NULL
)
316 free (ai
->ai_canonname
);
317 if (ai
->ai_addr
!= NULL
)
325 xgai_strerror (int ecode
)
327 static const char *eai_descr
[] =
330 "address family for nodename not supported", /* EAI_ADDRFAMILY */
331 "temporary failure in name resolution", /* EAI_AGAIN */
332 "invalid value for ai_flags", /* EAI_BADFLAGS */
333 "non-recoverable failure in name resolution", /* EAI_FAIL */
334 "ai_family not supported", /* EAI_FAMILY */
335 "memory allocation failure", /* EAI_MEMORY */
336 "no address associated with nodename", /* EAI_NODATA */
337 "nodename nor servname provided, or not known", /* EAI_NONAME */
338 "servname not supported for ai_socktype", /* EAI_SERVICE */
339 "ai_socktype not supported", /* EAI_SOCKTYPE */
340 "system error returned in errno", /* EAI_SYSTEM */
341 "argument buffer overflow", /* EAI_OVERFLOW */
344 if (ecode
< 0 || ecode
> (int) (sizeof eai_descr
/ sizeof eai_descr
[0]))
345 return "unknown error";
346 return eai_descr
[ecode
];
349 #endif /* HAVE_GETADDRINFO */