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