Fix #8316: Make sort industries by production and transported with a cargo filter...
[openttd-github.git] / src / 3rdparty / os2 / getaddrinfo.c
blob3cdda21f1bb5db475e891da3919ce987094aadbd
1 /*
2 * This file is part of libESMTP, a library for submission of RFC 2822
3 * formatted electronic mail messages using the SMTP protocol described
4 * in RFC 2821.
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.
26 #if !HAVE_GETADDRINFO
28 /* Need to turn off Posix features in glibc to build this */
29 #undef _POSIX_C_SOURCE
30 #undef _XOPEN_SOURCE
32 #include "getaddrinfo.h"
33 //#include "compat/inet_pton.h"
35 #include <string.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <netdb.h>
43 static struct addrinfo *
44 dup_addrinfo (struct addrinfo *info, void *addr, size_t addrlen) {
45 struct addrinfo *ret;
47 ret = malloc (sizeof (struct addrinfo));
48 if (ret == NULL)
49 return NULL;
50 memcpy (ret, info, sizeof (struct addrinfo));
51 ret->ai_addr = malloc (addrlen);
52 if (ret->ai_addr == NULL) {
53 free (ret);
54 return NULL;
56 memcpy (ret->ai_addr, addr, addrlen);
57 ret->ai_addrlen = addrlen;
58 return ret;
61 int
62 getaddrinfo (const char *nodename, const char *servname,
63 const struct addrinfo *hints, struct addrinfo **res)
65 struct hostent *hp;
66 struct servent *servent;
67 const char *socktype;
68 int port;
69 struct addrinfo hint, result;
70 struct addrinfo *ai, *sai, *eai;
71 char **addrs;
73 if (servname == NULL && nodename == NULL)
74 return EAI_NONAME;
76 memset (&result, 0, sizeof result);
78 /* default for hints */
79 if (hints == NULL) {
80 memset (&hint, 0, sizeof hint);
81 hint.ai_family = PF_UNSPEC;
82 hints = &hint;
85 if (servname == NULL)
86 port = 0;
87 else {
88 /* check for tcp or udp sockets only */
89 if (hints->ai_socktype == SOCK_STREAM)
90 socktype = "tcp";
91 else if (hints->ai_socktype == SOCK_DGRAM)
92 socktype = "udp";
93 else
94 return EAI_SERVICE;
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);
102 else
103 return EAI_NONAME;
106 /* if nodename == NULL refer to the local host for a client or any
107 for a server */
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;
115 else
116 return EAI_FAMILY;
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);
122 else
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
130 dots notation. */
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;
137 else
138 return EAI_FAMILY;
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)
143 return EAI_NONAME;
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;
150 #if HAVE_H_ERRNO
151 h_errno = 0;
152 #endif
153 errno = 0;
154 hp = gethostbyname(nodename);
155 if (hp == NULL) {
156 #ifdef EAI_SYSTEM
157 if (errno != 0) {
158 return EAI_SYSTEM;
160 #endif
161 switch (h_errno) {
162 case HOST_NOT_FOUND:
163 return EAI_NODATA;
164 case NO_DATA:
165 return EAI_NODATA;
166 #if defined(NO_ADDRESS) && NO_ADDRESS != NO_DATA
167 case NO_ADDRESS:
168 return EAI_NODATA;
169 #endif
170 case NO_RECOVERY:
171 return EAI_FAIL;
172 case TRY_AGAIN:
173 return EAI_AGAIN;
174 default:
175 return EAI_FAIL;
177 return EAI_FAIL;
180 /* Check that the address family is acceptable.
182 switch (hp->h_addrtype) {
183 case AF_INET:
184 if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET))
185 return EAI_FAMILY;
186 break;
187 #ifndef __OS2__
188 case AF_INET6:
189 if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET6))
190 return EAI_FAMILY;
191 break;
192 #endif
193 default:
194 return EAI_FAMILY;
197 /* For each element pointed to by hp, create an element in the
198 result linked list. */
199 sai = eai = NULL;
200 for (addrs = hp->h_addr_list; *addrs != NULL; addrs++) {
201 struct sockaddr sa;
202 size_t addrlen;
204 if (hp->h_length < 1)
205 continue;
206 sa.sa_family = hp->h_addrtype;
207 switch (hp->h_addrtype) {
208 case AF_INET:
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);
213 break;
214 #ifndef __OS2__
215 case AF_INET6:
216 #if SIN6_LEN
217 ((struct sockaddr_in6 *) &sa)->sin6_len = hp->h_length;
218 #endif
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);
223 break;
224 #endif
225 default:
226 continue;
229 result.ai_family = hp->h_addrtype;
230 ai = dup_addrinfo (&result, &sa, addrlen);
231 if (ai == NULL) {
232 freeaddrinfo (sai);
233 return EAI_MEMORY;
235 if (sai == NULL)
236 sai = ai;
237 else
238 eai->ai_next = ai;
239 eai = ai;
242 if (sai == NULL) {
243 return EAI_NODATA;
246 if (hints->ai_flags & AI_CANONNAME) {
247 sai->ai_canonname = malloc (strlen (hp->h_name) + 1);
248 if (sai->ai_canonname == NULL) {
249 freeaddrinfo (sai);
250 return EAI_MEMORY;
252 strcpy (sai->ai_canonname, hp->h_name);
255 *res = sai;
256 return 0;
259 void
260 freeaddrinfo (struct addrinfo *ai)
262 struct addrinfo *next;
264 while (ai != NULL) {
265 next = ai->ai_next;
266 if (ai->ai_canonname != NULL)
267 free (ai->ai_canonname);
268 if (ai->ai_addr != NULL)
269 free (ai->ai_addr);
270 free (ai);
271 ai = next;
275 const char *
276 gai_strerror (int ecode)
278 static const char *eai_descr[] = {
279 "no error",
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 */