]>
git.ipfire.org Git - thirdparty/squid.git/blob - lib/getaddrinfo.c
becb57b0e8d6ccd58e68745039d3576fa6c5e9a6
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
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
) {
89 ret
= malloc (sizeof (struct addrinfo
));
92 memcpy (ret
, info
, sizeof (struct addrinfo
));
93 ret
->ai_addr
= malloc (addrlen
);
94 if (ret
->ai_addr
== NULL
) {
98 memcpy (ret
->ai_addr
, addr
, addrlen
);
99 ret
->ai_addrlen
= addrlen
;
104 xgetaddrinfo (const char *nodename
, const char *servname
,
105 const struct addrinfo
*hints
, struct addrinfo
**res
)
108 struct servent
*servent
;
109 const char *socktype
;
111 struct addrinfo hint
, result
;
112 struct addrinfo
*ai
, *sai
, *eai
;
115 if (servname
== NULL
&& nodename
== NULL
)
118 memset (&result
, 0, sizeof result
);
120 /* default for hints */
122 memset (&hint
, 0, sizeof hint
);
123 hint
.ai_family
= PF_UNSPEC
;
127 if (servname
== NULL
)
130 /* check for tcp or udp sockets only */
131 if (hints
->ai_socktype
== SOCK_STREAM
)
133 else if (hints
->ai_socktype
== SOCK_DGRAM
)
137 result
.ai_socktype
= hints
->ai_socktype
;
139 /* Note: maintain port in host byte order to make debugging easier */
140 if (isdigit (*servname
))
141 port
= strtol (servname
, NULL
, 10);
142 else if ((servent
= getservbyname (servname
, socktype
)) != NULL
)
143 port
= ntohs (servent
->s_port
);
148 /* if nodename == NULL refer to the local host for a client or any
150 if (nodename
== NULL
) {
151 struct sockaddr_in sin
;
153 /* check protocol family is PF_UNSPEC or PF_INET - could try harder
154 for IPv6 but that's more code than I'm prepared to write */
155 if (hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET
)
156 result
.ai_family
= AF_INET
;
160 sin
.sin_family
= result
.ai_family
;
161 sin
.sin_port
= htons (port
);
162 if (hints
->ai_flags
& AI_PASSIVE
)
163 sin
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
165 sin
.sin_addr
.s_addr
= htonl (INADDR_LOOPBACK
);
166 /* Duplicate result and addr and return */
167 *res
= dup_addrinfo (&result
, &sin
, sizeof sin
);
168 return (*res
== NULL
) ? EAI_MEMORY
: 0;
171 /* If AI_NUMERIC is specified, use xinet_pton to translate numbers and
173 if (hints
->ai_flags
& AI_NUMERICHOST
) {
174 struct sockaddr_in sin
;
176 /* check protocol family is PF_UNSPEC or PF_INET */
177 if (hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET
)
178 result
.ai_family
= AF_INET
;
182 sin
.sin_family
= result
.ai_family
;
183 sin
.sin_port
= htons (port
);
184 if (xinet_pton(result
.ai_family
, nodename
, &sin
.sin_addr
))
186 sin
.sin_addr
.s_addr
= inet_addr (nodename
);
187 /* Duplicate result and addr and return */
188 *res
= dup_addrinfo (&result
, &sin
, sizeof sin
);
189 return (*res
== NULL
) ? EAI_MEMORY
: 0;
194 hp
= gethostbyname(nodename
);
206 #if defined(NO_ADDRESS) && NO_ADDRESS != NO_DATA
220 /* Check that the address family is acceptable.
222 switch (hp
->h_addrtype
) {
224 if (!(hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET
))
229 if (!(hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET6
))
237 /* For each element pointed to by hp, create an element in the
238 result linked list. */
240 for (addrs
= hp
->h_addr_list
; *addrs
!= NULL
; addrs
++) {
244 if (hp
->h_length
< 1)
246 sa
.sa_family
= hp
->h_addrtype
;
247 switch (hp
->h_addrtype
) {
249 ((struct sockaddr_in
*) &sa
)->sin_port
= htons (port
);
250 memcpy (&((struct sockaddr_in
*) &sa
)->sin_addr
,
251 *addrs
, hp
->h_length
);
252 addrlen
= sizeof (struct sockaddr_in
);
257 ((struct sockaddr_in6
*) &sa
)->sin6_len
= hp
->h_length
;
259 ((struct sockaddr_in6
*) &sa
)->sin6_port
= htons (port
);
260 memcpy (&((struct sockaddr_in6
*) &sa
)->sin6_addr
,
261 *addrs
, hp
->h_length
);
262 addrlen
= sizeof (struct sockaddr_in6
);
269 result
.ai_family
= hp
->h_addrtype
;
270 ai
= dup_addrinfo (&result
, &sa
, addrlen
);
286 if (hints
->ai_flags
& AI_CANONNAME
) {
287 sai
->ai_canonname
= malloc (strlen (hp
->h_name
) + 1);
288 if (sai
->ai_canonname
== NULL
) {
292 strcpy (sai
->ai_canonname
, hp
->h_name
);
300 xfreeaddrinfo (struct addrinfo
*ai
)
302 struct addrinfo
*next
;
306 if (ai
->ai_canonname
!= NULL
)
307 free (ai
->ai_canonname
);
308 if (ai
->ai_addr
!= NULL
)
316 xgai_strerror (int ecode
)
318 static const char *eai_descr
[] = {
320 "address family for nodename not supported", /* EAI_ADDRFAMILY */
321 "temporary failure in name resolution", /* EAI_AGAIN */
322 "invalid value for ai_flags", /* EAI_BADFLAGS */
323 "non-recoverable failure in name resolution", /* EAI_FAIL */
324 "ai_family not supported", /* EAI_FAMILY */
325 "memory allocation failure", /* EAI_MEMORY */
326 "no address associated with nodename", /* EAI_NODATA */
327 "nodename nor servname provided, or not known", /* EAI_NONAME */
328 "servname not supported for ai_socktype", /* EAI_SERVICE */
329 "ai_socktype not supported", /* EAI_SOCKTYPE */
330 "system error returned in errno", /* EAI_SYSTEM */
331 "argument buffer overflow", /* EAI_OVERFLOW */
334 if (ecode
< 0 || ecode
> (int) (sizeof eai_descr
/ sizeof eai_descr
[0]))
335 return "unknown error";
336 return eai_descr
[ecode
];
339 #endif /* HAVE_GETADDRINFO */