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-2021, 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 */
34 #include "port/pg_bswap.h"
39 * The native routines may or may not exist on the Windows platform we are on,
40 * so we dynamically look up the routines, and call them via function pointers.
41 * Here we need to declare what the function pointers look like
43 typedef int (__stdcall
* getaddrinfo_ptr_t
) (const char *nodename
,
45 const struct addrinfo
*hints
,
46 struct addrinfo
**res
);
48 typedef void (__stdcall
* freeaddrinfo_ptr_t
) (struct addrinfo
*ai
);
50 typedef int (__stdcall
* getnameinfo_ptr_t
) (const struct sockaddr
*sa
,
52 char *node
, int nodelen
,
53 char *service
, int servicelen
,
56 /* static pointers to the native routines, so we only do the lookup once. */
57 static getaddrinfo_ptr_t getaddrinfo_ptr
= NULL
;
58 static freeaddrinfo_ptr_t freeaddrinfo_ptr
= NULL
;
59 static getnameinfo_ptr_t getnameinfo_ptr
= NULL
;
63 haveNativeWindowsIPv6routines(void)
65 void *hLibrary
= NULL
;
66 static bool alreadyLookedForIpv6routines
= false;
68 if (alreadyLookedForIpv6routines
)
69 return (getaddrinfo_ptr
!= NULL
);
72 * For Windows XP and later versions, the IPv6 routines are present in the
73 * WinSock 2 library (ws2_32.dll).
75 hLibrary
= LoadLibraryA("ws2_32");
77 /* If hLibrary is null, we couldn't find a dll with functions */
80 /* We found a dll, so now get the addresses of the routines */
82 getaddrinfo_ptr
= (getaddrinfo_ptr_t
) (pg_funcptr_t
) GetProcAddress(hLibrary
,
84 freeaddrinfo_ptr
= (freeaddrinfo_ptr_t
) (pg_funcptr_t
) GetProcAddress(hLibrary
,
86 getnameinfo_ptr
= (getnameinfo_ptr_t
) (pg_funcptr_t
) GetProcAddress(hLibrary
,
90 * If any one of the routines is missing, let's play it safe and
93 if (getaddrinfo_ptr
== NULL
||
94 freeaddrinfo_ptr
== NULL
||
95 getnameinfo_ptr
== NULL
)
97 FreeLibrary(hLibrary
);
99 getaddrinfo_ptr
= NULL
;
100 freeaddrinfo_ptr
= NULL
;
101 getnameinfo_ptr
= NULL
;
105 alreadyLookedForIpv6routines
= true;
106 return (getaddrinfo_ptr
!= NULL
);
112 * get address info for ipv4 sockets.
114 * Bugs: - only one addrinfo is set even though hintp is NULL or
116 * - AI_CANONNAME is not supported.
117 * - servname can only be a number, not text.
120 getaddrinfo(const char *node
, const char *service
,
121 const struct addrinfo
*hintp
,
122 struct addrinfo
**res
)
125 struct sockaddr_in sin
,
127 struct addrinfo hints
;
132 * If Windows has native IPv6 support, use the native Windows routine.
133 * Otherwise, fall through and use our own code.
135 if (haveNativeWindowsIPv6routines())
136 return (*getaddrinfo_ptr
) (node
, service
, hintp
, res
);
141 memset(&hints
, 0, sizeof(hints
));
142 hints
.ai_family
= AF_INET
;
143 hints
.ai_socktype
= SOCK_STREAM
;
146 memcpy(&hints
, hintp
, sizeof(hints
));
148 if (hints
.ai_family
!= AF_INET
&& hints
.ai_family
!= AF_UNSPEC
)
151 if (hints
.ai_socktype
== 0)
152 hints
.ai_socktype
= SOCK_STREAM
;
154 if (!node
&& !service
)
157 memset(&sin
, 0, sizeof(sin
));
159 sin
.sin_family
= AF_INET
;
164 sin
.sin_addr
.s_addr
= pg_hton32(INADDR_ANY
);
165 else if (hints
.ai_flags
& AI_NUMERICHOST
)
167 if (!inet_aton(node
, &sin
.sin_addr
))
175 struct hostent hpstr
;
179 pqGethostbyname(node
, &hpstr
, buf
, sizeof(buf
),
182 hp
= gethostbyname(node
);
198 if (hp
->h_addrtype
!= AF_INET
)
201 memcpy(&(sin
.sin_addr
), hp
->h_addr
, hp
->h_length
);
206 if (hints
.ai_flags
& AI_PASSIVE
)
207 sin
.sin_addr
.s_addr
= pg_hton32(INADDR_ANY
);
209 sin
.sin_addr
.s_addr
= pg_hton32(INADDR_LOOPBACK
);
213 sin
.sin_port
= pg_hton16((unsigned short) atoi(service
));
215 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
216 sin
.sin_len
= sizeof(sin
);
219 ai
= malloc(sizeof(*ai
));
223 psin
= malloc(sizeof(*psin
));
230 memcpy(psin
, &sin
, sizeof(*psin
));
233 ai
->ai_family
= AF_INET
;
234 ai
->ai_socktype
= hints
.ai_socktype
;
235 ai
->ai_protocol
= hints
.ai_protocol
;
236 ai
->ai_addrlen
= sizeof(*psin
);
237 ai
->ai_addr
= (struct sockaddr
*) psin
;
238 ai
->ai_canonname
= NULL
;
248 freeaddrinfo(struct addrinfo
*res
)
255 * If Windows has native IPv6 support, use the native Windows routine.
256 * Otherwise, fall through and use our own code.
258 if (haveNativeWindowsIPv6routines())
260 (*freeaddrinfo_ptr
) (res
);
273 gai_strerror(int errcode
)
275 #ifdef HAVE_HSTRERROR
281 hcode
= HOST_NOT_FOUND
;
292 return hstrerror(hcode
);
293 #else /* !HAVE_HSTRERROR */
298 return "Unknown host";
300 return "Host name lookup failure";
301 /* Errors below are probably WIN32 only */
304 return "Invalid argument";
308 return "Address family not supported";
312 return "Not enough memory";
314 #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME /* MSVC/WIN64 duplicate */
316 return "No host data of that type was found";
320 return "Class type not found";
324 return "Socket type not supported";
327 return "Unknown server error";
329 #endif /* HAVE_HSTRERROR */
333 * Convert an ipv4 address to a hostname.
335 * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV behavior.
336 * It will never resolve a hostname.
340 getnameinfo(const struct sockaddr
*sa
, int salen
,
341 char *node
, int nodelen
,
342 char *service
, int servicelen
, int flags
)
347 * If Windows has native IPv6 support, use the native Windows routine.
348 * Otherwise, fall through and use our own code.
350 if (haveNativeWindowsIPv6routines())
351 return (*getnameinfo_ptr
) (sa
, salen
, node
, nodelen
,
352 service
, servicelen
, flags
);
355 /* Invalid arguments. */
356 if (sa
== NULL
|| (node
== NULL
&& service
== NULL
))
360 if (sa
->sa_family
== AF_INET6
)
364 /* Unsupported flags. */
365 if (flags
& NI_NAMEREQD
)
370 if (sa
->sa_family
== AF_INET
)
372 if (pg_inet_net_ntop(AF_INET
,
373 &((struct sockaddr_in
*) sa
)->sin_addr
,
374 sa
->sa_family
== AF_INET
? 32 : 128,
375 node
, nodelen
) == NULL
)
386 if (sa
->sa_family
== AF_INET
)
388 ret
= snprintf(service
, servicelen
, "%d",
389 pg_ntoh16(((struct sockaddr_in
*) sa
)->sin_port
));
391 if (ret
< 0 || ret
>= servicelen
)