libpqtypes - port.c

Home Page

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