Header And Logo

PostgreSQL
| The world's most advanced open source database.

getaddrinfo.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * getaddrinfo.c
00004  *    Support getaddrinfo() on platforms that don't have it.
00005  *
00006  * We also supply getnameinfo() here, assuming that the platform will have
00007  * it if and only if it has getaddrinfo().  If this proves false on some
00008  * platform, we'll need to split this file and provide a separate configure
00009  * test for getnameinfo().
00010  *
00011  * Windows may or may not have these routines, so we handle Windows specially
00012  * by dynamically checking for their existence.  If they already exist, we
00013  * use the Windows native routines, but if not, we use our own.
00014  *
00015  *
00016  * Copyright (c) 2003-2013, PostgreSQL Global Development Group
00017  *
00018  * IDENTIFICATION
00019  *    src/port/getaddrinfo.c
00020  *
00021  *-------------------------------------------------------------------------
00022  */
00023 
00024 /* This is intended to be used in both frontend and backend, so use c.h */
00025 #include "c.h"
00026 
00027 #include <sys/socket.h>
00028 #include <netdb.h>
00029 #include <netinet/in.h>
00030 #include <arpa/inet.h>
00031 
00032 #include "getaddrinfo.h"
00033 #include "libpq/pqcomm.h"       /* needed for struct sockaddr_storage */
00034 
00035 
00036 #ifdef WIN32
00037 /*
00038  * The native routines may or may not exist on the Windows platform we are on,
00039  * so we dynamically look up the routines, and call them via function pointers.
00040  * Here we need to declare what the function pointers look like
00041  */
00042 typedef int (__stdcall * getaddrinfo_ptr_t) (const char *nodename,
00043                                                          const char *servname,
00044                                                const struct addrinfo * hints,
00045                                                      struct addrinfo ** res);
00046 
00047 typedef void (__stdcall * freeaddrinfo_ptr_t) (struct addrinfo * ai);
00048 
00049 typedef int (__stdcall * getnameinfo_ptr_t) (const struct sockaddr * sa,
00050                                                          int salen,
00051                                                      char *host, int hostlen,
00052                                                      char *serv, int servlen,
00053                                                          int flags);
00054 
00055 /* static pointers to the native routines, so we only do the lookup once. */
00056 static getaddrinfo_ptr_t getaddrinfo_ptr = NULL;
00057 static freeaddrinfo_ptr_t freeaddrinfo_ptr = NULL;
00058 static getnameinfo_ptr_t getnameinfo_ptr = NULL;
00059 
00060 
00061 static bool
00062 haveNativeWindowsIPv6routines(void)
00063 {
00064     void       *hLibrary = NULL;
00065     static bool alreadyLookedForIpv6routines = false;
00066 
00067     if (alreadyLookedForIpv6routines)
00068         return (getaddrinfo_ptr != NULL);
00069 
00070     /*
00071      * For Windows XP and Windows 2003 (and longhorn/vista), the IPv6 routines
00072      * are present in the WinSock 2 library (ws2_32.dll). Try that first
00073      */
00074 
00075     hLibrary = LoadLibraryA("ws2_32");
00076 
00077     if (hLibrary == NULL || GetProcAddress(hLibrary, "getaddrinfo") == NULL)
00078     {
00079         /*
00080          * Well, ws2_32 doesn't exist, or more likely doesn't have
00081          * getaddrinfo.
00082          */
00083         if (hLibrary != NULL)
00084             FreeLibrary(hLibrary);
00085 
00086         /*
00087          * In Windows 2000, there was only the IPv6 Technology Preview look in
00088          * the IPv6 WinSock library (wship6.dll).
00089          */
00090 
00091         hLibrary = LoadLibraryA("wship6");
00092     }
00093 
00094     /* If hLibrary is null, we couldn't find a dll with functions */
00095     if (hLibrary != NULL)
00096     {
00097         /* We found a dll, so now get the addresses of the routines */
00098 
00099         getaddrinfo_ptr = (getaddrinfo_ptr_t) GetProcAddress(hLibrary,
00100                                                              "getaddrinfo");
00101         freeaddrinfo_ptr = (freeaddrinfo_ptr_t) GetProcAddress(hLibrary,
00102                                                              "freeaddrinfo");
00103         getnameinfo_ptr = (getnameinfo_ptr_t) GetProcAddress(hLibrary,
00104                                                              "getnameinfo");
00105 
00106         /*
00107          * If any one of the routines is missing, let's play it safe and
00108          * ignore them all
00109          */
00110         if (getaddrinfo_ptr == NULL ||
00111             freeaddrinfo_ptr == NULL ||
00112             getnameinfo_ptr == NULL)
00113         {
00114             FreeLibrary(hLibrary);
00115             hLibrary = NULL;
00116             getaddrinfo_ptr = NULL;
00117             freeaddrinfo_ptr = NULL;
00118             getnameinfo_ptr = NULL;
00119         }
00120     }
00121 
00122     alreadyLookedForIpv6routines = true;
00123     return (getaddrinfo_ptr != NULL);
00124 }
00125 #endif
00126 
00127 
00128 /*
00129  * get address info for ipv4 sockets.
00130  *
00131  *  Bugs:   - only one addrinfo is set even though hintp is NULL or
00132  *        ai_socktype is 0
00133  *      - AI_CANONNAME is not supported.
00134  *      - servname can only be a number, not text.
00135  */
00136 int
00137 getaddrinfo(const char *node, const char *service,
00138             const struct addrinfo * hintp,
00139             struct addrinfo ** res)
00140 {
00141     struct addrinfo *ai;
00142     struct sockaddr_in sin,
00143                *psin;
00144     struct addrinfo hints;
00145 
00146 #ifdef WIN32
00147 
00148     /*
00149      * If Windows has native IPv6 support, use the native Windows routine.
00150      * Otherwise, fall through and use our own code.
00151      */
00152     if (haveNativeWindowsIPv6routines())
00153         return (*getaddrinfo_ptr) (node, service, hintp, res);
00154 #endif
00155 
00156     if (hintp == NULL)
00157     {
00158         memset(&hints, 0, sizeof(hints));
00159         hints.ai_family = AF_INET;
00160         hints.ai_socktype = SOCK_STREAM;
00161     }
00162     else
00163         memcpy(&hints, hintp, sizeof(hints));
00164 
00165     if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
00166         return EAI_FAMILY;
00167 
00168     if (hints.ai_socktype == 0)
00169         hints.ai_socktype = SOCK_STREAM;
00170 
00171     if (!node && !service)
00172         return EAI_NONAME;
00173 
00174     memset(&sin, 0, sizeof(sin));
00175 
00176     sin.sin_family = AF_INET;
00177 
00178     if (node)
00179     {
00180         if (node[0] == '\0')
00181             sin.sin_addr.s_addr = htonl(INADDR_ANY);
00182         else if (hints.ai_flags & AI_NUMERICHOST)
00183         {
00184             if (!inet_aton(node, &sin.sin_addr))
00185                 return EAI_FAIL;
00186         }
00187         else
00188         {
00189             struct hostent *hp;
00190 
00191 #ifdef FRONTEND
00192             struct hostent hpstr;
00193             char        buf[BUFSIZ];
00194             int         herrno = 0;
00195 
00196             pqGethostbyname(node, &hpstr, buf, sizeof(buf),
00197                             &hp, &herrno);
00198 #else
00199             hp = gethostbyname(node);
00200 #endif
00201             if (hp == NULL)
00202             {
00203                 switch (h_errno)
00204                 {
00205                     case HOST_NOT_FOUND:
00206                     case NO_DATA:
00207                         return EAI_NONAME;
00208                     case TRY_AGAIN:
00209                         return EAI_AGAIN;
00210                     case NO_RECOVERY:
00211                     default:
00212                         return EAI_FAIL;
00213                 }
00214             }
00215             if (hp->h_addrtype != AF_INET)
00216                 return EAI_FAIL;
00217 
00218             memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
00219         }
00220     }
00221     else
00222     {
00223         if (hints.ai_flags & AI_PASSIVE)
00224             sin.sin_addr.s_addr = htonl(INADDR_ANY);
00225         else
00226             sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00227     }
00228 
00229     if (service)
00230         sin.sin_port = htons((unsigned short) atoi(service));
00231 
00232 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
00233     sin.sin_len = sizeof(sin);
00234 #endif
00235 
00236     ai = malloc(sizeof(*ai));
00237     if (!ai)
00238         return EAI_MEMORY;
00239 
00240     psin = malloc(sizeof(*psin));
00241     if (!psin)
00242     {
00243         free(ai);
00244         return EAI_MEMORY;
00245     }
00246 
00247     memcpy(psin, &sin, sizeof(*psin));
00248 
00249     ai->ai_flags = 0;
00250     ai->ai_family = AF_INET;
00251     ai->ai_socktype = hints.ai_socktype;
00252     ai->ai_protocol = hints.ai_protocol;
00253     ai->ai_addrlen = sizeof(*psin);
00254     ai->ai_addr = (struct sockaddr *) psin;
00255     ai->ai_canonname = NULL;
00256     ai->ai_next = NULL;
00257 
00258     *res = ai;
00259 
00260     return 0;
00261 }
00262 
00263 
00264 void
00265 freeaddrinfo(struct addrinfo * res)
00266 {
00267     if (res)
00268     {
00269 #ifdef WIN32
00270 
00271         /*
00272          * If Windows has native IPv6 support, use the native Windows routine.
00273          * Otherwise, fall through and use our own code.
00274          */
00275         if (haveNativeWindowsIPv6routines())
00276         {
00277             (*freeaddrinfo_ptr) (res);
00278             return;
00279         }
00280 #endif
00281 
00282         if (res->ai_addr)
00283             free(res->ai_addr);
00284         free(res);
00285     }
00286 }
00287 
00288 
00289 const char *
00290 gai_strerror(int errcode)
00291 {
00292 #ifdef HAVE_HSTRERROR
00293     int         hcode;
00294 
00295     switch (errcode)
00296     {
00297         case EAI_NONAME:
00298             hcode = HOST_NOT_FOUND;
00299             break;
00300         case EAI_AGAIN:
00301             hcode = TRY_AGAIN;
00302             break;
00303         case EAI_FAIL:
00304         default:
00305             hcode = NO_RECOVERY;
00306             break;
00307     }
00308 
00309     return hstrerror(hcode);
00310 #else                           /* !HAVE_HSTRERROR */
00311 
00312     switch (errcode)
00313     {
00314         case EAI_NONAME:
00315             return "Unknown host";
00316         case EAI_AGAIN:
00317             return "Host name lookup failure";
00318             /* Errors below are probably WIN32 only */
00319 #ifdef EAI_BADFLAGS
00320         case EAI_BADFLAGS:
00321             return "Invalid argument";
00322 #endif
00323 #ifdef EAI_FAMILY
00324         case EAI_FAMILY:
00325             return "Address family not supported";
00326 #endif
00327 #ifdef EAI_MEMORY
00328         case EAI_MEMORY:
00329             return "Not enough memory";
00330 #endif
00331 #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME     /* MSVC/WIN64 duplicate */
00332         case EAI_NODATA:
00333             return "No host data of that type was found";
00334 #endif
00335 #ifdef EAI_SERVICE
00336         case EAI_SERVICE:
00337             return "Class type not found";
00338 #endif
00339 #ifdef EAI_SOCKTYPE
00340         case EAI_SOCKTYPE:
00341             return "Socket type not supported";
00342 #endif
00343         default:
00344             return "Unknown server error";
00345     }
00346 #endif   /* HAVE_HSTRERROR */
00347 }
00348 
00349 /*
00350  * Convert an ipv4 address to a hostname.
00351  *
00352  * Bugs:    - Only supports NI_NUMERICHOST and NI_NUMERICSERV
00353  *        It will never resolv a hostname.
00354  *      - No IPv6 support.
00355  */
00356 int
00357 getnameinfo(const struct sockaddr * sa, int salen,
00358             char *node, int nodelen,
00359             char *service, int servicelen, int flags)
00360 {
00361 #ifdef WIN32
00362 
00363     /*
00364      * If Windows has native IPv6 support, use the native Windows routine.
00365      * Otherwise, fall through and use our own code.
00366      */
00367     if (haveNativeWindowsIPv6routines())
00368         return (*getnameinfo_ptr) (sa, salen, node, nodelen,
00369                                    service, servicelen, flags);
00370 #endif
00371 
00372     /* Invalid arguments. */
00373     if (sa == NULL || (node == NULL && service == NULL))
00374         return EAI_FAIL;
00375 
00376 #ifdef  HAVE_IPV6
00377     if (sa->sa_family == AF_INET6)
00378         return EAI_FAMILY;
00379 #endif
00380 
00381     if (node)
00382     {
00383         if (sa->sa_family == AF_INET)
00384         {
00385             if (inet_net_ntop(AF_INET, &((struct sockaddr_in *) sa)->sin_addr,
00386                               sa->sa_family == AF_INET ? 32 : 128,
00387                               node, nodelen) == NULL)
00388                 return EAI_MEMORY;
00389         }
00390         else
00391             return EAI_MEMORY;
00392     }
00393 
00394     if (service)
00395     {
00396         int         ret = -1;
00397 
00398         if (sa->sa_family == AF_INET)
00399         {
00400             ret = snprintf(service, servicelen, "%d",
00401                            ntohs(((struct sockaddr_in *) sa)->sin_port));
00402         }
00403         if (ret == -1 || ret > servicelen)
00404             return EAI_MEMORY;
00405     }
00406 
00407     return 0;
00408 }