diff --git a/src/port/getaddrinfo.c b/src/port/getaddrinfo.c index fdf8bcfab632ca8402128bd60c8d4c13007e3824..77757d3a79270f5378ce6ffd76c7a6e9bfb9b1d7 100644 --- a/src/port/getaddrinfo.c +++ b/src/port/getaddrinfo.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -29,6 +33,103 @@ #include "getaddrinfo.h" + +#ifdef WIN32 + +#define WIN32_LEAN_AND_MEAN + +#include <windows.h> + +/* + * 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;