Consistently use "superuser" instead of "super user"
[pgsql.git] / src / port / getaddrinfo.c
blobbb194da529cd4442a10592640dc47b353fb33191
1 /*-------------------------------------------------------------------------
3 * getaddrinfo.c
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
18 * IDENTIFICATION
19 * src/port/getaddrinfo.c
21 *-------------------------------------------------------------------------
24 /* This is intended to be used in both frontend and backend, so use c.h */
25 #include "c.h"
27 #include <sys/socket.h>
28 #include <netdb.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"
37 #ifdef WIN32
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,
44 const char *servname,
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,
51 int salen,
52 char *node, int nodelen,
53 char *service, int servicelen,
54 int flags);
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;
62 static bool
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 */
78 if (hLibrary != NULL)
80 /* We found a dll, so now get the addresses of the routines */
82 getaddrinfo_ptr = (getaddrinfo_ptr_t) (pg_funcptr_t) GetProcAddress(hLibrary,
83 "getaddrinfo");
84 freeaddrinfo_ptr = (freeaddrinfo_ptr_t) (pg_funcptr_t) GetProcAddress(hLibrary,
85 "freeaddrinfo");
86 getnameinfo_ptr = (getnameinfo_ptr_t) (pg_funcptr_t) GetProcAddress(hLibrary,
87 "getnameinfo");
90 * If any one of the routines is missing, let's play it safe and
91 * ignore them all
93 if (getaddrinfo_ptr == NULL ||
94 freeaddrinfo_ptr == NULL ||
95 getnameinfo_ptr == NULL)
97 FreeLibrary(hLibrary);
98 hLibrary = NULL;
99 getaddrinfo_ptr = NULL;
100 freeaddrinfo_ptr = NULL;
101 getnameinfo_ptr = NULL;
105 alreadyLookedForIpv6routines = true;
106 return (getaddrinfo_ptr != NULL);
108 #endif
112 * get address info for ipv4 sockets.
114 * Bugs: - only one addrinfo is set even though hintp is NULL or
115 * ai_socktype is 0
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)
124 struct addrinfo *ai;
125 struct sockaddr_in sin,
126 *psin;
127 struct addrinfo hints;
129 #ifdef WIN32
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);
137 #endif
139 if (hintp == NULL)
141 memset(&hints, 0, sizeof(hints));
142 hints.ai_family = AF_INET;
143 hints.ai_socktype = SOCK_STREAM;
145 else
146 memcpy(&hints, hintp, sizeof(hints));
148 if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
149 return EAI_FAMILY;
151 if (hints.ai_socktype == 0)
152 hints.ai_socktype = SOCK_STREAM;
154 if (!node && !service)
155 return EAI_NONAME;
157 memset(&sin, 0, sizeof(sin));
159 sin.sin_family = AF_INET;
161 if (node)
163 if (node[0] == '\0')
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))
168 return EAI_NONAME;
170 else
172 struct hostent *hp;
174 #ifdef FRONTEND
175 struct hostent hpstr;
176 char buf[BUFSIZ];
177 int herrno = 0;
179 pqGethostbyname(node, &hpstr, buf, sizeof(buf),
180 &hp, &herrno);
181 #else
182 hp = gethostbyname(node);
183 #endif
184 if (hp == NULL)
186 switch (h_errno)
188 case HOST_NOT_FOUND:
189 case NO_DATA:
190 return EAI_NONAME;
191 case TRY_AGAIN:
192 return EAI_AGAIN;
193 case NO_RECOVERY:
194 default:
195 return EAI_FAIL;
198 if (hp->h_addrtype != AF_INET)
199 return EAI_FAIL;
201 memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
204 else
206 if (hints.ai_flags & AI_PASSIVE)
207 sin.sin_addr.s_addr = pg_hton32(INADDR_ANY);
208 else
209 sin.sin_addr.s_addr = pg_hton32(INADDR_LOOPBACK);
212 if (service)
213 sin.sin_port = pg_hton16((unsigned short) atoi(service));
215 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
216 sin.sin_len = sizeof(sin);
217 #endif
219 ai = malloc(sizeof(*ai));
220 if (!ai)
221 return EAI_MEMORY;
223 psin = malloc(sizeof(*psin));
224 if (!psin)
226 free(ai);
227 return EAI_MEMORY;
230 memcpy(psin, &sin, sizeof(*psin));
232 ai->ai_flags = 0;
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;
239 ai->ai_next = NULL;
241 *res = ai;
243 return 0;
247 void
248 freeaddrinfo(struct addrinfo *res)
250 if (res)
252 #ifdef WIN32
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);
261 return;
263 #endif
265 if (res->ai_addr)
266 free(res->ai_addr);
267 free(res);
272 const char *
273 gai_strerror(int errcode)
275 #ifdef HAVE_HSTRERROR
276 int hcode;
278 switch (errcode)
280 case EAI_NONAME:
281 hcode = HOST_NOT_FOUND;
282 break;
283 case EAI_AGAIN:
284 hcode = TRY_AGAIN;
285 break;
286 case EAI_FAIL:
287 default:
288 hcode = NO_RECOVERY;
289 break;
292 return hstrerror(hcode);
293 #else /* !HAVE_HSTRERROR */
295 switch (errcode)
297 case EAI_NONAME:
298 return "Unknown host";
299 case EAI_AGAIN:
300 return "Host name lookup failure";
301 /* Errors below are probably WIN32 only */
302 #ifdef EAI_BADFLAGS
303 case EAI_BADFLAGS:
304 return "Invalid argument";
305 #endif
306 #ifdef EAI_FAMILY
307 case EAI_FAMILY:
308 return "Address family not supported";
309 #endif
310 #ifdef EAI_MEMORY
311 case EAI_MEMORY:
312 return "Not enough memory";
313 #endif
314 #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME /* MSVC/WIN64 duplicate */
315 case EAI_NODATA:
316 return "No host data of that type was found";
317 #endif
318 #ifdef EAI_SERVICE
319 case EAI_SERVICE:
320 return "Class type not found";
321 #endif
322 #ifdef EAI_SOCKTYPE
323 case EAI_SOCKTYPE:
324 return "Socket type not supported";
325 #endif
326 default:
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.
337 * - No IPv6 support.
340 getnameinfo(const struct sockaddr *sa, int salen,
341 char *node, int nodelen,
342 char *service, int servicelen, int flags)
344 #ifdef WIN32
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);
353 #endif
355 /* Invalid arguments. */
356 if (sa == NULL || (node == NULL && service == NULL))
357 return EAI_FAIL;
359 #ifdef HAVE_IPV6
360 if (sa->sa_family == AF_INET6)
361 return EAI_FAMILY;
362 #endif
364 /* Unsupported flags. */
365 if (flags & NI_NAMEREQD)
366 return EAI_AGAIN;
368 if (node)
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)
376 return EAI_MEMORY;
378 else
379 return EAI_MEMORY;
382 if (service)
384 int ret = -1;
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)
392 return EAI_MEMORY;
395 return 0;