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-2008, PostgreSQL Global Development Group
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 #ifndef WIN32_ONLY_COMPILER /* MSVC complains because another case has the
335 return "No host data of that type was found";
340 return "Class type not found";
344 return "Socket type not supported";
347 return "Unknown server error";
349 #endif /* HAVE_HSTRERROR */
353 * Convert an ipv4 address to a hostname.
355 * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV
356 * It will never resolv a hostname.
360 getnameinfo(const struct sockaddr
* sa
, int salen
,
361 char *node
, int nodelen
,
362 char *service
, int servicelen
, int flags
)
367 * If Windows has native IPv6 support, use the native Windows routine.
368 * Otherwise, fall through and use our own code.
370 if (haveNativeWindowsIPv6routines())
371 return (*getnameinfo_ptr
) (sa
, salen
, node
, nodelen
,
372 service
, servicelen
, flags
);
375 /* Invalid arguments. */
376 if (sa
== NULL
|| (node
== NULL
&& service
== NULL
))
379 /* We don't support those. */
380 if ((node
&& !(flags
& NI_NUMERICHOST
))
381 || (service
&& !(flags
& NI_NUMERICSERV
)))
385 if (sa
->sa_family
== AF_INET6
)
393 if (sa
->sa_family
== AF_INET
)
397 p
= inet_ntoa(((struct sockaddr_in
*) sa
)->sin_addr
);
398 ret
= snprintf(node
, nodelen
, "%s", p
);
400 if (ret
== -1 || ret
> nodelen
)
408 if (sa
->sa_family
== AF_INET
)
410 ret
= snprintf(service
, servicelen
, "%d",
411 ntohs(((struct sockaddr_in
*) sa
)->sin_port
));
413 if (ret
== -1 || ret
> servicelen
)