upstream removed this so we don't need to
[debian/amanda] / gnulib / getaddrinfo.c
index 1b6100d90ec5a0bb6ba4563d06a47dc7748e8d0f..6aa676c89ce4e13030da78867c22ba8d30203392 100644 (file)
@@ -1,11 +1,10 @@
 /* Get address information (partial implementation).
 /* Get address information (partial implementation).
-   Copyright (C) 1997, 2001, 2002, 2004, 2005, 2006, 2007 Free Software
-   Foundation, Inc.
+   Copyright (C) 1997, 2001-2002, 2004-2010 Free Software Foundation, Inc.
    Contributed by Simon Josefsson <simon@josefsson.org>.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    Contributed by Simon Josefsson <simon@josefsson.org>.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    This program is distributed in the hope that it will be useful,
    any later version.
 
    This program is distributed in the hope that it will be useful,
 
 #include <config.h>
 
 
 #include <config.h>
 
-#include "getaddrinfo.h"
+/* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
+   optimizes away the sa == NULL test below.  */
+#define _GL_ARG_NONNULL(params)
+
+#include <netdb.h>
 
 #if HAVE_NETINET_IN_H
 # include <netinet/in.h>
 #endif
 
 
 #if HAVE_NETINET_IN_H
 # include <netinet/in.h>
 #endif
 
+/* Get inet_ntop.  */
+#include <arpa/inet.h>
+
 /* Get calloc. */
 #include <stdlib.h>
 
 /* Get memcpy, strdup. */
 #include <string.h>
 
 /* Get calloc. */
 #include <stdlib.h>
 
 /* Get memcpy, strdup. */
 #include <string.h>
 
+/* Get snprintf. */
+#include <stdio.h>
+
 #include <stdbool.h>
 
 #include "gettext.h"
 #define _(String) gettext (String)
 #define N_(String) String
 
 #include <stdbool.h>
 
 #include "gettext.h"
 #define _(String) gettext (String)
 #define N_(String) String
 
-#include "inet_ntop.h"
-#include "snprintf.h"
-
-extern int h_errno;
-
 /* BeOS has AF_INET, but not PF_INET.  */
 #ifndef PF_INET
 # define PF_INET AF_INET
 /* BeOS has AF_INET, but not PF_INET.  */
 #ifndef PF_INET
 # define PF_INET AF_INET
@@ -57,12 +61,12 @@ extern int h_errno;
 
 #ifdef WIN32_NATIVE
 typedef int (WSAAPI *getaddrinfo_func) (const char*, const char*,
 
 #ifdef WIN32_NATIVE
 typedef int (WSAAPI *getaddrinfo_func) (const char*, const char*,
-                                       const struct addrinfo*,
-                                       struct addrinfo**);
+                                        const struct addrinfo*,
+                                        struct addrinfo**);
 typedef void (WSAAPI *freeaddrinfo_func) (struct addrinfo*);
 typedef int (WSAAPI *getnameinfo_func) (const struct sockaddr*,
 typedef void (WSAAPI *freeaddrinfo_func) (struct addrinfo*);
 typedef int (WSAAPI *getnameinfo_func) (const struct sockaddr*,
-                                       socklen_t, char*, DWORD,
-                                       char*, DWORD, int);
+                                        socklen_t, char*, DWORD,
+                                        char*, DWORD, int);
 
 static getaddrinfo_func getaddrinfo_ptr = NULL;
 static freeaddrinfo_func freeaddrinfo_ptr = NULL;
 
 static getaddrinfo_func getaddrinfo_ptr = NULL;
 static freeaddrinfo_func freeaddrinfo_ptr = NULL;
@@ -122,9 +126,9 @@ validate_family (int family)
    socket addresses. */
 int
 getaddrinfo (const char *restrict nodename,
    socket addresses. */
 int
 getaddrinfo (const char *restrict nodename,
-            const char *restrict servname,
-            const struct addrinfo *restrict hints,
-            struct addrinfo **restrict res)
+             const char *restrict servname,
+             const struct addrinfo *restrict hints,
+             struct addrinfo **restrict res)
 {
   struct addrinfo *tmp;
   int port = 0;
 {
   struct addrinfo *tmp;
   int port = 0;
@@ -149,29 +153,25 @@ getaddrinfo (const char *restrict nodename,
     return getaddrinfo_ptr (nodename, servname, hints, res);
 #endif
 
     return getaddrinfo_ptr (nodename, servname, hints, res);
 #endif
 
-  if (hints && (hints->ai_flags & ~(AI_CANONNAME | AI_PASSIVE)))
+  if (hints && (hints->ai_flags & ~(AI_CANONNAME|AI_PASSIVE)))
     /* FIXME: Support more flags. */
     return EAI_BADFLAGS;
 
   if (hints && !validate_family (hints->ai_family))
     return EAI_FAMILY;
 
     /* FIXME: Support more flags. */
     return EAI_BADFLAGS;
 
   if (hints && !validate_family (hints->ai_family))
     return EAI_FAMILY;
 
-  if ((hints != NULL) &&
-      (hints->ai_socktype != 0) &&
-      (hints->ai_socktype != SOCK_STREAM) &&
-      (hints->ai_socktype != SOCK_DGRAM))
-    {
-      /* FIXME: Support other socktype. */
-      return EAI_SOCKTYPE; /* FIXME: Better return code? */
-    }
+  if (hints &&
+      hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM)
+    /* FIXME: Support other socktype. */
+    return EAI_SOCKTYPE; /* FIXME: Better return code? */
 
   if (!nodename)
     {
 
   if (!nodename)
     {
-      if (hints && !(hints->ai_flags & AI_PASSIVE))
-       return EAI_NONAME;
+      if (!(hints->ai_flags & AI_PASSIVE))
+        return EAI_NONAME;
 
 #ifdef HAVE_IPV6
 
 #ifdef HAVE_IPV6
-      nodename = (hints && (hints->ai_family == AF_INET6)) ? "::" : "0.0.0.0";
+      nodename = (hints->ai_family == AF_INET6) ? "::" : "0.0.0.0";
 #else
       nodename = "0.0.0.0";
 #endif
 #else
       nodename = "0.0.0.0";
 #endif
@@ -181,30 +181,28 @@ getaddrinfo (const char *restrict nodename,
     {
       struct servent *se = NULL;
       const char *proto =
     {
       struct servent *se = NULL;
       const char *proto =
-       (hints && (hints->ai_socktype == SOCK_DGRAM)) ? "udp" : "tcp";
+        (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
 
 
-      if ((hints == NULL) || !(hints->ai_flags & AI_NUMERICSERV))
-        {
-         /* FIXME: Use getservbyname_r if available. */
-         se = getservbyname (servname, proto);
-        }
+      if (hints == NULL || !(hints->ai_flags & AI_NUMERICSERV))
+        /* FIXME: Use getservbyname_r if available. */
+        se = getservbyname (servname, proto);
 
       if (!se)
 
       if (!se)
-       {
-         char *c;
-         if (!(*servname >= '0' && *servname <= '9'))
-           return EAI_NONAME;
-         port = strtoul (servname, &c, 10);
-         if (*c || port > 0xffff)
-           return EAI_NONAME;
-         port = htons (port);
-       }
+        {
+          char *c;
+          if (!(*servname >= '0' && *servname <= '9'))
+            return EAI_NONAME;
+          port = strtoul (servname, &c, 10);
+          if (*c || port > 0xffff)
+            return EAI_NONAME;
+          port = htons (port);
+        }
       else
       else
-       port = se->s_port;
+        port = se->s_port;
     }
 
   /* FIXME: Use gethostbyname_r if available. */
     }
 
   /* FIXME: Use gethostbyname_r if available. */
-  he = gethostbyname(nodename);
+  he = gethostbyname (nodename);
   if (!he || he->h_addr_list[0] == NULL)
     return EAI_NONAME;
 
   if (!he || he->h_addr_list[0] == NULL)
     return EAI_NONAME;
 
@@ -235,23 +233,23 @@ getaddrinfo (const char *restrict nodename,
 #if HAVE_IPV6
     case PF_INET6:
       {
 #if HAVE_IPV6
     case PF_INET6:
       {
-       struct v6_pair *p = storage;
-       struct sockaddr_in6 *sinp = &p->sockaddr_in6;
-       tmp = &p->addrinfo;
+        struct v6_pair *p = storage;
+        struct sockaddr_in6 *sinp = &p->sockaddr_in6;
+        tmp = &p->addrinfo;
 
 
-       if (port)
-         sinp->sin6_port = port;
+        if (port)
+          sinp->sin6_port = port;
 
 
-       if (he->h_length != sizeof (sinp->sin6_addr))
-         {
-           free (storage);
-           return EAI_SYSTEM; /* FIXME: Better return code?  Set errno? */
-         }
+        if (he->h_length != sizeof (sinp->sin6_addr))
+          {
+            free (storage);
+            return EAI_SYSTEM; /* FIXME: Better return code?  Set errno? */
+          }
 
 
-       memcpy (&sinp->sin6_addr, he->h_addr_list[0], sizeof sinp->sin6_addr);
+        memcpy (&sinp->sin6_addr, he->h_addr_list[0], sizeof sinp->sin6_addr);
 
 
-       tmp->ai_addr = (struct sockaddr *) sinp;
-       tmp->ai_addrlen = sizeof *sinp;
+        tmp->ai_addr = (struct sockaddr *) sinp;
+        tmp->ai_addrlen = sizeof *sinp;
       }
       break;
 #endif
       }
       break;
 #endif
@@ -259,23 +257,23 @@ getaddrinfo (const char *restrict nodename,
 #if HAVE_IPV4
     case PF_INET:
       {
 #if HAVE_IPV4
     case PF_INET:
       {
-       struct v4_pair *p = storage;
-       struct sockaddr_in *sinp = &p->sockaddr_in;
-       tmp = &p->addrinfo;
+        struct v4_pair *p = storage;
+        struct sockaddr_in *sinp = &p->sockaddr_in;
+        tmp = &p->addrinfo;
 
 
-       if (port)
-         sinp->sin_port = port;
+        if (port)
+          sinp->sin_port = port;
 
 
-       if (he->h_length != sizeof (sinp->sin_addr))
-         {
-           free (storage);
-           return EAI_SYSTEM; /* FIXME: Better return code?  Set errno? */
-         }
+        if (he->h_length != sizeof (sinp->sin_addr))
+          {
+            free (storage);
+            return EAI_SYSTEM; /* FIXME: Better return code?  Set errno? */
+          }
 
 
-       memcpy (&sinp->sin_addr, he->h_addr_list[0], sizeof sinp->sin_addr);
+        memcpy (&sinp->sin_addr, he->h_addr_list[0], sizeof sinp->sin_addr);
 
 
-       tmp->ai_addr = (struct sockaddr *) sinp;
-       tmp->ai_addrlen = sizeof *sinp;
+        tmp->ai_addr = (struct sockaddr *) sinp;
+        tmp->ai_addrlen = sizeof *sinp;
       }
       break;
 #endif
       }
       break;
 #endif
@@ -285,20 +283,20 @@ getaddrinfo (const char *restrict nodename,
       return EAI_NODATA;
     }
 
       return EAI_NODATA;
     }
 
-  if (hints && (hints->ai_flags & AI_CANONNAME))
+  if (hints && hints->ai_flags & AI_CANONNAME)
     {
       const char *cn;
       if (he->h_name)
     {
       const char *cn;
       if (he->h_name)
-       cn = he->h_name;
+        cn = he->h_name;
       else
       else
-       cn = nodename;
+        cn = nodename;
 
       tmp->ai_canonname = strdup (cn);
       if (!tmp->ai_canonname)
 
       tmp->ai_canonname = strdup (cn);
       if (!tmp->ai_canonname)
-       {
-         free (storage);
-         return EAI_MEMORY;
-       }
+        {
+          free (storage);
+          return EAI_MEMORY;
+        }
     }
 
   tmp->ai_protocol = (hints) ? hints->ai_protocol : 0;
     }
 
   tmp->ai_protocol = (hints) ? hints->ai_protocol : 0;
@@ -306,6 +304,22 @@ getaddrinfo (const char *restrict nodename,
   tmp->ai_addr->sa_family = he->h_addrtype;
   tmp->ai_family = he->h_addrtype;
 
   tmp->ai_addr->sa_family = he->h_addrtype;
   tmp->ai_family = he->h_addrtype;
 
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+  switch (he->h_addrtype)
+    {
+#if HAVE_IPV4
+    case AF_INET:
+      tmp->ai_addr->sa_len = sizeof (struct sockaddr_in);
+      break;
+#endif
+#if HAVE_IPV6
+    case AF_INET6:
+      tmp->ai_addr->sa_len = sizeof (struct sockaddr_in6);
+      break;
+#endif
+    }
+#endif
+
   /* FIXME: If more than one address, create linked list of addrinfo's. */
 
   *res = tmp;
   /* FIXME: If more than one address, create linked list of addrinfo's. */
 
   *res = tmp;
@@ -332,24 +346,27 @@ freeaddrinfo (struct addrinfo *ai)
       cur = ai;
       ai = ai->ai_next;
 
       cur = ai;
       ai = ai->ai_next;
 
-      if (cur->ai_canonname) free (cur->ai_canonname);
+      free (cur->ai_canonname);
       free (cur);
     }
 }
 
       free (cur);
     }
 }
 
-int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
-               char *restrict node, socklen_t nodelen,
-               char *restrict service, socklen_t servicelen,
-               int flags)
+int
+getnameinfo (const struct sockaddr *restrict sa, socklen_t salen,
+             char *restrict node, socklen_t nodelen,
+             char *restrict service, socklen_t servicelen,
+             int flags)
 {
 #ifdef WIN32_NATIVE
   if (use_win32_p ())
     return getnameinfo_ptr (sa, salen, node, nodelen,
 {
 #ifdef WIN32_NATIVE
   if (use_win32_p ())
     return getnameinfo_ptr (sa, salen, node, nodelen,
-                           service, servicelen, flags);
+                            service, servicelen, flags);
 #endif
 
   /* FIXME: Support other flags. */
 #endif
 
   /* FIXME: Support other flags. */
-  if (flags & ~(NI_NUMERICHOST | NI_NUMERICSERV))
+  if ((node && nodelen > 0 && !(flags & NI_NUMERICHOST)) ||
+      (service && servicelen > 0 && !(flags & NI_NUMERICHOST)) ||
+      (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV)))
     return EAI_BADFLAGS;
 
   if (sa == NULL || salen < sizeof (sa->sa_family))
     return EAI_BADFLAGS;
 
   if (sa == NULL || salen < sizeof (sa->sa_family))
@@ -360,102 +377,47 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
 #if HAVE_IPV4
     case AF_INET:
       if (salen < sizeof (struct sockaddr_in))
 #if HAVE_IPV4
     case AF_INET:
       if (salen < sizeof (struct sockaddr_in))
-       return EAI_FAMILY;
+        return EAI_FAMILY;
       break;
 #endif
 #if HAVE_IPV6
     case AF_INET6:
       if (salen < sizeof (struct sockaddr_in6))
       break;
 #endif
 #if HAVE_IPV6
     case AF_INET6:
       if (salen < sizeof (struct sockaddr_in6))
-       return EAI_FAMILY;
+        return EAI_FAMILY;
       break;
 #endif
     default:
       return EAI_FAMILY;
     }
 
       break;
 #endif
     default:
       return EAI_FAMILY;
     }
 
-  if (node && (nodelen > 0))
+  if (node && nodelen > 0 && flags & NI_NUMERICHOST)
     {
     {
-      char     addrbuf[256];
-
       switch (sa->sa_family)
       switch (sa->sa_family)
-       {
+        {
 #if HAVE_IPV4
 #if HAVE_IPV4
-       case AF_INET:
-         if (flags & NI_NUMERICHOST)
-           {
-             if (!inet_ntop (AF_INET,
-                         &(((const struct sockaddr_in *) sa)->sin_addr),
-                         addrbuf, sizeof(addrbuf)))
-             return EAI_SYSTEM;
-           }
-         else
-           {
-             struct hostent *host_ent = gethostbyaddr(
-                         (char *)&(((struct sockaddr_in *)sa)->sin_addr),
-                         sizeof(struct sockaddr_in),
-                         sa->sa_family);
-             if (host_ent != NULL)
-               {
-                 if (nodelen <= snprintf(node, nodelen, "%s",
-                                       host_ent->h_name))
-                    return EAI_OVERFLOW;
-               }
-             else
-               {
-                 if (!inet_ntop (AF_INET,
-                         &(((const struct sockaddr_in *) sa)->sin_addr),
-                         addrbuf, sizeof(addrbuf)))
-                   { 
-                     return EAI_SYSTEM;
-                   }
-                   if (nodelen <= snprintf(node, nodelen, "%s", addrbuf))
-                     return EAI_OVERFLOW;
-               }
-           }
-         break;
+        case AF_INET:
+          if (!inet_ntop (AF_INET,
+                          &(((const struct sockaddr_in *) sa)->sin_addr),
+                          node, nodelen))
+            return EAI_SYSTEM;
+          break;
 #endif
 
 #if HAVE_IPV6
 #endif
 
 #if HAVE_IPV6
-       case AF_INET6:
-         if (flags & NI_NUMERICHOST)
-           {
-             if (!inet_ntop (AF_INET6,
-                         &(((const struct sockaddr_in6 *) sa)->sin6_addr),
-                         addrbuf, sizeof(addrbuf)))
-             return EAI_SYSTEM;
-           }
-         else
-           {
-             struct hostent *host_ent = gethostbyaddr(
-                         (char *)&(((struct sockaddr_in6 *)sa)->sin6_addr),
-                         sizeof(struct sockaddr_in6),
-                         sa->sa_family);
-             if (host_ent != NULL)
-               {
-                 if (nodelen <= snprintf(node, nodelen, "%s",
-                                       host_ent->h_name))
-                    return EAI_OVERFLOW;
-               }
-             else
-               {
-                 if (!inet_ntop (AF_INET6,
-                         &(((const struct sockaddr_in6 *) sa)->sin6_addr),
-                         addrbuf, sizeof(addrbuf)))
-                   { 
-                     return EAI_SYSTEM;
-                   }
-                   if (nodelen <= snprintf(node, nodelen, "%s", addrbuf))
-                     return EAI_OVERFLOW;
-               }
-           }
-         break;
+        case AF_INET6:
+          if (!inet_ntop (AF_INET6,
+                          &(((const struct sockaddr_in6 *) sa)->sin6_addr),
+                          node, nodelen))
+            return EAI_SYSTEM;
+          break;
 #endif
 #endif
-       default:
-         return EAI_FAMILY;
-       }
+
+        default:
+          return EAI_FAMILY;
+        }
     }
 
     }
 
-  if (service && (servicelen > 0))
+  if (service && servicelen > 0 && flags & NI_NUMERICSERV)
     switch (sa->sa_family)
       {
 #if HAVE_IPV4
     switch (sa->sa_family)
       {
 #if HAVE_IPV4
@@ -464,13 +426,13 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
 #if HAVE_IPV6
       case AF_INET6:
 #endif
 #if HAVE_IPV6
       case AF_INET6:
 #endif
-       {
-         unsigned short int port
-           = ntohs (((const struct sockaddr_in *) sa)->sin_port);
-         if (servicelen <= snprintf (service, servicelen, "%u", port))
-           return EAI_OVERFLOW;
-       }
-       break;
+        {
+          unsigned short int port
+            = ntohs (((const struct sockaddr_in *) sa)->sin_port);
+          if (servicelen <= snprintf (service, servicelen, "%u", port))
+            return EAI_OVERFLOW;
+        }
+        break;
       }
 
   return 0;
       }
 
   return 0;