]>
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
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
52 #include "compat/getaddrinfo.h"
53 #include "compat/inet_pton.h"
65 #include <sys/socket.h>
68 #include <netinet/in.h>
71 #include <arpa/inet.h>
81 static struct addrinfo
*
82 dup_addrinfo (struct addrinfo
*info
, void *addr
, size_t addrlen
) {
85 ret
= malloc (sizeof (struct addrinfo
));
88 memcpy (ret
, info
, sizeof (struct addrinfo
));
89 ret
->ai_addr
= malloc (addrlen
);
90 if (ret
->ai_addr
== NULL
) {
94 memcpy (ret
->ai_addr
, addr
, addrlen
);
95 ret
->ai_addrlen
= addrlen
;
100 xgetaddrinfo (const char *nodename
, const char *servname
,
101 const struct addrinfo
*hints
, struct addrinfo
**res
)
104 struct servent
*servent
;
105 const char *socktype
;
107 struct addrinfo hint
, result
;
108 struct addrinfo
*ai
, *sai
, *eai
;
111 if (servname
== NULL
&& nodename
== NULL
)
114 memset (&result
, 0, sizeof result
);
116 /* default for hints */
118 memset (&hint
, 0, sizeof hint
);
119 hint
.ai_family
= PF_UNSPEC
;
123 if (servname
== NULL
)
126 /* check for tcp or udp sockets only */
127 if (hints
->ai_socktype
== SOCK_STREAM
)
129 else if (hints
->ai_socktype
== SOCK_DGRAM
)
133 result
.ai_socktype
= hints
->ai_socktype
;
135 /* Note: maintain port in host byte order to make debugging easier */
136 if (isdigit (*servname
))
137 port
= strtol (servname
, NULL
, 10);
138 else if ((servent
= getservbyname (servname
, socktype
)) != NULL
)
139 port
= ntohs (servent
->s_port
);
144 /* if nodename == NULL refer to the local host for a client or any
146 if (nodename
== NULL
) {
147 struct sockaddr_in sin
;
149 /* check protocol family is PF_UNSPEC or PF_INET - could try harder
150 for IPv6 but that's more code than I'm prepared to write */
151 if (hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET
)
152 result
.ai_family
= AF_INET
;
156 sin
.sin_family
= result
.ai_family
;
157 sin
.sin_port
= htons (port
);
158 if (hints
->ai_flags
& AI_PASSIVE
)
159 sin
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
161 sin
.sin_addr
.s_addr
= htonl (INADDR_LOOPBACK
);
162 /* Duplicate result and addr and return */
163 *res
= dup_addrinfo (&result
, &sin
, sizeof sin
);
164 return (*res
== NULL
) ? EAI_MEMORY
: 0;
167 /* If AI_NUMERIC is specified, use inet_pton to translate numbers and
169 if (hints
->ai_flags
& AI_NUMERICHOST
) {
170 struct sockaddr_in sin
;
172 /* check protocol family is PF_UNSPEC or PF_INET */
173 if (hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET
)
174 result
.ai_family
= AF_INET
;
178 sin
.sin_family
= result
.ai_family
;
179 sin
.sin_port
= htons (port
);
180 if (inet_pton(result
.ai_family
, nodename
, &sin
.sin_addr
))
182 sin
.sin_addr
.s_addr
= inet_addr (nodename
);
183 /* Duplicate result and addr and return */
184 *res
= dup_addrinfo (&result
, &sin
, sizeof sin
);
185 return (*res
== NULL
) ? EAI_MEMORY
: 0;
190 hp
= gethostbyname(nodename
);
202 #if defined(NO_ADDRESS) && NO_ADDRESS != NO_DATA
216 /* Check that the address family is acceptable.
218 switch (hp
->h_addrtype
) {
220 if (!(hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET
))
225 if (!(hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET6
))
233 /* For each element pointed to by hp, create an element in the
234 result linked list. */
236 for (addrs
= hp
->h_addr_list
; *addrs
!= NULL
; addrs
++) {
240 if (hp
->h_length
< 1)
242 sa
.sa_family
= hp
->h_addrtype
;
243 switch (hp
->h_addrtype
) {
245 ((struct sockaddr_in
*) &sa
)->sin_port
= htons (port
);
246 memcpy (&((struct sockaddr_in
*) &sa
)->sin_addr
,
247 *addrs
, hp
->h_length
);
248 addrlen
= sizeof (struct sockaddr_in
);
253 ((struct sockaddr_in6
*) &sa
)->sin6_len
= hp
->h_length
;
255 ((struct sockaddr_in6
*) &sa
)->sin6_port
= htons (port
);
256 memcpy (&((struct sockaddr_in6
*) &sa
)->sin6_addr
,
257 *addrs
, hp
->h_length
);
258 addrlen
= sizeof (struct sockaddr_in6
);
265 result
.ai_family
= hp
->h_addrtype
;
266 ai
= dup_addrinfo (&result
, &sa
, addrlen
);
282 if (hints
->ai_flags
& AI_CANONNAME
) {
283 sai
->ai_canonname
= malloc (strlen (hp
->h_name
) + 1);
284 if (sai
->ai_canonname
== NULL
) {
288 strcpy (sai
->ai_canonname
, hp
->h_name
);
296 xfreeaddrinfo (struct addrinfo
*ai
)
298 struct addrinfo
*next
;
302 if (ai
->ai_canonname
!= NULL
)
303 free (ai
->ai_canonname
);
304 if (ai
->ai_addr
!= NULL
)
312 xgai_strerror (int ecode
)
314 static const char *eai_descr
[] = {
316 "address family for nodename not supported", /* EAI_ADDRFAMILY */
317 "temporary failure in name resolution", /* EAI_AGAIN */
318 "invalid value for ai_flags", /* EAI_BADFLAGS */
319 "non-recoverable failure in name resolution", /* EAI_FAIL */
320 "ai_family not supported", /* EAI_FAMILY */
321 "memory allocation failure", /* EAI_MEMORY */
322 "no address associated with nodename", /* EAI_NODATA */
323 "nodename nor servname provided, or not known", /* EAI_NONAME */
324 "servname not supported for ai_socktype", /* EAI_SERVICE */
325 "ai_socktype not supported", /* EAI_SOCKTYPE */
326 "system error returned in errno", /* EAI_SYSTEM */
327 "argument buffer overflow", /* EAI_OVERFLOW */
330 if (ecode
< 0 || ecode
> (int) (sizeof eai_descr
/ sizeof eai_descr
[0]))
331 return "unknown error";
332 return eai_descr
[ecode
];
335 #endif /* HAVE_GETADDRINFO */