root/maint/gnulib/lib/getaddrinfo.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. getaddrinfo
  2. freeaddrinfo
  3. use_win32_p
  4. use_win32_p
  5. validate_family
  6. getaddrinfo
  7. freeaddrinfo
  8. getnameinfo

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

/* [previous][next][first][last][top][bottom][index][help] */