PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
getaddrinfo.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * getaddrinfo.c
4  * Support getaddrinfo() on platforms that don't have it.
5  *
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().
10  *
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.
14  *
15  *
16  * Copyright (c) 2003-2017, PostgreSQL Global Development Group
17  *
18  * IDENTIFICATION
19  * src/port/getaddrinfo.c
20  *
21  *-------------------------------------------------------------------------
22  */
23 
24 /* This is intended to be used in both frontend and backend, so use c.h */
25 #include "c.h"
26 
27 #include <sys/socket.h>
28 #include <netdb.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 
32 #include "getaddrinfo.h"
33 #include "libpq/pqcomm.h" /* needed for struct sockaddr_storage */
34 
35 
36 #ifdef WIN32
37 /*
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
41  */
42 typedef int (__stdcall * getaddrinfo_ptr_t) (const char *nodename,
43  const char *servname,
44  const struct addrinfo *hints,
45  struct addrinfo **res);
46 
47 typedef void (__stdcall * freeaddrinfo_ptr_t) (struct addrinfo *ai);
48 
49 typedef int (__stdcall * getnameinfo_ptr_t) (const struct sockaddr *sa,
50  int salen,
51  char *host, int hostlen,
52  char *serv, int servlen,
53  int flags);
54 
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;
59 
60 
61 static bool
62 haveNativeWindowsIPv6routines(void)
63 {
64  void *hLibrary = NULL;
65  static bool alreadyLookedForIpv6routines = false;
66 
67  if (alreadyLookedForIpv6routines)
68  return (getaddrinfo_ptr != NULL);
69 
70  /*
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
73  */
74 
75  hLibrary = LoadLibraryA("ws2_32");
76 
77  if (hLibrary == NULL || GetProcAddress(hLibrary, "getaddrinfo") == NULL)
78  {
79  /*
80  * Well, ws2_32 doesn't exist, or more likely doesn't have
81  * getaddrinfo.
82  */
83  if (hLibrary != NULL)
84  FreeLibrary(hLibrary);
85 
86  /*
87  * In Windows 2000, there was only the IPv6 Technology Preview look in
88  * the IPv6 WinSock library (wship6.dll).
89  */
90 
91  hLibrary = LoadLibraryA("wship6");
92  }
93 
94  /* If hLibrary is null, we couldn't find a dll with functions */
95  if (hLibrary != NULL)
96  {
97  /* We found a dll, so now get the addresses of the routines */
98 
99  getaddrinfo_ptr = (getaddrinfo_ptr_t) GetProcAddress(hLibrary,
100  "getaddrinfo");
101  freeaddrinfo_ptr = (freeaddrinfo_ptr_t) GetProcAddress(hLibrary,
102  "freeaddrinfo");
103  getnameinfo_ptr = (getnameinfo_ptr_t) GetProcAddress(hLibrary,
104  "getnameinfo");
105 
106  /*
107  * If any one of the routines is missing, let's play it safe and
108  * ignore them all
109  */
110  if (getaddrinfo_ptr == NULL ||
111  freeaddrinfo_ptr == NULL ||
112  getnameinfo_ptr == NULL)
113  {
114  FreeLibrary(hLibrary);
115  hLibrary = NULL;
116  getaddrinfo_ptr = NULL;
117  freeaddrinfo_ptr = NULL;
118  getnameinfo_ptr = NULL;
119  }
120  }
121 
122  alreadyLookedForIpv6routines = true;
123  return (getaddrinfo_ptr != NULL);
124 }
125 #endif
126 
127 
128 /*
129  * get address info for ipv4 sockets.
130  *
131  * Bugs: - only one addrinfo is set even though hintp is NULL or
132  * ai_socktype is 0
133  * - AI_CANONNAME is not supported.
134  * - servname can only be a number, not text.
135  */
136 int
137 getaddrinfo(const char *node, const char *service,
138  const struct addrinfo *hintp,
139  struct addrinfo **res)
140 {
141  struct addrinfo *ai;
142  struct sockaddr_in sin,
143  *psin;
144  struct addrinfo hints;
145 
146 #ifdef WIN32
147 
148  /*
149  * If Windows has native IPv6 support, use the native Windows routine.
150  * Otherwise, fall through and use our own code.
151  */
152  if (haveNativeWindowsIPv6routines())
153  return (*getaddrinfo_ptr) (node, service, hintp, res);
154 #endif
155 
156  if (hintp == NULL)
157  {
158  memset(&hints, 0, sizeof(hints));
159  hints.ai_family = AF_INET;
160  hints.ai_socktype = SOCK_STREAM;
161  }
162  else
163  memcpy(&hints, hintp, sizeof(hints));
164 
165  if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
166  return EAI_FAMILY;
167 
168  if (hints.ai_socktype == 0)
169  hints.ai_socktype = SOCK_STREAM;
170 
171  if (!node && !service)
172  return EAI_NONAME;
173 
174  memset(&sin, 0, sizeof(sin));
175 
176  sin.sin_family = AF_INET;
177 
178  if (node)
179  {
180  if (node[0] == '\0')
181  sin.sin_addr.s_addr = htonl(INADDR_ANY);
182  else if (hints.ai_flags & AI_NUMERICHOST)
183  {
184  if (!inet_aton(node, &sin.sin_addr))
185  return EAI_NONAME;
186  }
187  else
188  {
189  struct hostent *hp;
190 
191 #ifdef FRONTEND
192  struct hostent hpstr;
193  char buf[BUFSIZ];
194  int herrno = 0;
195 
196  pqGethostbyname(node, &hpstr, buf, sizeof(buf),
197  &hp, &herrno);
198 #else
199  hp = gethostbyname(node);
200 #endif
201  if (hp == NULL)
202  {
203  switch (h_errno)
204  {
205  case HOST_NOT_FOUND:
206  case NO_DATA:
207  return EAI_NONAME;
208  case TRY_AGAIN:
209  return EAI_AGAIN;
210  case NO_RECOVERY:
211  default:
212  return EAI_FAIL;
213  }
214  }
215  if (hp->h_addrtype != AF_INET)
216  return EAI_FAIL;
217 
218  memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
219  }
220  }
221  else
222  {
223  if (hints.ai_flags & AI_PASSIVE)
224  sin.sin_addr.s_addr = htonl(INADDR_ANY);
225  else
226  sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
227  }
228 
229  if (service)
230  sin.sin_port = htons((unsigned short) atoi(service));
231 
232 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
233  sin.sin_len = sizeof(sin);
234 #endif
235 
236  ai = malloc(sizeof(*ai));
237  if (!ai)
238  return EAI_MEMORY;
239 
240  psin = malloc(sizeof(*psin));
241  if (!psin)
242  {
243  free(ai);
244  return EAI_MEMORY;
245  }
246 
247  memcpy(psin, &sin, sizeof(*psin));
248 
249  ai->ai_flags = 0;
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;
256  ai->ai_next = NULL;
257 
258  *res = ai;
259 
260  return 0;
261 }
262 
263 
264 void
265 freeaddrinfo(struct addrinfo *res)
266 {
267  if (res)
268  {
269 #ifdef WIN32
270 
271  /*
272  * If Windows has native IPv6 support, use the native Windows routine.
273  * Otherwise, fall through and use our own code.
274  */
275  if (haveNativeWindowsIPv6routines())
276  {
277  (*freeaddrinfo_ptr) (res);
278  return;
279  }
280 #endif
281 
282  if (res->ai_addr)
283  free(res->ai_addr);
284  free(res);
285  }
286 }
287 
288 
289 const char *
291 {
292 #ifdef HAVE_HSTRERROR
293  int hcode;
294 
295  switch (errcode)
296  {
297  case EAI_NONAME:
298  hcode = HOST_NOT_FOUND;
299  break;
300  case EAI_AGAIN:
301  hcode = TRY_AGAIN;
302  break;
303  case EAI_FAIL:
304  default:
305  hcode = NO_RECOVERY;
306  break;
307  }
308 
309  return hstrerror(hcode);
310 #else /* !HAVE_HSTRERROR */
311 
312  switch (errcode)
313  {
314  case EAI_NONAME:
315  return "Unknown host";
316  case EAI_AGAIN:
317  return "Host name lookup failure";
318  /* Errors below are probably WIN32 only */
319 #ifdef EAI_BADFLAGS
320  case EAI_BADFLAGS:
321  return "Invalid argument";
322 #endif
323 #ifdef EAI_FAMILY
324  case EAI_FAMILY:
325  return "Address family not supported";
326 #endif
327 #ifdef EAI_MEMORY
328  case EAI_MEMORY:
329  return "Not enough memory";
330 #endif
331 #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME /* MSVC/WIN64 duplicate */
332  case EAI_NODATA:
333  return "No host data of that type was found";
334 #endif
335 #ifdef EAI_SERVICE
336  case EAI_SERVICE:
337  return "Class type not found";
338 #endif
339 #ifdef EAI_SOCKTYPE
340  case EAI_SOCKTYPE:
341  return "Socket type not supported";
342 #endif
343  default:
344  return "Unknown server error";
345  }
346 #endif /* HAVE_HSTRERROR */
347 }
348 
349 /*
350  * Convert an ipv4 address to a hostname.
351  *
352  * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV behavior.
353  * It will never resolve a hostname.
354  * - No IPv6 support.
355  */
356 int
357 getnameinfo(const struct sockaddr *sa, int salen,
358  char *node, int nodelen,
359  char *service, int servicelen, int flags)
360 {
361 #ifdef WIN32
362 
363  /*
364  * If Windows has native IPv6 support, use the native Windows routine.
365  * Otherwise, fall through and use our own code.
366  */
367  if (haveNativeWindowsIPv6routines())
368  return (*getnameinfo_ptr) (sa, salen, node, nodelen,
369  service, servicelen, flags);
370 #endif
371 
372  /* Invalid arguments. */
373  if (sa == NULL || (node == NULL && service == NULL))
374  return EAI_FAIL;
375 
376 #ifdef HAVE_IPV6
377  if (sa->sa_family == AF_INET6)
378  return EAI_FAMILY;
379 #endif
380 
381  /* Unsupported flags. */
382  if (flags & NI_NAMEREQD)
383  return EAI_AGAIN;
384 
385  if (node)
386  {
387  if (sa->sa_family == AF_INET)
388  {
389  if (inet_net_ntop(AF_INET, &((struct sockaddr_in *) sa)->sin_addr,
390  sa->sa_family == AF_INET ? 32 : 128,
391  node, nodelen) == NULL)
392  return EAI_MEMORY;
393  }
394  else
395  return EAI_MEMORY;
396  }
397 
398  if (service)
399  {
400  int ret = -1;
401 
402  if (sa->sa_family == AF_INET)
403  {
404  ret = snprintf(service, servicelen, "%d",
405  ntohs(((struct sockaddr_in *) sa)->sin_port));
406  }
407  if (ret == -1 || ret >= servicelen)
408  return EAI_MEMORY;
409  }
410 
411  return 0;
412 }
#define NI_NAMEREQD
Definition: getaddrinfo.h:84
int pqGethostbyname(const char *name, struct hostent *resultbuf, char *buffer, size_t buflen, struct hostent **result, int *herrno)
Definition: thread.c:117
#define EAI_FAIL
Definition: getaddrinfo.h:36
const char * gai_strerror(int errcode)
Definition: getaddrinfo.c:290
int errcode(int sqlerrcode)
Definition: elog.c:575
#define EAI_FAMILY
Definition: getaddrinfo.h:37
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void freeaddrinfo(struct addrinfo *res)
Definition: getaddrinfo.c:265
#define AI_NUMERICHOST
Definition: getaddrinfo.h:73
#define EAI_BADFLAGS
Definition: getaddrinfo.h:33
#define EAI_SOCKTYPE
Definition: getaddrinfo.h:38
#define malloc(a)
Definition: header.h:50
#define EAI_AGAIN
Definition: getaddrinfo.h:35
char * ai_canonname
Definition: getaddrinfo.h:106
#define EAI_SERVICE
Definition: getaddrinfo.h:39
static char * buf
Definition: pg_test_fsync.c:66
#define AI_PASSIVE
Definition: getaddrinfo.h:62
#define EAI_NONAME
Definition: getaddrinfo.h:34
int getnameinfo(const struct sockaddr *sa, int salen, char *node, int nodelen, char *service, int servicelen, int flags)
Definition: getaddrinfo.c:357
char * inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
Definition: inet_net_ntop.c:77
int inet_aton(const char *cp, struct in_addr *addr)
Definition: inet_aton.c:54
#define free(a)
Definition: header.h:65
int ai_protocol
Definition: getaddrinfo.h:103
#define NULL
Definition: c.h:229
int ai_socktype
Definition: getaddrinfo.h:102
struct addrinfo * ai_next
Definition: getaddrinfo.h:107
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hintp, struct addrinfo **res)
Definition: getaddrinfo.c:137
size_t ai_addrlen
Definition: getaddrinfo.h:104
#define EAI_MEMORY
Definition: getaddrinfo.h:40
int ai_flags
Definition: getaddrinfo.h:100
struct sockaddr * ai_addr
Definition: getaddrinfo.h:105
int ai_family
Definition: getaddrinfo.h:101