2 * This file is part of libESMTP, a library for submission of RFC 2822
3 * formatted electronic mail messages using the SMTP protocol described
6 * Copyright (C) 2001,2002 Brian Stafford <brian@stafford.uklinux.net>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 /* An emulation of the RFC 2553 / Posix getaddrinfo resolver interface.
28 /* Need to turn off Posix features in glibc to build this */
29 #undef _POSIX_C_SOURCE
32 #include "getaddrinfo.h"
33 //#include "compat/inet_pton.h"
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
43 static struct addrinfo
*
44 dup_addrinfo (struct addrinfo
*info
, void *addr
, size_t addrlen
) {
47 ret
= malloc (sizeof (struct addrinfo
));
50 memcpy (ret
, info
, sizeof (struct addrinfo
));
51 ret
->ai_addr
= malloc (addrlen
);
52 if (ret
->ai_addr
== NULL
) {
56 memcpy (ret
->ai_addr
, addr
, addrlen
);
57 ret
->ai_addrlen
= addrlen
;
62 getaddrinfo (const char *nodename
, const char *servname
,
63 const struct addrinfo
*hints
, struct addrinfo
**res
)
66 struct servent
*servent
;
69 struct addrinfo hint
, result
;
70 struct addrinfo
*ai
, *sai
, *eai
;
73 if (servname
== NULL
&& nodename
== NULL
)
76 memset (&result
, 0, sizeof result
);
78 /* default for hints */
80 memset (&hint
, 0, sizeof hint
);
81 hint
.ai_family
= PF_UNSPEC
;
88 /* check for tcp or udp sockets only */
89 if (hints
->ai_socktype
== SOCK_STREAM
)
91 else if (hints
->ai_socktype
== SOCK_DGRAM
)
95 result
.ai_socktype
= hints
->ai_socktype
;
97 /* Note: maintain port in host byte order to make debugging easier */
98 if (isdigit (*servname
))
99 port
= strtol (servname
, NULL
, 10);
100 else if ((servent
= getservbyname (servname
, socktype
)) != NULL
)
101 port
= ntohs (servent
->s_port
);
106 /* if nodename == NULL refer to the local host for a client or any
108 if (nodename
== NULL
) {
109 struct sockaddr_in sin
;
111 /* check protocol family is PF_UNSPEC or PF_INET - could try harder
112 for IPv6 but that's more code than I'm prepared to write */
113 if (hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET
)
114 result
.ai_family
= AF_INET
;
118 sin
.sin_family
= result
.ai_family
;
119 sin
.sin_port
= htons (port
);
120 if (hints
->ai_flags
& AI_PASSIVE
)
121 sin
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
123 sin
.sin_addr
.s_addr
= htonl (INADDR_LOOPBACK
);
124 /* Duplicate result and addr and return */
125 *res
= dup_addrinfo (&result
, &sin
, sizeof sin
);
126 return (*res
== NULL
) ? EAI_MEMORY
: 0;
129 /* If AI_NUMERIC is specified, use inet_pton to translate numbers and
131 if (hints
->ai_flags
& AI_NUMERICHOST
) {
132 struct sockaddr_in sin
;
134 /* check protocol family is PF_UNSPEC or PF_INET */
135 if (hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET
)
136 result
.ai_family
= AF_INET
;
140 sin
.sin_family
= result
.ai_family
;
141 sin
.sin_port
= htons (port
);
142 if (inet_pton(result
.ai_family
, nodename
, &sin
.sin_addr
)==0)
144 sin
.sin_addr
.s_addr
= inet_addr (nodename
);
145 /* Duplicate result and addr and return */
146 *res
= dup_addrinfo (&result
, &sin
, sizeof sin
);
147 return (*res
== NULL
) ? EAI_MEMORY
: 0;
154 hp
= gethostbyname(nodename
);
166 #if defined(NO_ADDRESS) && NO_ADDRESS != NO_DATA
180 /* Check that the address family is acceptable.
182 switch (hp
->h_addrtype
) {
184 if (!(hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET
))
189 if (!(hints
->ai_family
== PF_UNSPEC
|| hints
->ai_family
== PF_INET6
))
197 /* For each element pointed to by hp, create an element in the
198 result linked list. */
200 for (addrs
= hp
->h_addr_list
; *addrs
!= NULL
; addrs
++) {
204 if (hp
->h_length
< 1)
206 sa
.sa_family
= hp
->h_addrtype
;
207 switch (hp
->h_addrtype
) {
209 ((struct sockaddr_in
*) &sa
)->sin_port
= htons (port
);
210 memcpy (&((struct sockaddr_in
*) &sa
)->sin_addr
,
211 *addrs
, hp
->h_length
);
212 addrlen
= sizeof (struct sockaddr_in
);
217 ((struct sockaddr_in6
*) &sa
)->sin6_len
= hp
->h_length
;
219 ((struct sockaddr_in6
*) &sa
)->sin6_port
= htons (port
);
220 memcpy (&((struct sockaddr_in6
*) &sa
)->sin6_addr
,
221 *addrs
, hp
->h_length
);
222 addrlen
= sizeof (struct sockaddr_in6
);
229 result
.ai_family
= hp
->h_addrtype
;
230 ai
= dup_addrinfo (&result
, &sa
, addrlen
);
246 if (hints
->ai_flags
& AI_CANONNAME
) {
247 sai
->ai_canonname
= malloc (strlen (hp
->h_name
) + 1);
248 if (sai
->ai_canonname
== NULL
) {
252 strcpy (sai
->ai_canonname
, hp
->h_name
);
260 freeaddrinfo (struct addrinfo
*ai
)
262 struct addrinfo
*next
;
266 if (ai
->ai_canonname
!= NULL
)
267 free (ai
->ai_canonname
);
268 if (ai
->ai_addr
!= NULL
)
276 gai_strerror (int ecode
)
278 static const char *eai_descr
[] = {
280 "address family for nodename not supported", /* EAI_ADDRFAMILY */
281 "temporary failure in name resolution", /* EAI_AGAIN */
282 "invalid value for ai_flags", /* EAI_BADFLAGS */
283 "non-recoverable failure in name resolution", /* EAI_FAIL */
284 "ai_family not supported", /* EAI_FAMILY */
285 "memory allocation failure", /* EAI_MEMORY */
286 "no address associated with nodename", /* EAI_NODATA */
287 "nodename nor servname provided, or not known", /* EAI_NONAME */
288 "servname not supported for ai_socktype", /* EAI_SERVICE */
289 "ai_socktype not supported", /* EAI_SOCKTYPE */
290 "system error returned in errno", /* EAI_SYSTEM */
291 "argument buffer overflow", /* EAI_OVERFLOW */
294 if (ecode
< 0 || ecode
> (int) (sizeof eai_descr
/ sizeof eai_descr
[0]))
295 return "unknown error";
296 return eai_descr
[ecode
];
299 #endif /* HAVE_GETADDRINFO */