1 /*-------------------------------------------------------------------------
4 * Support getaddrinfo() on platforms that don't have it.
6 * We also supply getnameinfo() here, assuming that the platform will have
7 * it if and only if it has getaddrinfo(). If this proves false on some
8 * platform, we'll need to split this file and provide a separate configure
9 * test for getnameinfo().
11 * Windows may or may not have these routines, so we handle Windows special
12 * by dynamically checking for their existence. If they already exist, we
13 * use the Windows native routines, but if not, we use our own.
16 * Copyright (c) 2003-2005, PostgreSQL Global Development Group
19 * $PostgreSQL: pgsql/src/port/getaddrinfo.c,v 1.20 2005/10/13 23:22:11 momjian Exp $
21 *-------------------------------------------------------------------------
24 /* This is intended to be used in both frontend and backend, so use c.h */
27 #ifndef WIN32_CLIENT_ONLY
28 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
34 #include "getaddrinfo.h"
39 #define WIN32_LEAN_AND_MEAN
44 * The native routines may or may not exist on the Windows platform we are on,
45 * so we dynamically look up the routines, and call them via function pointers.
46 * Here we need to declare what the function pointers look like
48 typedef int (__stdcall * getaddrinfo_ptr_t) (const char *nodename,
50 const struct addrinfo * hints,
51 struct addrinfo ** res);
53 typedef void (__stdcall * freeaddrinfo_ptr_t) (struct addrinfo * ai);
55 typedef int (__stdcall * getnameinfo_ptr_t) (const struct sockaddr * sa,
57 char *host, int hostlen,
58 char *serv, int servlen,
61 /* static pointers to the native routines, so we only do the lookup once. */
62 static getaddrinfo_ptr_t getaddrinfo_ptr = NULL;
63 static freeaddrinfo_ptr_t freeaddrinfo_ptr = NULL;
64 static getnameinfo_ptr_t getnameinfo_ptr = NULL;
68 haveNativeWindowsIPv6routines(void)
70 void *hLibrary = NULL;
71 static bool alreadyLookedForIpv6routines = false;
73 if (alreadyLookedForIpv6routines)
74 return (getaddrinfo_ptr != NULL);
77 * For Windows XP and Windows 2003 (and longhorn/vista), the IPv6
78 * routines are present in the WinSock 2 library (ws2_32.dll).
82 hLibrary = LoadLibraryA("ws2_32");
84 if (hLibrary == NULL || GetProcAddress(hLibrary, "getaddrinfo") == NULL)
87 * Well, ws2_32 doesn't exist, or more likely doesn't have
91 FreeLibrary(hLibrary);
94 * In Windows 2000, there was only the IPv6 Technology Preview look in
95 * the IPv6 WinSock library (wship6.dll).
98 hLibrary = LoadLibraryA("wship6");
101 /* If hLibrary is null, we couldn't find a dll with functions */
102 if (hLibrary != NULL)
104 /* We found a dll, so now get the addresses of the routines */
106 getaddrinfo_ptr = (getaddrinfo_ptr_t) GetProcAddress(hLibrary,
108 freeaddrinfo_ptr = (freeaddrinfo_ptr_t) GetProcAddress(hLibrary,
110 getnameinfo_ptr = (getnameinfo_ptr_t) GetProcAddress(hLibrary,
114 * If any one of the routines is missing, let's play it safe and
117 if (getaddrinfo_ptr == NULL ||
118 freeaddrinfo_ptr == NULL ||
119 getnameinfo_ptr == NULL)
121 FreeLibrary(hLibrary);
123 getaddrinfo_ptr = NULL;
124 freeaddrinfo_ptr = NULL;
125 getnameinfo_ptr = NULL;
129 alreadyLookedForIpv6routines = true;
130 return (getaddrinfo_ptr != NULL);
137 * get address info for ipv4 sockets.
139 * Bugs: - only one addrinfo is set even though hintp is NULL or
141 * - AI_CANONNAME is not supported.
142 * - servname can only be a number, not text.
145 getaddrinfo(const char *node, const char *service,
146 const struct addrinfo * hintp,
147 struct addrinfo ** res)
150 struct sockaddr_in sin,
152 struct addrinfo hints;
156 * If Windows has native IPv6 support, use the native Windows routine.
157 * Otherwise, fall through and use our own code.
159 if (haveNativeWindowsIPv6routines())
160 return (*getaddrinfo_ptr) (node, service, hintp, res);
165 memset(&hints, 0, sizeof(hints));
166 hints.ai_family = AF_INET;
167 hints.ai_socktype = SOCK_STREAM;
170 memcpy(&hints, hintp, sizeof(hints));
172 if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
175 if (hints.ai_socktype == 0)
176 hints.ai_socktype = SOCK_STREAM;
178 if (!node && !service)
181 memset(&sin, 0, sizeof(sin));
183 sin.sin_family = AF_INET;
188 sin.sin_addr.s_addr = htonl(INADDR_ANY);
189 else if (hints.ai_flags & AI_NUMERICHOST)
191 if (!inet_aton(node, &sin.sin_addr))
199 struct hostent hpstr;
203 pqGethostbyname(node, &hpstr, buf, sizeof(buf),
206 hp = gethostbyname(node);
222 if (hp->h_addrtype != AF_INET)
225 memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
230 if (hints.ai_flags & AI_PASSIVE)
231 sin.sin_addr.s_addr = htonl(INADDR_ANY);
233 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
237 sin.sin_port = htons((unsigned short) atoi(service));
239 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
240 sin.sin_len = sizeof(sin);
243 ai = malloc(sizeof(*ai));
247 psin = malloc(sizeof(*psin));
254 memcpy(psin, &sin, sizeof(*psin));
257 ai->ai_family = AF_INET;
258 ai->ai_socktype = hints.ai_socktype;
259 ai->ai_protocol = hints.ai_protocol;
260 ai->ai_addrlen = sizeof(*psin);
261 ai->ai_addr = (struct sockaddr *) psin;
262 ai->ai_canonname = NULL;
272 freeaddrinfo(struct addrinfo * res)
278 * If Windows has native IPv6 support, use the native Windows routine.
279 * Otherwise, fall through and use our own code.
281 if (haveNativeWindowsIPv6routines())
283 (*freeaddrinfo_ptr) (res);
296 gai_strerror(int errcode)
298 #ifdef HAVE_HSTRERROR
304 hcode = HOST_NOT_FOUND;
315 return hstrerror(hcode);
317 #else /* !HAVE_HSTRERROR */
322 return "Unknown host";
324 return "Host name lookup failure";
325 /* Errors below are probably WIN32 only */
328 return "Invalid argument";
332 return "Address family not supported";
336 return "Not enough memory";
340 return "No host data of that type was found";
344 return "Class type not found";
348 return "Socket type not supported";
351 return "Unknown server error";
353 #endif /* HAVE_HSTRERROR */
357 * Convert an ipv4 address to a hostname.
359 * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV
360 * It will never resolv a hostname.
364 getnameinfo(const struct sockaddr * sa, int salen,
365 char *node, int nodelen,
366 char *service, int servicelen, int flags)
370 * If Windows has native IPv6 support, use the native Windows routine.
371 * Otherwise, fall through and use our own code.
373 if (haveNativeWindowsIPv6routines())
374 return (*getnameinfo_ptr) (sa, salen, node, nodelen,
375 service, servicelen, flags);
378 /* Invalid arguments. */
379 if (sa == NULL || (node == NULL && service == NULL))
382 /* We don't support those. */
383 if ((node && !(flags & NI_NUMERICHOST))
384 || (service && !(flags & NI_NUMERICSERV)))
388 if (sa->sa_family == AF_INET6)
396 if (sa->sa_family == AF_INET)
400 p = inet_ntoa(((struct sockaddr_in *) sa)->sin_addr);
401 ret = snprintf(node, nodelen, "%s", p);
403 if (ret == -1 || ret > nodelen)
411 if (sa->sa_family == AF_INET)
413 ret = snprintf(service, servicelen, "%d",
414 ntohs(((struct sockaddr_in *) sa)->sin_port));
416 if (ret == -1 || ret > servicelen)