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 */ |