OSDN Git Service

Update a number of broken links in comments.
[pg-rex/syncrep.git] / src / port / getaddrinfo.c
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-2010, PostgreSQL Global Development Group
17  *
18  * IDENTIFICATION
19  *        $PostgreSQL: pgsql/src/port/getaddrinfo.c,v 1.30 2010/01/02 16:58:13 momjian Exp $
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_FAIL;
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 *
290 gai_strerror(int errcode)
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 #ifdef EAI_NODATA
332 #ifndef WIN32_ONLY_COMPILER             /* MSVC complains because another case has the
333                                                                  * same value */
334                 case EAI_NODATA:
335                         return "No host data of that type was found";
336 #endif
337 #endif
338 #ifdef EAI_SERVICE
339                 case EAI_SERVICE:
340                         return "Class type not found";
341 #endif
342 #ifdef EAI_SOCKTYPE
343                 case EAI_SOCKTYPE:
344                         return "Socket type not supported";
345 #endif
346                 default:
347                         return "Unknown server error";
348         }
349 #endif   /* HAVE_HSTRERROR */
350 }
351
352 /*
353  * Convert an ipv4 address to a hostname.
354  *
355  * Bugs:        - Only supports NI_NUMERICHOST and NI_NUMERICSERV
356  *                It will never resolv a hostname.
357  *              - No IPv6 support.
358  */
359 int
360 getnameinfo(const struct sockaddr * sa, int salen,
361                         char *node, int nodelen,
362                         char *service, int servicelen, int flags)
363 {
364 #ifdef WIN32
365
366         /*
367          * If Windows has native IPv6 support, use the native Windows routine.
368          * Otherwise, fall through and use our own code.
369          */
370         if (haveNativeWindowsIPv6routines())
371                 return (*getnameinfo_ptr) (sa, salen, node, nodelen,
372                                                                    service, servicelen, flags);
373 #endif
374
375         /* Invalid arguments. */
376         if (sa == NULL || (node == NULL && service == NULL))
377                 return EAI_FAIL;
378
379         /* We don't support those. */
380         if ((node && !(flags & NI_NUMERICHOST))
381                 || (service && !(flags & NI_NUMERICSERV)))
382                 return EAI_FAIL;
383
384 #ifdef  HAVE_IPV6
385         if (sa->sa_family == AF_INET6)
386                 return EAI_FAMILY;
387 #endif
388
389         if (node)
390         {
391                 int                     ret = -1;
392
393                 if (sa->sa_family == AF_INET)
394                 {
395                         char       *p;
396
397                         p = inet_ntoa(((struct sockaddr_in *) sa)->sin_addr);
398                         ret = snprintf(node, nodelen, "%s", p);
399                 }
400                 if (ret == -1 || ret > nodelen)
401                         return EAI_MEMORY;
402         }
403
404         if (service)
405         {
406                 int                     ret = -1;
407
408                 if (sa->sa_family == AF_INET)
409                 {
410                         ret = snprintf(service, servicelen, "%d",
411                                                    ntohs(((struct sockaddr_in *) sa)->sin_port));
412                 }
413                 if (ret == -1 || ret > servicelen)
414                         return EAI_MEMORY;
415         }
416
417         return 0;
418 }