1/* -*- buffer-read-only: t -*- vi: set ro: */ 2/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ 3#line 1 4/* Get address information (partial implementation). 5 Copyright (C) 1997, 2001-2002, 2004-2010 Free Software Foundation, Inc. 6 Contributed by Simon Josefsson <simon@josefsson.org>. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3, or (at your option) 11 any later version. 12 13 This program 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 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software Foundation, 20 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 21 22#include <config.h> 23 24/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc 25 optimizes away the sa == NULL test below. */ 26#define _GL_ARG_NONNULL(params) 27 28#include <netdb.h> 29 30#if HAVE_NETINET_IN_H 31# include <netinet/in.h> 32#endif 33 34/* Get inet_ntop. */ 35#include <arpa/inet.h> 36 37/* Get calloc. */ 38#include <stdlib.h> 39 40/* Get memcpy, strdup. */ 41#include <string.h> 42 43/* Get snprintf. */ 44#include <stdio.h> 45 46#include <stdbool.h> 47 48#include "gettext.h" 49#define _(String) gettext (String) 50#define N_(String) String 51 52/* BeOS has AF_INET, but not PF_INET. */ 53#ifndef PF_INET 54# define PF_INET AF_INET 55#endif 56/* BeOS also lacks PF_UNSPEC. */ 57#ifndef PF_UNSPEC 58# define PF_UNSPEC 0 59#endif 60 61#if defined _WIN32 || defined __WIN32__ 62# define WIN32_NATIVE 63#endif 64 65#ifdef WIN32_NATIVE 66typedef int (WSAAPI *getaddrinfo_func) (const char*, const char*, 67 const struct addrinfo*, 68 struct addrinfo**); 69typedef void (WSAAPI *freeaddrinfo_func) (struct addrinfo*); 70typedef int (WSAAPI *getnameinfo_func) (const struct sockaddr*, 71 socklen_t, char*, DWORD, 72 char*, DWORD, int); 73 74static getaddrinfo_func getaddrinfo_ptr = NULL; 75static freeaddrinfo_func freeaddrinfo_ptr = NULL; 76static getnameinfo_func getnameinfo_ptr = NULL; 77 78static int 79use_win32_p (void) 80{ 81 static int done = 0; 82 HMODULE h; 83 84 if (done) 85 return getaddrinfo_ptr ? 1 : 0; 86 87 done = 1; 88 89 h = GetModuleHandle ("ws2_32.dll"); 90 91 if (h) 92 { 93 getaddrinfo_ptr = (getaddrinfo_func) GetProcAddress (h, "getaddrinfo"); 94 freeaddrinfo_ptr = (freeaddrinfo_func) GetProcAddress (h, "freeaddrinfo"); 95 getnameinfo_ptr = (getnameinfo_func) GetProcAddress (h, "getnameinfo"); 96 } 97 98 /* If either is missing, something is odd. */ 99 if (!getaddrinfo_ptr || !freeaddrinfo_ptr || !getnameinfo_ptr) 100 { 101 getaddrinfo_ptr = NULL; 102 freeaddrinfo_ptr = NULL; 103 getnameinfo_ptr = NULL; 104 return 0; 105 } 106 107 return 1; 108} 109#endif 110 111static inline bool 112validate_family (int family) 113{ 114 /* FIXME: Support more families. */ 115#if HAVE_IPV4 116 if (family == PF_INET) 117 return true; 118#endif 119#if HAVE_IPV6 120 if (family == PF_INET6) 121 return true; 122#endif 123 if (family == PF_UNSPEC) 124 return true; 125 return false; 126} 127 128/* Translate name of a service location and/or a service name to set of 129 socket addresses. */ 130int 131getaddrinfo (const char *restrict nodename, 132 const char *restrict servname, 133 const struct addrinfo *restrict hints, 134 struct addrinfo **restrict res) 135{ 136 struct addrinfo *tmp; 137 int port = 0; 138 struct hostent *he; 139 void *storage; 140 size_t size; 141#if HAVE_IPV6 142 struct v6_pair { 143 struct addrinfo addrinfo; 144 struct sockaddr_in6 sockaddr_in6; 145 }; 146#endif 147#if HAVE_IPV4 148 struct v4_pair { 149 struct addrinfo addrinfo; 150 struct sockaddr_in sockaddr_in; 151 }; 152#endif 153 154#ifdef WIN32_NATIVE 155 if (use_win32_p ()) 156 return getaddrinfo_ptr (nodename, servname, hints, res); 157#endif 158 159 if (hints && (hints->ai_flags & ~(AI_CANONNAME|AI_PASSIVE))) 160 /* FIXME: Support more flags. */ 161 return EAI_BADFLAGS; 162 163 if (hints && !validate_family (hints->ai_family)) 164 return EAI_FAMILY; 165 166 if (hints && 167 hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM) 168 /* FIXME: Support other socktype. */ 169 return EAI_SOCKTYPE; /* FIXME: Better return code? */ 170 171 if (!nodename) 172 { 173 if (!(hints->ai_flags & AI_PASSIVE)) 174 return EAI_NONAME; 175 176#ifdef HAVE_IPV6 177 nodename = (hints->ai_family == AF_INET6) ? "::" : "0.0.0.0"; 178#else 179 nodename = "0.0.0.0"; 180#endif 181 } 182 183 if (servname) 184 { 185 struct servent *se = NULL; 186 const char *proto = 187 (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp"; 188 189 if (hints == NULL || !(hints->ai_flags & AI_NUMERICSERV)) 190 /* FIXME: Use getservbyname_r if available. */ 191 se = getservbyname (servname, proto); 192 193 if (!se) 194 { 195 char *c; 196 if (!(*servname >= '0' && *servname <= '9')) 197 return EAI_NONAME; 198 port = strtoul (servname, &c, 10); 199 if (*c || port > 0xffff) 200 return EAI_NONAME; 201 port = htons (port); 202 } 203 else 204 port = se->s_port; 205 } 206 207 /* FIXME: Use gethostbyname_r if available. */ 208 he = gethostbyname (nodename); 209 if (!he || he->h_addr_list[0] == NULL) 210 return EAI_NONAME; 211 212 switch (he->h_addrtype) 213 { 214#if HAVE_IPV6 215 case PF_INET6: 216 size = sizeof (struct v6_pair); 217 break; 218#endif 219 220#if HAVE_IPV4 221 case PF_INET: 222 size = sizeof (struct v4_pair); 223 break; 224#endif 225 226 default: 227 return EAI_NODATA; 228 } 229 230 storage = calloc (1, size); 231 if (!storage) 232 return EAI_MEMORY; 233 234 switch (he->h_addrtype) 235 { 236#if HAVE_IPV6 237 case PF_INET6: 238 { 239 struct v6_pair *p = storage; 240 struct sockaddr_in6 *sinp = &p->sockaddr_in6; 241 tmp = &p->addrinfo; 242 243 if (port) 244 sinp->sin6_port = port; 245 246 if (he->h_length != sizeof (sinp->sin6_addr)) 247 { 248 free (storage); 249 return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */ 250 } 251 252 memcpy (&sinp->sin6_addr, he->h_addr_list[0], sizeof sinp->sin6_addr); 253 254 tmp->ai_addr = (struct sockaddr *) sinp; 255 tmp->ai_addrlen = sizeof *sinp; 256 } 257 break; 258#endif 259 260#if HAVE_IPV4 261 case PF_INET: 262 { 263 struct v4_pair *p = storage; 264 struct sockaddr_in *sinp = &p->sockaddr_in; 265 tmp = &p->addrinfo; 266 267 if (port) 268 sinp->sin_port = port; 269 270 if (he->h_length != sizeof (sinp->sin_addr)) 271 { 272 free (storage); 273 return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */ 274 } 275 276 memcpy (&sinp->sin_addr, he->h_addr_list[0], sizeof sinp->sin_addr); 277 278 tmp->ai_addr = (struct sockaddr *) sinp; 279 tmp->ai_addrlen = sizeof *sinp; 280 } 281 break; 282#endif 283 284 default: 285 free (storage); 286 return EAI_NODATA; 287 } 288 289 if (hints && hints->ai_flags & AI_CANONNAME) 290 { 291 const char *cn; 292 if (he->h_name) 293 cn = he->h_name; 294 else 295 cn = nodename; 296 297 tmp->ai_canonname = strdup (cn); 298 if (!tmp->ai_canonname) 299 { 300 free (storage); 301 return EAI_MEMORY; 302 } 303 } 304 305 tmp->ai_protocol = (hints) ? hints->ai_protocol : 0; 306 tmp->ai_socktype = (hints) ? hints->ai_socktype : 0; 307 tmp->ai_addr->sa_family = he->h_addrtype; 308 tmp->ai_family = he->h_addrtype; 309 310#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 311 switch (he->h_addrtype) 312 { 313#if HAVE_IPV4 314 case AF_INET: 315 tmp->ai_addr->sa_len = sizeof (struct sockaddr_in); 316 break; 317#endif 318#if HAVE_IPV6 319 case AF_INET6: 320 tmp->ai_addr->sa_len = sizeof (struct sockaddr_in6); 321 break; 322#endif 323 } 324#endif 325 326 /* FIXME: If more than one address, create linked list of addrinfo's. */ 327 328 *res = tmp; 329 330 return 0; 331} 332 333/* Free `addrinfo' structure AI including associated storage. */ 334void 335freeaddrinfo (struct addrinfo *ai) 336{ 337#ifdef WIN32_NATIVE 338 if (use_win32_p ()) 339 { 340 freeaddrinfo_ptr (ai); 341 return; 342 } 343#endif 344 345 while (ai) 346 { 347 struct addrinfo *cur; 348 349 cur = ai; 350 ai = ai->ai_next; 351 352 free (cur->ai_canonname); 353 free (cur); 354 } 355} 356 357int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, 358 char *restrict node, socklen_t nodelen, 359 char *restrict service, socklen_t servicelen, 360 int flags) 361{ 362#ifdef WIN32_NATIVE 363 if (use_win32_p ()) 364 return getnameinfo_ptr (sa, salen, node, nodelen, 365 service, servicelen, flags); 366#endif 367 368 /* FIXME: Support other flags. */ 369 if ((node && nodelen > 0 && !(flags & NI_NUMERICHOST)) || 370 (service && servicelen > 0 && !(flags & NI_NUMERICHOST)) || 371 (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV))) 372 return EAI_BADFLAGS; 373 374 if (sa == NULL || salen < sizeof (sa->sa_family)) 375 return EAI_FAMILY; 376 377 switch (sa->sa_family) 378 { 379#if HAVE_IPV4 380 case AF_INET: 381 if (salen < sizeof (struct sockaddr_in)) 382 return EAI_FAMILY; 383 break; 384#endif 385#if HAVE_IPV6 386 case AF_INET6: 387 if (salen < sizeof (struct sockaddr_in6)) 388 return EAI_FAMILY; 389 break; 390#endif 391 default: 392 return EAI_FAMILY; 393 } 394 395 if (node && nodelen > 0 && flags & NI_NUMERICHOST) 396 { 397 switch (sa->sa_family) 398 { 399#if HAVE_IPV4 400 case AF_INET: 401 if (!inet_ntop (AF_INET, 402 &(((const struct sockaddr_in *) sa)->sin_addr), 403 node, nodelen)) 404 return EAI_SYSTEM; 405 break; 406#endif 407 408#if HAVE_IPV6 409 case AF_INET6: 410 if (!inet_ntop (AF_INET6, 411 &(((const struct sockaddr_in6 *) sa)->sin6_addr), 412 node, nodelen)) 413 return EAI_SYSTEM; 414 break; 415#endif 416 417 default: 418 return EAI_FAMILY; 419 } 420 } 421 422 if (service && servicelen > 0 && flags & NI_NUMERICSERV) 423 switch (sa->sa_family) 424 { 425#if HAVE_IPV4 426 case AF_INET: 427#endif 428#if HAVE_IPV6 429 case AF_INET6: 430#endif 431 { 432 unsigned short int port 433 = ntohs (((const struct sockaddr_in *) sa)->sin_port); 434 if (servicelen <= snprintf (service, servicelen, "%u", port)) 435 return EAI_OVERFLOW; 436 } 437 break; 438 } 439 440 return 0; 441} 442