* getaddrinfo.c
* Support getaddrinfo() on platforms that don't have it.
*
+ * We also supply getnameinfo() here, assuming that the platform will have
+ * it if and only if it has getaddrinfo(). If this proves false on some
+ * platform, we'll need to split this file and provide a separate configure
+ * test for getnameinfo().
*
- * Copyright (c) 2003, PostgreSQL Global Development Group
+ * Windows may or may not have these routines, so we handle Windows specially
+ * 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-2013, PostgreSQL Global Development Group
+ *
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/port/getaddrinfo.c,v 1.9 2003/06/23 23:52:00 momjian Exp $
+ * src/port/getaddrinfo.c
*
*-------------------------------------------------------------------------
*/
/* This is intended to be used in both frontend and backend, so use c.h */
#include "c.h"
-#if !defined(_MSC_VER) && !defined(__BORLANDC__)
-#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#ifdef HAVE_UNIX_SOCKETS
-#include <sys/un.h>
-#endif
-#endif
#include "getaddrinfo.h"
+#include "libpq/pqcomm.h" /* needed for struct sockaddr_storage */
+
+
+#ifdef WIN32
+/*
+ * 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 = (getaddrinfo_ptr_t) GetProcAddress(hLibrary,
+ "getaddrinfo");
+ freeaddrinfo_ptr = (freeaddrinfo_ptr_t) GetProcAddress(hLibrary,
+ "freeaddrinfo");
+ getnameinfo_ptr = (getnameinfo_ptr_t) 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.
*/
int
getaddrinfo(const char *node, const char *service,
- const struct addrinfo *hintp,
- struct addrinfo **res)
+ const struct addrinfo * hintp,
+ struct addrinfo ** res)
{
- struct addrinfo *ai;
- struct sockaddr_in sin, *psin;
- struct addrinfo hints;
+ struct addrinfo *ai;
+ struct sockaddr_in sin,
+ *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)
+ if (hintp == NULL)
{
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
}
else
- {
memcpy(&hints, hintp, sizeof(hints));
- }
if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
return EAI_FAMILY;
else if (hints.ai_flags & AI_NUMERICHOST)
{
if (!inet_aton(node, &sin.sin_addr))
- {
return EAI_FAIL;
- }
}
else
{
struct hostent *hp;
+
#ifdef FRONTEND
struct hostent hpstr;
- char buf[BUFSIZ];
- int herrno = 0;
+ char buf[BUFSIZ];
+ int herrno = 0;
pqGethostbyname(node, &hpstr, buf, sizeof(buf),
- &hp, &herrno);
+ &hp, &herrno);
#else
hp = gethostbyname(node);
#endif
if (service)
sin.sin_port = htons((unsigned short) atoi(service));
-#if SALEN
- sin.sin_len = sizeof(sin);
+
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
+ sin.sin_len = sizeof(sin);
#endif
ai = malloc(sizeof(*ai));
if (!ai)
- {
return EAI_MEMORY;
- }
psin = malloc(sizeof(*psin));
if (!psin)
void
-freeaddrinfo(struct addrinfo *res)
+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) (res);
+ return;
+ }
+#endif
+
if (res->ai_addr)
free(res->ai_addr);
free(res);
gai_strerror(int errcode)
{
#ifdef HAVE_HSTRERROR
- int hcode;
+ int hcode;
switch (errcode)
{
}
return hstrerror(hcode);
-
-#else /* !HAVE_HSTRERROR */
+#else /* !HAVE_HSTRERROR */
switch (errcode)
{
return "Unknown host";
case EAI_AGAIN:
return "Host name lookup failure";
- case EAI_FAIL:
+ /* Errors below are probably WIN32 only */
+#ifdef EAI_BADFLAGS
+ case EAI_BADFLAGS:
+ return "Invalid argument";
+#endif
+#ifdef EAI_FAMILY
+ case EAI_FAMILY:
+ return "Address family not supported";
+#endif
+#ifdef EAI_MEMORY
+ case EAI_MEMORY:
+ return "Not enough memory";
+#endif
+#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME /* MSVC/WIN64 duplicate */
+ case EAI_NODATA:
+ return "No host data of that type was found";
+#endif
+#ifdef EAI_SERVICE
+ case EAI_SERVICE:
+ return "Class type not found";
+#endif
+#ifdef EAI_SOCKTYPE
+ case EAI_SOCKTYPE:
+ return "Socket type not supported";
+#endif
default:
return "Unknown server error";
}
-
-#endif /* HAVE_HSTRERROR */
+#endif /* HAVE_HSTRERROR */
}
/*
- * Convert an address to a hostname.
- *
+ * Convert an ipv4 address to a hostname.
+ *
* Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV
* It will never resolv a hostname.
* - No IPv6 support.
*/
int
-getnameinfo(const struct sockaddr *sa, int salen,
- char *node, int nodelen,
- char *service, int servicelen, int flags)
+getnameinfo(const struct sockaddr * sa, int salen,
+ char *node, int nodelen,
+ char *service, int servicelen, int flags)
{
- int ret = -1;
+#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;
- }
-
- /* We don't support those. */
- if ((node && !(flags & NI_NUMERICHOST))
- || (service && !(flags & NI_NUMERICSERV)))
- {
return EAI_FAIL;
- }
#ifdef HAVE_IPV6
if (sa->sa_family == AF_INET6)
- {
- return EAI_FAMILY;
- }
+ return EAI_FAMILY;
#endif
- if (service)
+ if (node)
{
if (sa->sa_family == AF_INET)
{
- ret = snprintf(service, servicelen, "%d",
- ntohs(((struct sockaddr_in *)sa)->sin_port));
- }
-#ifdef HAVE_UNIX_SOCKETS
- else if (sa->sa_family == AF_UNIX)
- {
- ret = snprintf(service, servicelen, "%s",
- ((struct sockaddr_un *)sa)->sun_path);
+ if (inet_net_ntop(AF_INET, &((struct sockaddr_in *) sa)->sin_addr,
+ sa->sa_family == AF_INET ? 32 : 128,
+ node, nodelen) == NULL)
+ return EAI_MEMORY;
}
-#endif
- if (ret == -1 || ret > servicelen)
- {
+ else
return EAI_MEMORY;
- }
}
- if (node)
+ if (service)
{
+ int ret = -1;
+
if (sa->sa_family == AF_INET)
{
- char *p;
- p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
- ret = snprintf(node, nodelen, "%s", p);
- }
-#ifdef HAVE_UNIX_SOCKETS
- else if (sa->sa_family == AF_UNIX)
- {
- ret = snprintf(node, nodelen, "%s", "localhost");
+ ret = snprintf(service, servicelen, "%d",
+ ntohs(((struct sockaddr_in *) sa)->sin_port));
}
-#endif
- if (ret == -1 || ret > nodelen)
- {
+ if (ret == -1 || ret > servicelen)
return EAI_MEMORY;
- }
}
return 0;