bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

getaddrinfo: native win32 support, getnameinfo support


From: Simon Josefsson
Subject: getaddrinfo: native win32 support, getnameinfo support
Date: Wed, 28 Jun 2006 13:08:51 +0200
User-agent: Gnus/5.110006 (No Gnus v0.6) Emacs/22.0.50 (gnu/linux)

Hi!  Some getaddrinfo improvements.  See the ChangeLog entry for the
details.  I've installed this.

/Simon

Index: lib/ChangeLog
===================================================================
RCS file: /sources/gnulib/gnulib/lib/ChangeLog,v
retrieving revision 1.1170
diff -u -p -r1.1170 ChangeLog
--- lib/ChangeLog       27 Jun 2006 13:15:26 -0000      1.1170
+++ lib/ChangeLog       28 Jun 2006 11:07:26 -0000
@@ -1,3 +1,19 @@
+2006-06-28  Simon Josefsson  <address@hidden>
+
+       * getaddrinfo.c: Try to load ws2_32.dll on Windows, to find the
+       functions there.  It will succeed on Windows XP, but on Windows
+       2000 and (presumably) earlier, it will fail, and use the internal
+       re-implementation.
+       (use_win32_p): New function.
+       (getaddrinfo): Use strtoul on servname, to support numeric ports.
+       Support AI_NUMERICSERV to disable getservbyname.
+       (getnameinfo): New function, only supports
+       NI_NUMERICHOST|NI_NUMERICSERV for now.
+
+       * getaddrinfo.h: Test and check for AI_* flags separately, MinGW
+       only have some of them.  Add AI_NUMERICSERV.  Add prototype for
+       getnameinfo.
+
 2006-06-27  Bruno Haible  <address@hidden>
 
        * stdlib_.h (intmax_t, uintmax_t): Undefine before typedef.
Index: lib/getaddrinfo.c
===================================================================
RCS file: /sources/gnulib/gnulib/lib/getaddrinfo.c,v
retrieving revision 1.8
diff -u -p -r1.8 getaddrinfo.c
--- lib/getaddrinfo.c   21 Jun 2006 17:22:32 -0000      1.8
+++ lib/getaddrinfo.c   28 Jun 2006 11:07:26 -0000
@@ -1,5 +1,5 @@
 /* Get address information (partial implementation).
-   Copyright (C) 1997, 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1997, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, 
Inc.
    Contributed by Simon Josefsson <address@hidden>.
 
    This program is free software; you can redistribute it and/or modify
@@ -40,6 +40,51 @@
 
 #include "strdup.h"
 
+#ifdef _WIN32
+typedef void WSAAPI (*freeaddrinfo_func) (struct addrinfo*);
+typedef int WSAAPI (*getaddrinfo_func) (const char*, const char*,
+                                       const struct addrinfo*,
+                                       struct addrinfo**);
+typedef int WSAAPI (*getnameinfo_func) (const struct sockaddr*,
+                                       socklen_t, char*, DWORD,
+                                       char*, DWORD, int);
+
+static getaddrinfo_func getaddrinfo_ptr = NULL;
+static freeaddrinfo_func freeaddrinfo_ptr = NULL;
+static getnameinfo_func getnameinfo_ptr = NULL;
+
+int use_win32_p (void)
+{
+  static int done = 0;
+  HMODULE h;
+
+  if (done)
+    return getaddrinfo_ptr ? 1 : 0;
+
+  done = 1;
+
+  h = GetModuleHandle ("ws2_32.dll");
+
+  if (h)
+    {
+      getaddrinfo_ptr = GetProcAddress (h, "getaddrinfo");
+      freeaddrinfo_ptr = GetProcAddress (h, "freeaddrinfo");
+      getnameinfo_ptr = GetProcAddress (h, "getnameinfo");
+    }
+
+  /* If either is missing, something is odd. */
+  if (!getaddrinfo_ptr || !freeaddrinfo_ptr || !getnameinfo_ptr)
+    {
+      getaddrinfo_ptr = NULL;
+      freeaddrinfo_ptr = NULL;
+      getnameinfo_ptr = NULL;
+      return 0;
+    }
+
+  return 1;
+}
+#endif
+
 static inline bool
 validate_family (int family)
 {
@@ -66,7 +111,7 @@ getaddrinfo (const char *restrict nodena
             struct addrinfo **restrict res)
 {
   struct addrinfo *tmp;
-  struct servent *se = NULL;
+  int port = 0;
   struct hostent *he;
   void *storage;
   size_t size;
@@ -83,6 +128,11 @@ getaddrinfo (const char *restrict nodena
   };
 #endif
 
+#ifdef _WIN32
+  if (use_win32_p ())
+    return getaddrinfo_ptr (nodename, servname, hints, res);
+#endif
+
   if (hints && (hints->ai_flags & ~AI_CANONNAME))
     /* FIXME: Support more flags. */
     return EAI_BADFLAGS;
@@ -101,14 +151,24 @@ getaddrinfo (const char *restrict nodena
 
   if (servname)
     {
+      struct servent *se = NULL;
       const char *proto =
        (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
 
-      /* FIXME: Use getservbyname_r if available. */
-      se = getservbyname (servname, proto);
+      if (!(hints->ai_flags & AI_NUMERICSERV))
+       /* FIXME: Use getservbyname_r if available. */
+       se = getservbyname (servname, proto);
 
       if (!se)
-       return EAI_SERVICE;
+       {
+         char *c;
+         port = strtoul (servname, &c, 10);
+         if (*c)
+           return EAI_NONAME;
+         port = htons (port);
+       }
+      else
+       port = se->s_port;
     }
 
   /* FIXME: Use gethostbyname_r if available. */
@@ -147,8 +207,8 @@ getaddrinfo (const char *restrict nodena
        struct sockaddr_in6 *sinp = &p->sockaddr_in6;
        tmp = &p->addrinfo;
 
-       if (se)
-         sinp->sin6_port = se->s_port;
+       if (port)
+         sinp->sin6_port = port;
 
        if (he->h_length != sizeof (sinp->sin6_addr))
          {
@@ -171,8 +231,8 @@ getaddrinfo (const char *restrict nodena
        struct sockaddr_in *sinp = &p->sockaddr_in;
        tmp = &p->addrinfo;
 
-       if (se)
-         sinp->sin_port = se->s_port;
+       if (port)
+         sinp->sin_port = port;
 
        if (he->h_length != sizeof (sinp->sin_addr))
          {
@@ -225,6 +285,11 @@ getaddrinfo (const char *restrict nodena
 void
 freeaddrinfo (struct addrinfo *ai)
 {
+#ifdef _WIN32
+  if (use_win32_p ())
+    return freeaddrinfo_ptr (ai);
+#endif
+
   while (ai)
     {
       struct addrinfo *cur;
@@ -236,3 +301,89 @@ freeaddrinfo (struct addrinfo *ai)
       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)
+{
+#if _WIN32
+  if (use_win32_p ())
+    return getnameinfo_ptr (sa, salen, node, nodelen,
+                           service, servicelen, flags);
+#endif
+
+  /* FIXME: Support other flags. */
+  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_FAMILY;
+
+  switch (sa->sa_family)
+    {
+#if HAVE_IPV4
+    case AF_INET:
+      if (salen < sizeof (struct sockaddr_in))
+       return EAI_FAMILY;
+      break;
+#endif
+#if HAVE_IPV6
+    case AF_INET6:
+      if (salen < sizeof (struct sockaddr_in6))
+       return EAI_FAMILY;
+      break;
+#endif
+    default:
+      return EAI_FAMILY;
+    }
+
+  if (node && nodelen > 0 && flags & NI_NUMERICHOST)
+    {
+      switch (sa->sa_family)
+       {
+#if HAVE_IPV4
+       case AF_INET:
+         if (!inet_ntop (AF_INET,
+                         (const void *)
+                         &(((const struct sockaddr_in *) sa)->sin_addr),
+                         node, nodelen))
+           return EAI_SYSTEM;
+         break;
+#endif
+
+#if HAVE_IPV6
+       case AF_INET6:
+         if (!inet_ntop (AF_INET6,
+                         (const void *)
+                         &(((const struct sockaddr_in6 *) sa)->sin6_addr),
+                         node, nodelen))
+           return EAI_SYSTEM;
+         break;
+#endif
+
+       default:
+         return EAI_FAMILY;
+       }
+    }
+
+  if (service && servicelen > 0 && flags & NI_NUMERICSERV)
+    switch (sa->sa_family)
+      {
+#if HAVE_IPV4
+      case AF_INET:
+#endif
+#if HAVE_IPV6
+      case AF_INET6:
+#endif
+       if (snprintf (service, servicelen, "%d",
+                     ntohs (((const struct sockaddr_in *) sa)->sin_port))
+           + 1 > servicelen)
+         return EAI_OVERFLOW;
+       break;
+      }
+
+  return 0;
+}
Index: lib/getaddrinfo.h
===================================================================
RCS file: /sources/gnulib/gnulib/lib/getaddrinfo.h,v
retrieving revision 1.12
diff -u -p -r1.12 getaddrinfo.h
--- lib/getaddrinfo.h   27 Jan 2006 12:50:41 -0000      1.12
+++ lib/getaddrinfo.h   28 Jun 2006 11:07:26 -0000
@@ -48,13 +48,26 @@ struct addrinfo
 
 /* Possible values for `ai_flags' field in `addrinfo' structure.  */
 # ifndef AI_PASSIVE
-#  define AI_PASSIVE   0x0001  /* Socket address is intended for `bind'.  */
-#  define AI_CANONNAME 0x0002  /* Request for canonical name.  */
+#  define AI_PASSIVE    0x0001 /* Socket address is intended for `bind'.  */
+# endif
+# ifndef AI_CANONNAME
+#  define AI_CANONNAME  0x0002 /* Request for canonical name.  */
+# endif
+# ifndef AI_NUMERICHOST
 #  define AI_NUMERICHOST 0x0004        /* Don't use name resolution.  */
-#  define AI_V4MAPPED  0x0008  /* IPv4 mapped addresses are acceptable.  */
-#  define AI_ALL       0x0010  /* Return IPv4 mapped and IPv6 addresses.  */
-#  define AI_ADDRCONFIG        0x0020  /* Use configuration of this host to 
choose
+# endif
+# ifndef AI_V4MAPPED
+#  define AI_V4MAPPED   0x0008 /* IPv4 mapped addresses are acceptable.  */
+# endif
+# ifndef AI_ALL
+#  define AI_ALL        0x0010 /* Return IPv4 mapped and IPv6 addresses.  */
+# endif
+# ifndef AI_ADDRCONFIG
+#  define AI_ADDRCONFIG         0x0020 /* Use configuration of this host to 
choose
                                   returned address type..  */
+#endif
+#ifndef AI_NUMERICSERV
+#  define AI_NUMERICSERV 0x0400        /* Don't use name resolution.  */
 # endif
 
 /* Error values for `getaddrinfo' function.  */
@@ -68,16 +81,17 @@ struct addrinfo
 #  define EAI_SOCKTYPE   -7    /* `ai_socktype' not supported.  */
 #  define EAI_SERVICE    -8    /* SERVICE not supported for `ai_socktype'.  */
 #  define EAI_MEMORY     -10   /* Memory allocation failure.  */
+#endif
+#ifndef EAI_OVERFLOW
+/* Not defined on mingw32. */
 #  define EAI_OVERFLOW   -12   /* Argument buffer overflow.  */
 #endif
 # ifndef EAI_ADDRFAMILY
-/* Not defined on mingw32.  XXX May be incorrect? Perhaps it is never
-   returned? */
+/* Not defined on mingw32. */
 #  define EAI_ADDRFAMILY  -9   /* Address family for NAME not supported.  */
 # endif
 # ifndef EAI_SYSTEM
-/* Not defined on mingw32.  XXX May be incorrect? Perhaps it is never
-   returned? */
+/* Not defined on mingw32. */
 #  define EAI_SYSTEM     -11   /* System error returned in `errno'.  */
 # endif
 
@@ -117,4 +131,15 @@ extern void freeaddrinfo (struct addrinf
 extern const char *gai_strerror (int ecode);
 # endif
 
+# if !HAVE_DECL_GETNAMEINFO
+/* Convert socket address to printable node and service names.
+   For more details, see the POSIX:2001 specification
+   <http://www.opengroup.org/susv3xsh/gai_strerror.html>.  */
+extern int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
+                      char *restrict node, socklen_t nodelen,
+                      char *restrict service, socklen_t servicelen,
+                      int flags);
+
+# endif
+
 #endif /* GETADDRINFO_H */
Index: m4/ChangeLog
===================================================================
RCS file: /sources/gnulib/gnulib/m4/ChangeLog,v
retrieving revision 1.838
diff -u -p -r1.838 ChangeLog
--- m4/ChangeLog        27 Jun 2006 21:21:13 -0000      1.838
+++ m4/ChangeLog        28 Jun 2006 11:07:26 -0000
@@ -1,3 +1,7 @@
+2006-06-28  Simon Josefsson  <address@hidden>
+
+       * getaddrinfo.m4: Look for getnameinfo prototypes too.
+
 2006-06-27  Simon Josefsson  <address@hidden>
 
        * sys_select_h.m4: New file, suggested by Paul Eggert and Martin
Index: m4/getaddrinfo.m4
===================================================================
RCS file: /sources/gnulib/gnulib/m4/getaddrinfo.m4,v
retrieving revision 1.16
diff -u -p -r1.16 getaddrinfo.m4
--- m4/getaddrinfo.m4   21 Jun 2006 17:22:32 -0000      1.16
+++ m4/getaddrinfo.m4   28 Jun 2006 11:07:26 -0000
@@ -1,4 +1,4 @@
-# getaddrinfo.m4 serial 9
+# getaddrinfo.m4 serial 10
 dnl Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -6,7 +6,7 @@ dnl with or without modifications, as lo
 
 AC_DEFUN([gl_GETADDRINFO],
 [
-  AC_MSG_NOTICE([checking how to do getaddrinfo])
+  AC_MSG_NOTICE([checking how to do getaddrinfo, freeaddrinfo and getnameinfo])
 
   AC_SEARCH_LIBS(getaddrinfo, [nsl socket])
   AC_CHECK_FUNCS(getaddrinfo,, [
@@ -58,7 +58,7 @@ AC_DEFUN([gl_PREREQ_GETADDRINFO], [
   AC_REQUIRE([AC_C_INLINE])
   AC_REQUIRE([AC_GNU_SOURCE])
   AC_CHECK_HEADERS_ONCE(netinet/in.h netdb.h)
-  AC_CHECK_DECLS([getaddrinfo, freeaddrinfo, gai_strerror],,,[
+  AC_CHECK_DECLS([getaddrinfo, freeaddrinfo, gai_strerror, getnameinfo],,,[
   /* sys/types.h is not needed according to POSIX, but the
      sys/socket.h in i386-unknown-freebsd4.10 and
      powerpc-apple-darwin5.5 required it. */
Index: ChangeLog
===================================================================
RCS file: /sources/gnulib/gnulib/ChangeLog,v
retrieving revision 1.530
diff -u -p -r1.530 ChangeLog
--- ChangeLog   27 Jun 2006 21:21:13 -0000      1.530
+++ ChangeLog   28 Jun 2006 11:07:26 -0000
@@ -1,3 +1,11 @@
+2006-06-28  Simon Josefsson  <address@hidden>
+
+       * tests/test-getaddrinfo.c: Test getnameinfo too.  Call WSAStartup
+       on _WIN32.
+
+       * modules/getaddrinfo (Depends-on): Add inet_ntop, needed by
+       getnameinfo.
+
 2006-06-27  Simon Josefsson  <address@hidden>
 
        * modules/sys_select: New file, suggested by Paul Eggert and
Index: modules/getaddrinfo
===================================================================
RCS file: /sources/gnulib/gnulib/modules/getaddrinfo,v
retrieving revision 1.6
diff -u -p -r1.6 getaddrinfo
--- modules/getaddrinfo 16 Feb 2006 09:47:28 -0000      1.6
+++ modules/getaddrinfo 28 Jun 2006 11:07:26 -0000
@@ -15,6 +15,7 @@ socklen
 stdbool
 strdup
 sys_socket
+inet_ntop
 
 configure.ac:
 gl_GETADDRINFO
Index: tests/test-getaddrinfo.c
===================================================================
RCS file: /sources/gnulib/gnulib/tests/test-getaddrinfo.c,v
retrieving revision 1.1
diff -u -p -r1.1 test-getaddrinfo.c
--- tests/test-getaddrinfo.c    21 Jun 2006 17:22:32 -0000      1.1
+++ tests/test-getaddrinfo.c    28 Jun 2006 11:07:26 -0000
@@ -15,9 +15,9 @@ int simple (char *host, char *service)
 
   memset (&hints, 0, sizeof (hints));
   hints.ai_flags = AI_CANONNAME;
-  hints.ai_family = AF_INET;
+  hints.ai_family = AF_UNSPEC;
   hints.ai_socktype = SOCK_STREAM;
-  res = getaddrinfo (host, 0, 0, &ai0);
+  res = getaddrinfo (host, service, 0, &ai0);
 
   printf ("res %d: %s\n", res, gai_strerror (res));
 
@@ -38,6 +38,23 @@ int simple (char *host, char *service)
                         buf, sizeof (buf) - 1));
       if (ai->ai_canonname)
        printf ("\tFound %s...\n", ai->ai_canonname);
+
+      {
+       char ipbuf[BUFSIZ];
+       char portbuf[BUFSIZ];
+
+       res = getnameinfo (ai->ai_addr, ai->ai_addrlen,
+                          ipbuf, sizeof (ipbuf) - 1,
+                          portbuf, sizeof (portbuf) - 1,
+                          NI_NUMERICHOST|NI_NUMERICSERV);
+       printf ("\t\tgetnameinfo %d: %s\n", res, gai_strerror (res));
+       if (res == 0)
+         {
+           printf ("\t\tip %s\n", ipbuf);
+           printf ("\t\tport %s\n", portbuf);
+         }
+      }
+
     }
 
   freeaddrinfo (ai0);
@@ -48,14 +65,33 @@ int simple (char *host, char *service)
 #define HOST1 "www.gnu.org"
 #define SERV1 "http"
 #define HOST2 "www.ibm.com"
-#define SERV2 "http"
-#define HOST3 "ibm.org"
+#define SERV2 "https"
+#define HOST3 "microsoft.com"
 #define SERV3 "http"
 #define HOST4 "google.org"
-#define SERV4 "http"
+#define SERV4 "ldap"
 
 int main (void)
 {
+#if _WIN32
+  {
+    WORD requested;
+    WSADATA data;
+    int err;
+
+    requested = MAKEWORD (1, 1);
+    err = WSAStartup (requested, &data);
+    if (err != 0)
+      return 1;
+
+    if (data.wVersion < requested)
+      {
+       WSACleanup ();
+       return 2;
+      }
+  }
+#endif
+
   return simple (HOST1, SERV1)
     + simple (HOST2, SERV2)
     + simple (HOST3, SERV3)




reply via email to

[Prev in Thread] Current Thread [Next in Thread]