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 specially
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-2011, PostgreSQL Global Development Group
19
* src/port/getaddrinfo.c
21
*-------------------------------------------------------------------------
24
/* This is intended to be used in both frontend and backend, so use c.h */
27
#include <sys/socket.h>
29
#include <netinet/in.h>
30
#include <arpa/inet.h>
32
#include "getaddrinfo.h"
33
#include "libpq/pqcomm.h" /* needed for struct sockaddr_storage */
38
* The native routines may or may not exist on the Windows platform we are on,
39
* so we dynamically look up the routines, and call them via function pointers.
40
* Here we need to declare what the function pointers look like
42
typedef int (__stdcall * getaddrinfo_ptr_t) (const char *nodename,
44
const struct addrinfo * hints,
45
struct addrinfo ** res);
47
typedef void (__stdcall * freeaddrinfo_ptr_t) (struct addrinfo * ai);
49
typedef int (__stdcall * getnameinfo_ptr_t) (const struct sockaddr * sa,
51
char *host, int hostlen,
52
char *serv, int servlen,
55
/* static pointers to the native routines, so we only do the lookup once. */
56
static getaddrinfo_ptr_t getaddrinfo_ptr = NULL;
57
static freeaddrinfo_ptr_t freeaddrinfo_ptr = NULL;
58
static getnameinfo_ptr_t getnameinfo_ptr = NULL;
62
haveNativeWindowsIPv6routines(void)
64
void *hLibrary = NULL;
65
static bool alreadyLookedForIpv6routines = false;
67
if (alreadyLookedForIpv6routines)
68
return (getaddrinfo_ptr != NULL);
71
* For Windows XP and Windows 2003 (and longhorn/vista), the IPv6 routines
72
* are present in the WinSock 2 library (ws2_32.dll). Try that first
75
hLibrary = LoadLibraryA("ws2_32");
77
if (hLibrary == NULL || GetProcAddress(hLibrary, "getaddrinfo") == NULL)
80
* Well, ws2_32 doesn't exist, or more likely doesn't have
84
FreeLibrary(hLibrary);
87
* In Windows 2000, there was only the IPv6 Technology Preview look in
88
* the IPv6 WinSock library (wship6.dll).
91
hLibrary = LoadLibraryA("wship6");
94
/* If hLibrary is null, we couldn't find a dll with functions */
97
/* We found a dll, so now get the addresses of the routines */
99
getaddrinfo_ptr = (getaddrinfo_ptr_t) GetProcAddress(hLibrary,
101
freeaddrinfo_ptr = (freeaddrinfo_ptr_t) GetProcAddress(hLibrary,
103
getnameinfo_ptr = (getnameinfo_ptr_t) GetProcAddress(hLibrary,
107
* If any one of the routines is missing, let's play it safe and
110
if (getaddrinfo_ptr == NULL ||
111
freeaddrinfo_ptr == NULL ||
112
getnameinfo_ptr == NULL)
114
FreeLibrary(hLibrary);
116
getaddrinfo_ptr = NULL;
117
freeaddrinfo_ptr = NULL;
118
getnameinfo_ptr = NULL;
122
alreadyLookedForIpv6routines = true;
123
return (getaddrinfo_ptr != NULL);
129
* get address info for ipv4 sockets.
131
* Bugs: - only one addrinfo is set even though hintp is NULL or
133
* - AI_CANONNAME is not supported.
134
* - servname can only be a number, not text.
137
getaddrinfo(const char *node, const char *service,
138
const struct addrinfo * hintp,
139
struct addrinfo ** res)
142
struct sockaddr_in sin,
144
struct addrinfo hints;
149
* If Windows has native IPv6 support, use the native Windows routine.
150
* Otherwise, fall through and use our own code.
152
if (haveNativeWindowsIPv6routines())
153
return (*getaddrinfo_ptr) (node, service, hintp, res);
158
memset(&hints, 0, sizeof(hints));
159
hints.ai_family = AF_INET;
160
hints.ai_socktype = SOCK_STREAM;
163
memcpy(&hints, hintp, sizeof(hints));
165
if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
168
if (hints.ai_socktype == 0)
169
hints.ai_socktype = SOCK_STREAM;
171
if (!node && !service)
174
memset(&sin, 0, sizeof(sin));
176
sin.sin_family = AF_INET;
181
sin.sin_addr.s_addr = htonl(INADDR_ANY);
182
else if (hints.ai_flags & AI_NUMERICHOST)
184
if (!inet_aton(node, &sin.sin_addr))
192
struct hostent hpstr;
196
pqGethostbyname(node, &hpstr, buf, sizeof(buf),
199
hp = gethostbyname(node);
215
if (hp->h_addrtype != AF_INET)
218
memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
223
if (hints.ai_flags & AI_PASSIVE)
224
sin.sin_addr.s_addr = htonl(INADDR_ANY);
226
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
230
sin.sin_port = htons((unsigned short) atoi(service));
232
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
233
sin.sin_len = sizeof(sin);
236
ai = malloc(sizeof(*ai));
240
psin = malloc(sizeof(*psin));
247
memcpy(psin, &sin, sizeof(*psin));
250
ai->ai_family = AF_INET;
251
ai->ai_socktype = hints.ai_socktype;
252
ai->ai_protocol = hints.ai_protocol;
253
ai->ai_addrlen = sizeof(*psin);
254
ai->ai_addr = (struct sockaddr *) psin;
255
ai->ai_canonname = NULL;
265
freeaddrinfo(struct addrinfo * res)
272
* If Windows has native IPv6 support, use the native Windows routine.
273
* Otherwise, fall through and use our own code.
275
if (haveNativeWindowsIPv6routines())
277
(*freeaddrinfo_ptr) (res);
290
gai_strerror(int errcode)
292
#ifdef HAVE_HSTRERROR
298
hcode = HOST_NOT_FOUND;
309
return hstrerror(hcode);
310
#else /* !HAVE_HSTRERROR */
315
return "Unknown host";
317
return "Host name lookup failure";
318
/* Errors below are probably WIN32 only */
321
return "Invalid argument";
325
return "Address family not supported";
329
return "Not enough memory";
332
#if !defined(WIN64) && !defined(WIN32_ONLY_COMPILER) /* MSVC/WIN64 duplicate */
334
return "No host data of that type was found";
339
return "Class type not found";
343
return "Socket type not supported";
346
return "Unknown server error";
348
#endif /* HAVE_HSTRERROR */
352
* Convert an ipv4 address to a hostname.
354
* Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV
355
* It will never resolv a hostname.
359
getnameinfo(const struct sockaddr * sa, int salen,
360
char *node, int nodelen,
361
char *service, int servicelen, int flags)
366
* If Windows has native IPv6 support, use the native Windows routine.
367
* Otherwise, fall through and use our own code.
369
if (haveNativeWindowsIPv6routines())
370
return (*getnameinfo_ptr) (sa, salen, node, nodelen,
371
service, servicelen, flags);
374
/* Invalid arguments. */
375
if (sa == NULL || (node == NULL && service == NULL))
378
/* We don't support those. */
379
if ((node && !(flags & NI_NUMERICHOST))
380
|| (service && !(flags & NI_NUMERICSERV)))
384
if (sa->sa_family == AF_INET6)
390
if (sa->sa_family == AF_INET)
392
if (inet_net_ntop(AF_INET, &((struct sockaddr_in *) sa)->sin_addr,
393
sa->sa_family == AF_INET ? 32 : 128,
394
node, nodelen) == NULL)
405
if (sa->sa_family == AF_INET)
407
ret = snprintf(service, servicelen, "%d",
408
ntohs(((struct sockaddr_in *) sa)->sin_port));
410
if (ret == -1 || ret > servicelen)