Doc fix.
[gsasl.git] / gl / getaddrinfo.c
blob9003abf60ac7e145ac755153de2897df22e7837c
1 /* Get address information (partial implementation).
2 Copyright (C) 1997, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
3 Contributed by Simon Josefsson <simon@josefsson.org>.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #include "getaddrinfo.h"
25 #if HAVE_NETINET_IN_H
26 # include <netinet/in.h>
27 #endif
29 /* Get calloc. */
30 #include <stdlib.h>
32 /* Get memcpy. */
33 #include <string.h>
35 #include <stdbool.h>
37 #include "gettext.h"
38 #define _(String) gettext (String)
39 #define N_(String) String
41 #include "inet_ntop.h"
42 #include "snprintf.h"
43 #include "strdup.h"
45 #if defined _WIN32 || defined __WIN32__
46 # define WIN32_NATIVE
47 #endif
49 #ifdef WIN32_NATIVE
50 typedef int (WSAAPI *getaddrinfo_func) (const char*, const char*,
51 const struct addrinfo*,
52 struct addrinfo**);
53 typedef void (WSAAPI *freeaddrinfo_func) (struct addrinfo*);
54 typedef int (WSAAPI *getnameinfo_func) (const struct sockaddr*,
55 socklen_t, char*, DWORD,
56 char*, DWORD, int);
58 static getaddrinfo_func getaddrinfo_ptr = NULL;
59 static freeaddrinfo_func freeaddrinfo_ptr = NULL;
60 static getnameinfo_func getnameinfo_ptr = NULL;
62 static int
63 use_win32_p (void)
65 static int done = 0;
66 HMODULE h;
68 if (done)
69 return getaddrinfo_ptr ? 1 : 0;
71 done = 1;
73 h = GetModuleHandle ("ws2_32.dll");
75 if (h)
77 getaddrinfo_ptr = (getaddrinfo_func) GetProcAddress (h, "getaddrinfo");
78 freeaddrinfo_ptr = (freeaddrinfo_func) GetProcAddress (h, "freeaddrinfo");
79 getnameinfo_ptr = (getnameinfo_func) GetProcAddress (h, "getnameinfo");
82 /* If either is missing, something is odd. */
83 if (!getaddrinfo_ptr || !freeaddrinfo_ptr || !getnameinfo_ptr)
85 getaddrinfo_ptr = NULL;
86 freeaddrinfo_ptr = NULL;
87 getnameinfo_ptr = NULL;
88 return 0;
91 return 1;
93 #endif
95 static inline bool
96 validate_family (int family)
98 /* FIXME: Support more families. */
99 #if HAVE_IPV4
100 if (family == PF_INET)
101 return true;
102 #endif
103 #if HAVE_IPV6
104 if (family == PF_INET6)
105 return true;
106 #endif
107 if (family == PF_UNSPEC)
108 return true;
109 return false;
112 /* Translate name of a service location and/or a service name to set of
113 socket addresses. */
115 getaddrinfo (const char *restrict nodename,
116 const char *restrict servname,
117 const struct addrinfo *restrict hints,
118 struct addrinfo **restrict res)
120 struct addrinfo *tmp;
121 int port = 0;
122 struct hostent *he;
123 void *storage;
124 size_t size;
125 #if HAVE_IPV6
126 struct v6_pair {
127 struct addrinfo addrinfo;
128 struct sockaddr_in6 sockaddr_in6;
130 #endif
131 #if HAVE_IPV4
132 struct v4_pair {
133 struct addrinfo addrinfo;
134 struct sockaddr_in sockaddr_in;
136 #endif
138 #ifdef WIN32_NATIVE
139 if (use_win32_p ())
140 return getaddrinfo_ptr (nodename, servname, hints, res);
141 #endif
143 if (hints && (hints->ai_flags & ~(AI_CANONNAME|AI_PASSIVE)))
144 /* FIXME: Support more flags. */
145 return EAI_BADFLAGS;
147 if (hints && !validate_family (hints->ai_family))
148 return EAI_FAMILY;
150 if (hints &&
151 hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM)
152 /* FIXME: Support other socktype. */
153 return EAI_SOCKTYPE; /* FIXME: Better return code? */
155 if (!nodename)
157 if (!(hints->ai_flags & AI_PASSIVE))
158 return EAI_NONAME;
160 #ifdef HAVE_IPV6
161 nodename = (hint->ai_family == AF_INET6) ? "::" : "0.0.0.0";
162 #else
163 nodename = "0.0.0.0";
164 #endif
167 if (servname)
169 struct servent *se = NULL;
170 const char *proto =
171 (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
173 if (!(hints->ai_flags & AI_NUMERICSERV))
174 /* FIXME: Use getservbyname_r if available. */
175 se = getservbyname (servname, proto);
177 if (!se)
179 char *c;
180 if (!(*servname >= '0' && *servname <= '9'))
181 return EAI_NONAME;
182 port = strtoul (servname, &c, 10);
183 if (*c || port > 0xffff)
184 return EAI_NONAME;
185 port = htons (port);
187 else
188 port = se->s_port;
191 /* FIXME: Use gethostbyname_r if available. */
192 he = gethostbyname (nodename);
193 if (!he || he->h_addr_list[0] == NULL)
194 return EAI_NONAME;
196 switch (he->h_addrtype)
198 #if HAVE_IPV6
199 case PF_INET6:
200 size = sizeof (struct v6_pair);
201 break;
202 #endif
204 #if HAVE_IPV4
205 case PF_INET:
206 size = sizeof (struct v4_pair);
207 break;
208 #endif
210 default:
211 return EAI_NODATA;
214 storage = calloc (1, size);
215 if (!storage)
216 return EAI_MEMORY;
218 switch (he->h_addrtype)
220 #if HAVE_IPV6
221 case PF_INET6:
223 struct v6_pair *p = storage;
224 struct sockaddr_in6 *sinp = &p->sockaddr_in6;
225 tmp = &p->addrinfo;
227 if (port)
228 sinp->sin6_port = port;
230 if (he->h_length != sizeof (sinp->sin6_addr))
232 free (storage);
233 return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */
236 memcpy (&sinp->sin6_addr, he->h_addr_list[0], sizeof sinp->sin6_addr);
238 tmp->ai_addr = (struct sockaddr *) sinp;
239 tmp->ai_addrlen = sizeof *sinp;
241 break;
242 #endif
244 #if HAVE_IPV4
245 case PF_INET:
247 struct v4_pair *p = storage;
248 struct sockaddr_in *sinp = &p->sockaddr_in;
249 tmp = &p->addrinfo;
251 if (port)
252 sinp->sin_port = port;
254 if (he->h_length != sizeof (sinp->sin_addr))
256 free (storage);
257 return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */
260 memcpy (&sinp->sin_addr, he->h_addr_list[0], sizeof sinp->sin_addr);
262 tmp->ai_addr = (struct sockaddr *) sinp;
263 tmp->ai_addrlen = sizeof *sinp;
265 break;
266 #endif
268 default:
269 free (storage);
270 return EAI_NODATA;
273 if (hints && hints->ai_flags & AI_CANONNAME)
275 const char *cn;
276 if (he->h_name)
277 cn = he->h_name;
278 else
279 cn = nodename;
281 tmp->ai_canonname = strdup (cn);
282 if (!tmp->ai_canonname)
284 free (storage);
285 return EAI_MEMORY;
289 tmp->ai_protocol = (hints) ? hints->ai_protocol : 0;
290 tmp->ai_socktype = (hints) ? hints->ai_socktype : 0;
291 tmp->ai_addr->sa_family = he->h_addrtype;
292 tmp->ai_family = he->h_addrtype;
294 /* FIXME: If more than one address, create linked list of addrinfo's. */
296 *res = tmp;
298 return 0;
301 /* Free `addrinfo' structure AI including associated storage. */
302 void
303 freeaddrinfo (struct addrinfo *ai)
305 #ifdef WIN32_NATIVE
306 if (use_win32_p ())
308 freeaddrinfo_ptr (ai);
309 return;
311 #endif
313 while (ai)
315 struct addrinfo *cur;
317 cur = ai;
318 ai = ai->ai_next;
320 if (cur->ai_canonname) free (cur->ai_canonname);
321 free (cur);
325 int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
326 char *restrict node, socklen_t nodelen,
327 char *restrict service, socklen_t servicelen,
328 int flags)
330 #ifdef WIN32_NATIVE
331 if (use_win32_p ())
332 return getnameinfo_ptr (sa, salen, node, nodelen,
333 service, servicelen, flags);
334 #endif
336 /* FIXME: Support other flags. */
337 if ((node && nodelen > 0 && !(flags & NI_NUMERICHOST)) ||
338 (service && servicelen > 0 && !(flags & NI_NUMERICHOST)) ||
339 (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV)))
340 return EAI_BADFLAGS;
342 if (sa == NULL || salen < sizeof (sa->sa_family))
343 return EAI_FAMILY;
345 switch (sa->sa_family)
347 #if HAVE_IPV4
348 case AF_INET:
349 if (salen < sizeof (struct sockaddr_in))
350 return EAI_FAMILY;
351 break;
352 #endif
353 #if HAVE_IPV6
354 case AF_INET6:
355 if (salen < sizeof (struct sockaddr_in6))
356 return EAI_FAMILY;
357 break;
358 #endif
359 default:
360 return EAI_FAMILY;
363 if (node && nodelen > 0 && flags & NI_NUMERICHOST)
365 switch (sa->sa_family)
367 #if HAVE_IPV4
368 case AF_INET:
369 if (!inet_ntop (AF_INET,
370 &(((const struct sockaddr_in *) sa)->sin_addr),
371 node, nodelen))
372 return EAI_SYSTEM;
373 break;
374 #endif
376 #if HAVE_IPV6
377 case AF_INET6:
378 if (!inet_ntop (AF_INET6,
379 &(((const struct sockaddr_in6 *) sa)->sin6_addr),
380 node, nodelen))
381 return EAI_SYSTEM;
382 break;
383 #endif
385 default:
386 return EAI_FAMILY;
390 if (service && servicelen > 0 && flags & NI_NUMERICSERV)
391 switch (sa->sa_family)
393 #if HAVE_IPV4
394 case AF_INET:
395 #endif
396 #if HAVE_IPV6
397 case AF_INET6:
398 #endif
399 if (snprintf (service, servicelen, "%d",
400 ntohs (((const struct sockaddr_in *) sa)->sin_port))
401 + 1 > servicelen)
402 return EAI_OVERFLOW;
403 break;
406 return 0;