00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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"
00034
00035
00036 #ifdef WIN32
00037
00038
00039
00040
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
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
00072
00073
00074
00075 hLibrary = LoadLibraryA("ws2_32");
00076
00077 if (hLibrary == NULL || GetProcAddress(hLibrary, "getaddrinfo") == NULL)
00078 {
00079
00080
00081
00082
00083 if (hLibrary != NULL)
00084 FreeLibrary(hLibrary);
00085
00086
00087
00088
00089
00090
00091 hLibrary = LoadLibraryA("wship6");
00092 }
00093
00094
00095 if (hLibrary != NULL)
00096 {
00097
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
00108
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
00130
00131
00132
00133
00134
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
00150
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
00273
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
00311
00312 switch (errcode)
00313 {
00314 case EAI_NONAME:
00315 return "Unknown host";
00316 case EAI_AGAIN:
00317 return "Host name lookup failure";
00318
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
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
00347 }
00348
00349
00350
00351
00352
00353
00354
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
00365
00366
00367 if (haveNativeWindowsIPv6routines())
00368 return (*getnameinfo_ptr) (sa, salen, node, nodelen,
00369 service, servicelen, flags);
00370 #endif
00371
00372
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 }