Add code to use Windows getaddrinfo and friends if they exist. This
authorTom Lane
Wed, 24 Aug 2005 22:13:23 +0000 (22:13 +0000)
committerTom Lane
Wed, 24 Aug 2005 22:13:23 +0000 (22:13 +0000)
has to be tested dynamically if we want to make portable executables.
Chuck McDevitt and Andrew Dunstan.

src/port/getaddrinfo.c

index fdf8bcfab632ca8402128bd60c8d4c13007e3824..77757d3a79270f5378ce6ffd76c7a6e9bfb9b1d7 100644 (file)
@@ -8,11 +8,15 @@
  * platform, we'll need to split this file and provide a separate configure
  * test for getnameinfo().
  *
+ * Windows may or may not have these routines, so we handle Windows special
+ * by dynamically checking for their existence.  If they already exist, we
+ * use the Windows native routines, but if not, we use our own.
+ *
  *
  * Copyright (c) 2003-2005, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/port/getaddrinfo.c,v 1.17 2005/07/28 04:03:14 tgl Exp $
+ *   $PostgreSQL: pgsql/src/port/getaddrinfo.c,v 1.18 2005/08/24 22:13:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "getaddrinfo.h"
 
+
+#ifdef WIN32
+
+#define WIN32_LEAN_AND_MEAN
+
+#include 
+
+/*
+ * The native routines may or may not exist on the Windows platform we are on,
+ * so we dynamically look up the routines, and call them via function pointers.
+ * Here we need to declare what the function pointers look like
+ */
+typedef int (__stdcall * getaddrinfo_ptr_t) (const char *nodename,
+                                            const char *servname,
+                                            const struct addrinfo * hints,
+                                            struct addrinfo ** res);
+
+typedef void (__stdcall * freeaddrinfo_ptr_t) (struct addrinfo * ai);
+
+typedef int (__stdcall * getnameinfo_ptr_t) (const struct sockaddr * sa,
+                                            int salen,
+                                            char *host, int hostlen,
+                                            char *serv, int servlen,
+                                            int flags);
+
+/* static pointers to the native routines, so we only do the lookup once. */
+static getaddrinfo_ptr_t getaddrinfo_ptr = NULL;
+static freeaddrinfo_ptr_t freeaddrinfo_ptr = NULL;
+static getnameinfo_ptr_t getnameinfo_ptr = NULL;
+
+
+static bool
+haveNativeWindowsIPv6routines(void)
+{
+   void       *hLibrary = NULL;
+   static bool alreadyLookedForIpv6routines = FALSE;
+
+   if (alreadyLookedForIpv6routines)
+       return (getaddrinfo_ptr != NULL);
+
+   /*
+    * For Windows XP and Windows 2003 (and longhorn/vista), the IPv6
+    * routines are present in the WinSock 2 library (ws2_32.dll).
+    * Try that first
+    */
+
+   hLibrary = LoadLibraryA("ws2_32");
+
+   if (hLibrary == NULL || GetProcAddress(hLibrary, "getaddrinfo") == NULL)
+   {
+       /*
+        * Well, ws2_32 doesn't exist, or more likely doesn't have
+        * getaddrinfo.
+        */
+       if (hLibrary != NULL)
+           FreeLibrary(hLibrary);
+
+       /*
+        * In Windows 2000, there was only the IPv6 Technology Preview look in
+        * the IPv6 WinSock library (wship6.dll).
+        */
+
+       hLibrary = LoadLibraryA("wship6");
+   }
+
+   /* If hLibrary is null, we couldn't find a dll with functions */
+   if (hLibrary != NULL)
+   {
+       /* We found a dll, so now get the addresses of the routines */
+
+       getaddrinfo_ptr = GetProcAddress(hLibrary, "getaddrinfo");
+       freeaddrinfo_ptr = GetProcAddress(hLibrary, "freeaddrinfo");
+       getnameinfo_ptr = GetProcAddress(hLibrary, "getnameinfo");
+
+       /*
+        * If any one of the routines is missing, let's play it safe and
+        * ignore them all
+        */
+       if (getaddrinfo_ptr == NULL ||
+           freeaddrinfo_ptr == NULL ||
+           getnameinfo_ptr == NULL)
+       {
+           FreeLibrary(hLibrary);
+           hLibrary = NULL;
+           getaddrinfo_ptr = NULL;
+           freeaddrinfo_ptr = NULL;
+           getnameinfo_ptr = NULL;
+       }
+   }
+
+   alreadyLookedForIpv6routines = TRUE;
+   return (getaddrinfo_ptr != NULL);
+}
+
+#endif
+
+
 /*
  * get address info for ipv4 sockets.
  *
@@ -47,6 +148,15 @@ getaddrinfo(const char *node, const char *service,
               *psin;
    struct addrinfo hints;
 
+#ifdef WIN32
+   /*
+    * If Windows has native IPv6 support, use the native Windows routine.
+    * Otherwise, fall through and use our own code.
+    */
+   if (haveNativeWindowsIPv6routines())
+       return (*getaddrinfo_ptr) (node, service, hintp, res);
+#endif
+
    if (hintp == NULL)
    {
        memset(&hints, 0, sizeof(hints));
@@ -160,6 +270,18 @@ freeaddrinfo(struct addrinfo * res)
 {
    if (res)
    {
+#ifdef WIN32
+       /*
+        * If Windows has native IPv6 support, use the native Windows routine.
+        * Otherwise, fall through and use our own code.
+        */
+       if (haveNativeWindowsIPv6routines())
+       {
+           (*freeaddrinfo_ptr) (node, service, hintp, res);
+           return;
+       }
+#endif
+
        if (res->ai_addr)
            free(res->ai_addr);
        free(res);
@@ -188,7 +310,6 @@ gai_strerror(int errcode)
    }
 
    return hstrerror(hcode);
-
 #else                          /* !HAVE_HSTRERROR */
 
    switch (errcode)
@@ -216,6 +337,16 @@ getnameinfo(const struct sockaddr * sa, int salen,
            char *node, int nodelen,
            char *service, int servicelen, int flags)
 {
+#ifdef WIN32
+   /*
+    * If Windows has native IPv6 support, use the native Windows routine.
+    * Otherwise, fall through and use our own code.
+    */
+   if (haveNativeWindowsIPv6routines())
+       return (*getnameinfo_ptr) (sa, salen, node, nodelen,
+                                  service, servicelen, flags);
+#endif
+
    /* Invalid arguments. */
    if (sa == NULL || (node == NULL && service == NULL))
        return EAI_FAIL;