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
pqt_snprintf(char * buf,size_t size,const char * format,...)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
pqt_vsnprintf(char * buf,size_t size,const char * format,va_list ap)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
strtol(const char * nptr,char ** endptr,int base)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
strtoul(const char * nptr,char ** endptr,int base)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
string2long(const char * nptr,char ** const endptr,int base,int is_signed)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
strtoll(const char * nptr,char ** endptr,int base)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
getaddrinfo(const char * node,const char * service,const struct addrinfo * hintp,struct addrinfo ** res)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
freeaddrinfo(struct addrinfo * res)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 *
gai_strerror(int errcode)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
getnameinfo(const struct sockaddr * sa,int salen,char * node,int nodelen,char * service,int servicelen,int flags)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 */
586
587
588