libpqtypes - port.c

Home Page

array.c
datetime.c
error.c
events.c
exec.c
geo.c
getaddrinfo.h
handler.c
libpqtypes-int.h
libpqtypes.h
misc.c
network.c
numerics.c
param.c
port.c
record.c
regression-test.c
spec.c
utils.c
varlena.c
  1 
  2 /*
  3  * port.c
  4  *   Portability functions.  Some of these functions are drop-ins for
  5  *   systems missing them and others just centralize differences.
  6  *
  7  * Copyright (c) 2011 eSilo, LLC. All rights reserved.
  8  * This is free software; see the source for copying conditions.  There is
  9  * NO warranty; not even for MERCHANTABILITY or  FITNESS FOR A  PARTICULAR
 10  * PURPOSE.
 11  */
 12 
 13 #include "libpqtypes-int.h"
 14 
 15 #if defined(__MINGW32__) || defined(__CYGWIN__)
 16 # define HAVE_VSNPRINTF
 17 #endif
 18 
 19 int
 20 pqt_snprintf(char *buf, size_t size, const char *format, ...)
 21 {
 22   int n;
 23   va_list ap;
 24   va_start(ap, format);
 25   n = pqt_vsnprintf(buf, size, format, ap);
 26   va_end(ap);
 27   return n;
 28 }
 29 
 30 int
 31 pqt_vsnprintf(char *buf, size_t size, const char *format, va_list ap)
 32 {
 33   int n;
 34 
 35 #ifdef PQT_MSVC
 36 # if PQT_MSVC >= 1400
 37   /* MSVC 8 */
 38   n = _vsnprintf_s(buf, size, size-1, format, ap);
 39 # else
 40   /* MSVC 6 or 7 */
 41   n = _vsnprintf(buf, size, format, ap);
 42 # endif
 43 
 44 #elif defined(HAVE_VSNPRINTF)
 45   /* All other platforms, including MinGW and Cygwin. */
 46   n = vsnprintf(buf, size, format, ap);
 47 #else
 48   /* Some platforms don't have the buffer-safe version */
 49   n = vsprintf(buf, format, ap);
 50 #endif
 51 
 52   if (n > -1 && (size_t) n < size)
 53     return n;
 54 
 55   /* Although some implementations return "required" buf size, this
 56    * always return -1 to keep things consistent for caller.
 57    */
 58   return -1;
 59 }
 60 
 61 #if defined(HAVE_CONFIG_H) && (!defined(HAVE_STRTOL) || \
 62   !defined(HAVE_STRTOUL))
 63 
 64 static unsigned long string2long(const char *nptr, char **endptr,
 65   int base, int is_signed);
 66 
 67 #ifndef HAVE_STRTOL
 68 long
 69 strtol(const char *nptr, char **endptr, int base)
 70 {
 71   return (signed long) string2long(nptr, endptr, base, 1);
 72 }
 73 #endif
 74 
 75 #ifndef HAVE_STRTOUL
 76 unsigned long
 77 strtoul(const char *nptr, char **endptr, int base)
 78 {
 79   return (unsigned long) string2long(nptr, endptr, base, 0);
 80 }
 81 #endif
 82 
 83 #define between(a, c, z) \
 84   ((unsigned) ((c) - (a)) <= (unsigned) ((z) - (a)))
 85 
 86 static unsigned long
 87 string2long(const char *nptr, char ** const endptr,
 88   int base, int is_signed)
 89 {
 90   unsigned int v;
 91   unsigned long val = 0;
 92   int c;
 93   int ovfl = 0, sign = 1;
 94   const char *startnptr = nptr, *nrstart;
 95 
 96   if (endptr)
 97     *endptr = (char *) nptr;
 98 
 99   while (isspace(*nptr))
100     nptr++;
101   c = *nptr;
102 
103   if (c == '-' || c == '+')
104   {
105     if (c == '-')
106       sign = -1;
107     nptr++;
108   }
109   nrstart = nptr; /* start of the number */
110 
111   /* When base is 0, the syntax determines the actual base */
112   if (base == 0)
113   {
114     if (*nptr == '0')
115     {
116       if (*++nptr == 'x' || *nptr == 'X')
117       {
118         base = 16;
119         nptr++;
120       }
121       else
122       {
123         base = 8;
124       }
125     }
126     else
127     {
128       base = 10;
129     }
130   }
131   else if (base==16 && *nptr=='0' && (*++nptr =='x' || *nptr =='X'))
132   {
133     nptr++;
134   }
135 
136   for (;;)
137   {
138     c = *nptr;
139     if (between('0', c, '9'))
140       v = c - '0';
141     else if (between('a', c, 'z'))
142       v = c - 'a' + 0xa;
143     else if (between('A', c, 'Z'))
144       v = c - 'A' + 0xA;
145     else
146       break;
147 
148     if (v >= base)
149       break;
150     if (val > (ULONG_MAX - v) / base)
151       ovfl++;
152 
153     val = (val * base) + v;
154     nptr++;
155   }
156 
157   if (endptr)
158   {
159     if (nrstart == nptr)
160       *endptr = (char *) startnptr;
161     else
162       *endptr = (char *) nptr;
163   }
164 
165   if (!ovfl)
166   {
167     /* Overflow is only possible when converting a signed long. */
168     if (is_signed && ((sign < 0 && val > -(unsigned long) LONG_MIN)
169         || (sign > 0 && val > LONG_MAX)))
170       ovfl++;
171   }
172 
173   if (ovfl)
174   {
175     errno = ERANGE;
176     if (is_signed)
177     {
178       if (sign < 0)
179         return LONG_MIN;
180       else
181         return LONG_MAX;
182     }
183     else
184     {
185       return ULONG_MAX;
186     }
187   }
188 
189   return (long) sign * val;
190 }
191 
192 #endif /* !strtol || !strtoul */
193 
194 
195 /* Non-windows platforms that don't have strtoll */
196 #if defined(HAVE_CONFIG_H) && !defined(HAVE_STRTOLL)
197 
198 #define MIN_INT64 (-MAX_INT64 - PQT_INT64CONST(1))
199 #define MAX_INT64 PQT_INT64CONST(9223372036854775807)
200 
201 /* no locale support */
202 long long int
203 strtoll(const char *nptr, char **endptr, int base)
204 {
205   const char *s;
206   /* LONGLONG */
207   long long int acc, cutoff;
208   int c;
209   int neg, any, cutlim;
210 
211   /* endptr may be NULL */
212 
213 #ifdef __GNUC__
214   /* This outrageous construct just to shut up a GCC warning. */
215   (void) &acc; (void) &cutoff;
216 #endif
217 
218   /*
219    * Skip white space and pick up leading +/- sign if any.
220    * If base is 0, allow 0x for hex and 0 for octal, else
221    * assume decimal; if base is already 16, allow 0x.
222    */
223   s = nptr;
224   do {
225     c = (unsigned char) *s++;
226   } while (isspace(c));
227   if (c == '-') {
228     neg = 1;
229     c = *s++;
230   } else {
231     neg = 0;
232     if (c == '+')
233       c = *s++;
234   }
235   if ((base == 0 || base == 16) &&
236       c == '0' && (*s == 'x' || *s == 'X')) {
237     c = s[1];
238     s += 2;
239     base = 16;
240   }
241   if (base == 0)
242     base = c == '0' ? 8 : 10;
243 
244   /*
245    * Compute the cutoff value between legal numbers and illegal
246    * numbers.  That is the largest legal value, divided by the
247    * base.  An input number that is greater than this value, if
248    * followed by a legal input character, is too big.  One that
249    * is equal to this value may be valid or not; the limit
250    * between valid and invalid numbers is then based on the last
251    * digit.  For instance, if the range for long longs is
252    * [-9223372036854775808..9223372036854775807] and the input base
253    * is 10, cutoff will be set to 922337203685477580 and cutlim to
254    * either 7 (neg==0) or 8 (neg==1), meaning that if we have
255    * accumulated a value > 922337203685477580, or equal but the
256    * next digit is > 7 (or 8), the number is too big, and we will
257    * return a range error.
258    *
259    * Set any if any `digits' consumed; make it negative to indicate
260    * overflow.
261    */
262   cutoff = neg ? MIN_INT64 : MAX_INT64;
263   cutlim = (int) (cutoff % base);
264   cutoff /= base;
265   if (neg) {
266     if (cutlim > 0) {
267       cutlim -= base;
268       cutoff += 1;
269     }
270     cutlim = -cutlim;
271   }
272   for (acc = 0, any = 0;; c = (unsigned char) *s++) {
273     if (isdigit(c))
274       c -= '0';
275     else if (isalpha(c))
276       c -= isupper(c) ? 'A' - 10 : 'a' - 10;
277     else
278       break;
279     if (c >= base)
280       break;
281     if (any < 0)
282       continue;
283     if (neg) {
284       if (acc < cutoff || (acc == cutoff && c > cutlim)) {
285         any = -1;
286         acc = MIN_INT64;
287         errno = ERANGE;
288       } else {
289         any = 1;
290         acc *= base;
291         acc -= c;
292       }
293     } else {
294       if (acc > cutoff || (acc == cutoff && c > cutlim)) {
295         any = -1;
296         acc = MAX_INT64;
297         errno = ERANGE;
298       } else {
299         any = 1;
300         acc *= base;
301         acc += c;
302       }
303     }
304   }
305   if (endptr != 0)
306     /* LINTED interface specification */
307     *endptr = (char *) (any ? s - 1 : nptr);
308   return (acc);
309 }
310 
311 #endif /* !HAVE_STRTOLL */
312 
313 
314 /* Non-windows machines missing getaddrinfo (postgres's port) */
315 #if defined(__CYGWIN__) || (defined(HAVE_CONFIG_H) && \
316   !defined(HAVE_GETADDRINFO))
317 #undef FRONTEND
318 #include <sys/socket.h>
319 #include <netdb.h>
320 #include <netinet/in.h>
321 #include <arpa/inet.h>
322 
323 #include "getaddrinfo.h"
324 
325 extern int h_errno;
326 
327 /*
328  * get address info for ipv4 sockets.
329  *
330  *  Bugs: - only one addrinfo is set even though hintp is NULL or
331  *      ai_socktype is 0
332  *    - AI_CANONNAME is not supported.
333  *    - servname can only be a number, not text.
334  */
335 int
336 getaddrinfo(const char *node, const char *service,
337       const struct addrinfo * hintp,
338       struct addrinfo ** res)
339 {
340   struct addrinfo *ai;
341   struct sockaddr_in sin,
342          *psin;
343   struct addrinfo hints;
344 
345   if (hintp == NULL)
346   {
347     memset(&hints, 0, sizeof(hints));
348     hints.ai_family = AF_INET;
349     hints.ai_socktype = SOCK_STREAM;
350   }
351   else
352     memcpy(&hints, hintp, sizeof(hints));
353 
354   if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC)
355     return EAI_FAMILY;
356 
357   if (hints.ai_socktype == 0)
358     hints.ai_socktype = SOCK_STREAM;
359 
360   if (!node && !service)
361     return EAI_NONAME;
362 
363   memset(&sin, 0, sizeof(sin));
364 
365   sin.sin_family = AF_INET;
366 
367   if (node)
368   {
369     if (node[0] == '\0')
370       sin.sin_addr.s_addr = htonl(INADDR_ANY);
371     else if (hints.ai_flags & AI_NUMERICHOST)
372     {
373       if (!inet_aton(node, &sin.sin_addr))
374         return EAI_FAIL;
375     }
376     else
377     {
378       struct hostent *hp;
379 
380 #ifdef FRONTEND
381       struct hostent hpstr;
382       char    buf[BUFSIZ];
383       int     herrno = 0;
384 
385       pqGethostbyname(node, &hpstr, buf, sizeof(buf),
386               &hp, &herrno);
387 #else
388       hp = gethostbyname(node);
389 #endif
390       if (hp == NULL)
391       {
392         switch (h_errno)
393         {
394           case HOST_NOT_FOUND:
395           case NO_DATA:
396             return EAI_NONAME;
397           case TRY_AGAIN:
398             return EAI_AGAIN;
399           case NO_RECOVERY:
400           default:
401             return EAI_FAIL;
402         }
403       }
404       if (hp->h_addrtype != AF_INET)
405         return EAI_FAIL;
406 
407       memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
408     }
409   }
410   else
411   {
412     if (hints.ai_flags & AI_PASSIVE)
413       sin.sin_addr.s_addr = htonl(INADDR_ANY);
414     else
415       sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
416   }
417 
418   if (service)
419     sin.sin_port = htons((unsigned short) atoi(service));
420 
421 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
422   sin.sin_len = sizeof(sin);
423 #endif
424 
425   ai = malloc(sizeof(*ai));
426   if (!ai)
427     return EAI_MEMORY;
428 
429   psin = malloc(sizeof(*psin));
430   if (!psin)
431   {
432     free(ai);
433     return EAI_MEMORY;
434   }
435 
436   memcpy(psin, &sin, sizeof(*psin));
437 
438   ai->ai_flags = 0;
439   ai->ai_family = AF_INET;
440   ai->ai_socktype = hints.ai_socktype;
441   ai->ai_protocol = hints.ai_protocol;
442   ai->ai_addrlen = sizeof(*psin);
443   ai->ai_addr = (struct sockaddr *) psin;
444   ai->ai_canonname = NULL;
445   ai->ai_next = NULL;
446 
447   *res = ai;
448 
449   return 0;
450 }
451 
452 
453 void
454 freeaddrinfo(struct addrinfo * res)
455 {
456   if (res)
457   {
458     if (res->ai_addr)
459       free(res->ai_addr);
460     free(res);
461   }
462 }
463 
464 
465 const char *
466 gai_strerror(int errcode)
467 {
468 #ifdef HAVE_HSTRERROR
469   int     hcode;
470 
471   switch (errcode)
472   {
473     case EAI_NONAME:
474       hcode = HOST_NOT_FOUND;
475       break;
476     case EAI_AGAIN:
477       hcode = TRY_AGAIN;
478       break;
479     case EAI_FAIL:
480     default:
481       hcode = NO_RECOVERY;
482       break;
483   }
484 
485   return hstrerror(hcode);
486 #else             /* !HAVE_HSTRERROR */
487 
488   switch (errcode)
489   {
490     case EAI_NONAME:
491       return "Unknown host";
492     case EAI_AGAIN:
493       return "Host name lookup failure";
494       /* Errors below are probably WIN32 only */
495 #ifdef EAI_BADFLAGS
496     case EAI_BADFLAGS:
497       return "Invalid argument";
498 #endif
499 #ifdef EAI_FAMILY
500     case EAI_FAMILY:
501       return "Address family not supported";
502 #endif
503 #ifdef EAI_MEMORY
504     case EAI_MEMORY:
505       return "Not enough memory";
506 #endif
507 #ifdef EAI_NODATA
508 #ifndef WIN32_ONLY_COMPILER   /* MSVC complains because another case has the
509                  * same value */
510     case EAI_NODATA:
511       return "No host data of that type was found";
512 #endif
513 #endif
514 #ifdef EAI_SERVICE
515     case EAI_SERVICE:
516       return "Class type not found";
517 #endif
518 #ifdef EAI_SOCKTYPE
519     case EAI_SOCKTYPE:
520       return "Socket type not supported";
521 #endif
522     default:
523       return "Unknown server error";
524   }
525 #endif   /* HAVE_HSTRERROR */
526 }
527 
528 /*
529  * Convert an ipv4 address to a hostname.
530  *
531  * Bugs:  - Only supports NI_NUMERICHOST and NI_NUMERICSERV
532  *      It will never resolv a hostname.
533  *    - No IPv6 support.
534  */
535 int
536 getnameinfo(const struct sockaddr * sa, int salen,
537       char *node, int nodelen,
538       char *service, int servicelen, int flags)
539 {
540   /* Invalid arguments. */
541   if (sa == NULL || (node == NULL && service == NULL))
542     return EAI_FAIL;
543 
544   /* We don't support those. */
545   if ((node && !(flags & NI_NUMERICHOST))
546     || (service && !(flags & NI_NUMERICSERV)))
547     return EAI_FAIL;
548 
549 #if defined(HAVE_IPV6) || defined(AF_INET6)
550   if (sa->sa_family == AF_INET6)
551     return EAI_FAMILY;
552 #endif
553 
554   if (node)
555   {
556     int     ret = -1;
557 
558     if (sa->sa_family == AF_INET)
559     {
560       char     *p;
561 
562       p = inet_ntoa(((struct sockaddr_in *) sa)->sin_addr);
563       ret = pqt_snprintf(node, nodelen, "%s", p);
564     }
565     if (ret == -1)
566       return EAI_MEMORY;
567   }
568 
569   if (service)
570   {
571     int     ret = -1;
572 
573     if (sa->sa_family == AF_INET)
574     {
575       ret = pqt_snprintf(service, servicelen, "%d",
576                ntohs(((struct sockaddr_in *) sa)->sin_port));
577     }
578     if (ret == -1)
579       return EAI_MEMORY;
580   }
581 
582   return 0;
583 }
584 
585 #endif /* HAVE_GETADDRINFO */