1 /* 2 * HTTP address list routines for CUPS. 3 * 4 * Copyright 2007-2016 by Apple Inc. 5 * Copyright 1997-2007 by Easy Software Products, all rights reserved. 6 * 7 * These coded instructions, statements, and computer programs are the 8 * property of Apple Inc. and are protected by Federal copyright 9 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 10 * which should have been included with this file. If this file is 11 * missing or damaged, see the license at "http://www.cups.org/". 12 * 13 * This file is subject to the Apple OS-Developed Software exception. 14 */ 15 16 /* 17 * Include necessary headers... 18 */ 19 20 #include "cups-private.h" 21 #ifdef HAVE_RESOLV_H 22 # include <resolv.h> 23 #endif /* HAVE_RESOLV_H */ 24 #ifdef HAVE_POLL 25 # include <poll.h> 26 #endif /* HAVE_POLL */ 27 #ifndef WIN32 28 # include <fcntl.h> 29 #endif /* WIN32 */ 30 31 32 /* 33 * 'httpAddrConnect()' - Connect to any of the addresses in the list. 34 * 35 * @since CUPS 1.2/macOS 10.5@ 36 */ 37 38 http_addrlist_t * /* O - Connected address or NULL on failure */ 39 httpAddrConnect( 40 http_addrlist_t *addrlist, /* I - List of potential addresses */ 41 int *sock) /* O - Socket */ 42 { 43 DEBUG_printf(("httpAddrConnect(addrlist=%p, sock=%p)", (void *)addrlist, (void *)sock)); 44 45 return (httpAddrConnect2(addrlist, sock, 30000, NULL)); 46 } 47 48 49 /* 50 * 'httpAddrConnect2()' - Connect to any of the addresses in the list with a 51 * timeout and optional cancel. 52 * 53 * @since CUPS 1.7/macOS 10.9@ 54 */ 55 56 http_addrlist_t * /* O - Connected address or NULL on failure */ 57 httpAddrConnect2( 58 http_addrlist_t *addrlist, /* I - List of potential addresses */ 59 int *sock, /* O - Socket */ 60 int msec, /* I - Timeout in milliseconds */ 61 int *cancel) /* I - Pointer to "cancel" variable */ 62 { 63 int val; /* Socket option value */ 64 #ifndef WIN32 65 int flags; /* Socket flags */ 66 #endif /* !WIN32 */ 67 int remaining; /* Remaining timeout */ 68 int i, /* Looping var */ 69 nfds, /* Number of file descriptors */ 70 fds[100], /* Socket file descriptors */ 71 result; /* Result from select() or poll() */ 72 http_addrlist_t *addrs[100]; /* Addresses */ 73 #ifndef HAVE_POLL 74 int max_fd = -1; /* Highest file descriptor */ 75 #endif /* !HAVE_POLL */ 76 #ifdef O_NONBLOCK 77 # ifdef HAVE_POLL 78 struct pollfd pfds[100]; /* Polled file descriptors */ 79 # else 80 fd_set input_set, /* select() input set */ 81 output_set, /* select() output set */ 82 error_set; /* select() error set */ 83 struct timeval timeout; /* Timeout */ 84 # endif /* HAVE_POLL */ 85 #endif /* O_NONBLOCK */ 86 #ifdef DEBUG 87 socklen_t len; /* Length of value */ 88 http_addr_t peer; /* Peer address */ 89 char temp[256]; /* Temporary address string */ 90 #endif /* DEBUG */ 91 92 93 DEBUG_printf(("httpAddrConnect2(addrlist=%p, sock=%p, msec=%d, cancel=%p)", (void *)addrlist, (void *)sock, msec, (void *)cancel)); 94 95 if (!sock) 96 { 97 errno = EINVAL; 98 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 99 return (NULL); 100 } 101 102 if (cancel && *cancel) 103 return (NULL); 104 105 if (msec <= 0) 106 msec = INT_MAX; 107 108 /* 109 * Loop through each address until we connect or run out of addresses... 110 */ 111 112 nfds = 0; 113 remaining = msec; 114 115 while (remaining > 0) 116 { 117 if (cancel && *cancel) 118 { 119 while (nfds > 0) 120 { 121 nfds --; 122 httpAddrClose(NULL, fds[nfds]); 123 } 124 125 return (NULL); 126 } 127 128 if (addrlist && nfds < (int)(sizeof(fds) / sizeof(fds[0]))) 129 { 130 /* 131 * Create the socket... 132 */ 133 134 DEBUG_printf(("2httpAddrConnect2: Trying %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)))); 135 136 if ((fds[nfds] = (int)socket(httpAddrFamily(&(addrlist->addr)), SOCK_STREAM, 0)) < 0) 137 { 138 /* 139 * Don't abort yet, as this could just be an issue with the local 140 * system not being configured with IPv4/IPv6/domain socket enabled. 141 * 142 * Just skip this address... 143 */ 144 145 addrlist = addrlist->next; 146 continue; 147 } 148 149 /* 150 * Set options... 151 */ 152 153 val = 1; 154 setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val)); 155 156 #ifdef SO_REUSEPORT 157 val = 1; 158 setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEPORT, CUPS_SOCAST &val, sizeof(val)); 159 #endif /* SO_REUSEPORT */ 160 161 #ifdef SO_NOSIGPIPE 162 val = 1; 163 setsockopt(fds[nfds], SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val)); 164 #endif /* SO_NOSIGPIPE */ 165 166 /* 167 * Using TCP_NODELAY improves responsiveness, especially on systems 168 * with a slow loopback interface... 169 */ 170 171 val = 1; 172 setsockopt(fds[nfds], IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val)); 173 174 #ifdef FD_CLOEXEC 175 /* 176 * Close this socket when starting another process... 177 */ 178 179 fcntl(fds[nfds], F_SETFD, FD_CLOEXEC); 180 #endif /* FD_CLOEXEC */ 181 182 #ifdef O_NONBLOCK 183 /* 184 * Do an asynchronous connect by setting the socket non-blocking... 185 */ 186 187 DEBUG_printf(("httpAddrConnect2: Setting non-blocking connect()")); 188 189 flags = fcntl(fds[nfds], F_GETFL, 0); 190 fcntl(fds[nfds], F_SETFL, flags | O_NONBLOCK); 191 #endif /* O_NONBLOCK */ 192 193 /* 194 * Then connect... 195 */ 196 197 if (!connect(fds[nfds], &(addrlist->addr.addr), (socklen_t)httpAddrLength(&(addrlist->addr)))) 198 { 199 DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)))); 200 201 #ifdef O_NONBLOCK 202 fcntl(fds[nfds], F_SETFL, flags); 203 #endif /* O_NONBLOCK */ 204 205 *sock = fds[nfds]; 206 207 while (nfds > 0) 208 { 209 nfds --; 210 httpAddrClose(NULL, fds[nfds]); 211 } 212 213 return (addrlist); 214 } 215 216 #ifdef WIN32 217 if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK) 218 #else 219 if (errno != EINPROGRESS && errno != EWOULDBLOCK) 220 #endif /* WIN32 */ 221 { 222 DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)), strerror(errno))); 223 httpAddrClose(NULL, fds[nfds]); 224 addrlist = addrlist->next; 225 continue; 226 } 227 228 #ifndef WIN32 229 fcntl(fds[nfds], F_SETFL, flags); 230 #endif /* !WIN32 */ 231 232 #ifndef HAVE_POLL 233 if (fds[nfds] > max_fd) 234 max_fd = fds[nfds]; 235 #endif /* !HAVE_POLL */ 236 237 addrs[nfds] = addrlist; 238 nfds ++; 239 addrlist = addrlist->next; 240 } 241 242 if (!addrlist && nfds == 0) 243 break; 244 245 /* 246 * See if we can connect to any of the addresses so far... 247 */ 248 249 #ifdef O_NONBLOCK 250 DEBUG_puts("1httpAddrConnect2: Finishing async connect()"); 251 252 do 253 { 254 if (cancel && *cancel) 255 { 256 /* 257 * Close this socket and return... 258 */ 259 260 DEBUG_puts("1httpAddrConnect2: Canceled connect()"); 261 262 while (nfds > 0) 263 { 264 nfds --; 265 httpAddrClose(NULL, fds[nfds]); 266 } 267 268 *sock = -1; 269 270 return (NULL); 271 } 272 273 # ifdef HAVE_POLL 274 for (i = 0; i < nfds; i ++) 275 { 276 pfds[i].fd = fds[i]; 277 pfds[i].events = POLLIN | POLLOUT; 278 } 279 280 result = poll(pfds, (nfds_t)nfds, addrlist ? 100 : remaining > 250 ? 250 : remaining); 281 282 DEBUG_printf(("1httpAddrConnect2: poll() returned %d (%d)", result, errno)); 283 284 # else 285 FD_ZERO(&input_set); 286 for (i = 0; i < nfds; i ++) 287 FD_SET(fds[i], &input_set); 288 output_set = input_set; 289 error_set = input_set; 290 291 timeout.tv_sec = 0; 292 timeout.tv_usec = (addrlist ? 100 : remaining > 250 ? 250 : remaining) * 1000; 293 294 result = select(max_fd + 1, &input_set, &output_set, &error_set, &timeout); 295 296 DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", result, errno)); 297 # endif /* HAVE_POLL */ 298 } 299 # ifdef WIN32 300 while (result < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)); 301 # else 302 while (result < 0 && (errno == EINTR || errno == EAGAIN)); 303 # endif /* WIN32 */ 304 305 if (result > 0) 306 { 307 http_addrlist_t *connaddr = NULL; /* Connected address, if any */ 308 309 for (i = 0; i < nfds; i ++) 310 { 311 # ifdef HAVE_POLL 312 DEBUG_printf(("pfds[%d].revents=%x\n", i, pfds[i].revents)); 313 if (pfds[i].revents && !(pfds[i].revents & (POLLERR | POLLHUP))) 314 # else 315 if (FD_ISSET(fds[i], &input_set) && !FD_ISSET(fds[i], &error_set)) 316 # endif /* HAVE_POLL */ 317 { 318 *sock = fds[i]; 319 connaddr = addrs[i]; 320 321 # ifdef DEBUG 322 len = sizeof(peer); 323 if (!getpeername(fds[i], (struct sockaddr *)&peer, &len)) 324 DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&peer, temp, sizeof(temp)), httpAddrPort(&peer))); 325 # endif /* DEBUG */ 326 } 327 # ifdef HAVE_POLL 328 else if (pfds[i].revents & (POLLERR | POLLHUP)) 329 # else 330 else if (FD_ISSET(fds[i], &error_set)) 331 # endif /* HAVE_POLL */ 332 { 333 /* 334 * Error on socket, remove from the "pool"... 335 */ 336 337 httpAddrClose(NULL, fds[i]); 338 nfds --; 339 if (i < nfds) 340 { 341 memmove(fds + i, fds + i + 1, (size_t)(nfds - i) * (sizeof(fds[0]))); 342 memmove(addrs + i, addrs + i + 1, (size_t)(nfds - i) * (sizeof(addrs[0]))); 343 } 344 i --; 345 } 346 } 347 348 if (connaddr) 349 return (connaddr); 350 } 351 #endif /* O_NONBLOCK */ 352 353 if (addrlist) 354 remaining -= 100; 355 else 356 remaining -= 250; 357 } 358 359 while (nfds > 0) 360 { 361 nfds --; 362 httpAddrClose(NULL, fds[nfds]); 363 } 364 365 #ifdef WIN32 366 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0); 367 #else 368 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0); 369 #endif /* WIN32 */ 370 371 return (NULL); 372 } 373 374 375 /* 376 * 'httpAddrCopyList()' - Copy an address list. 377 * 378 * @since CUPS 1.7/macOS 10.9@ 379 */ 380 381 http_addrlist_t * /* O - New address list or @code NULL@ on error */ 382 httpAddrCopyList( 383 http_addrlist_t *src) /* I - Source address list */ 384 { 385 http_addrlist_t *dst = NULL, /* First list entry */ 386 *prev = NULL, /* Previous list entry */ 387 *current = NULL;/* Current list entry */ 388 389 390 while (src) 391 { 392 if ((current = malloc(sizeof(http_addrlist_t))) == NULL) 393 { 394 current = dst; 395 396 while (current) 397 { 398 prev = current; 399 current = current->next; 400 401 free(prev); 402 } 403 404 return (NULL); 405 } 406 407 memcpy(current, src, sizeof(http_addrlist_t)); 408 409 current->next = NULL; 410 411 if (prev) 412 prev->next = current; 413 else 414 dst = current; 415 416 prev = current; 417 src = src->next; 418 } 419 420 return (dst); 421 } 422 423 424 /* 425 * 'httpAddrFreeList()' - Free an address list. 426 * 427 * @since CUPS 1.2/macOS 10.5@ 428 */ 429 430 void 431 httpAddrFreeList( 432 http_addrlist_t *addrlist) /* I - Address list to free */ 433 { 434 http_addrlist_t *next; /* Next address in list */ 435 436 437 /* 438 * Free each address in the list... 439 */ 440 441 while (addrlist) 442 { 443 next = addrlist->next; 444 445 free(addrlist); 446 447 addrlist = next; 448 } 449 } 450 451 452 /* 453 * 'httpAddrGetList()' - Get a list of addresses for a hostname. 454 * 455 * @since CUPS 1.2/macOS 10.5@ 456 */ 457 458 http_addrlist_t * /* O - List of addresses or NULL */ 459 httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for passive listen address */ 460 int family, /* I - Address family or AF_UNSPEC */ 461 const char *service) /* I - Service name or port number */ 462 { 463 http_addrlist_t *first, /* First address in list */ 464 *addr, /* Current address in list */ 465 *temp; /* New address */ 466 _cups_globals_t *cg = _cupsGlobals(); 467 /* Global data */ 468 469 470 #ifdef DEBUG 471 _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, " 472 "service=\"%s\")\n", 473 hostname ? hostname : "(nil)", 474 family == AF_UNSPEC ? "UNSPEC" : 475 # ifdef AF_LOCAL 476 family == AF_LOCAL ? "LOCAL" : 477 # endif /* AF_LOCAL */ 478 # ifdef AF_INET6 479 family == AF_INET6 ? "INET6" : 480 # endif /* AF_INET6 */ 481 family == AF_INET ? "INET" : "???", service); 482 #endif /* DEBUG */ 483 484 #ifdef HAVE_RES_INIT 485 /* 486 * STR #2920: Initialize resolver after failure in cups-polld 487 * 488 * If the previous lookup failed, re-initialize the resolver to prevent 489 * temporary network errors from persisting. This *should* be handled by 490 * the resolver libraries, but apparently the glibc folks do not agree. 491 * 492 * We set a flag at the end of this function if we encounter an error that 493 * requires reinitialization of the resolver functions. We then call 494 * res_init() if the flag is set on the next call here or in httpAddrLookup(). 495 */ 496 497 if (cg->need_res_init) 498 { 499 res_init(); 500 501 cg->need_res_init = 0; 502 } 503 #endif /* HAVE_RES_INIT */ 504 505 /* 506 * Lookup the address the best way we can... 507 */ 508 509 first = addr = NULL; 510 511 #ifdef AF_LOCAL 512 if (hostname && hostname[0] == '/') 513 { 514 /* 515 * Domain socket address... 516 */ 517 518 if ((first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t))) != NULL) 519 { 520 addr = first; 521 first->addr.un.sun_family = AF_LOCAL; 522 strlcpy(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path)); 523 } 524 } 525 else 526 #endif /* AF_LOCAL */ 527 if (!hostname || _cups_strcasecmp(hostname, "localhost")) 528 { 529 #ifdef HAVE_GETADDRINFO 530 struct addrinfo hints, /* Address lookup hints */ 531 *results, /* Address lookup results */ 532 *current; /* Current result */ 533 char ipv6[64], /* IPv6 address */ 534 *ipv6zone; /* Pointer to zone separator */ 535 int ipv6len; /* Length of IPv6 address */ 536 int error; /* getaddrinfo() error */ 537 538 539 /* 540 * Lookup the address as needed... 541 */ 542 543 memset(&hints, 0, sizeof(hints)); 544 hints.ai_family = family; 545 hints.ai_flags = hostname ? 0 : AI_PASSIVE; 546 hints.ai_socktype = SOCK_STREAM; 547 548 if (hostname && *hostname == '[') 549 { 550 /* 551 * Remove brackets from numeric IPv6 address... 552 */ 553 554 if (!strncmp(hostname, "[v1.", 4)) 555 { 556 /* 557 * Copy the newer address format which supports link-local addresses... 558 */ 559 560 strlcpy(ipv6, hostname + 4, sizeof(ipv6)); 561 if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']') 562 { 563 ipv6[ipv6len] = '\0'; 564 hostname = ipv6; 565 566 /* 567 * Convert "+zone" in address to "%zone"... 568 */ 569 570 if ((ipv6zone = strrchr(ipv6, '+')) != NULL) 571 *ipv6zone = '%'; 572 } 573 } 574 else 575 { 576 /* 577 * Copy the regular non-link-local IPv6 address... 578 */ 579 580 strlcpy(ipv6, hostname + 1, sizeof(ipv6)); 581 if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']') 582 { 583 ipv6[ipv6len] = '\0'; 584 hostname = ipv6; 585 } 586 } 587 } 588 589 if ((error = getaddrinfo(hostname, service, &hints, &results)) == 0) 590 { 591 /* 592 * Copy the results to our own address list structure... 593 */ 594 595 for (current = results; current; current = current->ai_next) 596 if (current->ai_family == AF_INET || current->ai_family == AF_INET6) 597 { 598 /* 599 * Copy the address over... 600 */ 601 602 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 603 if (!temp) 604 { 605 httpAddrFreeList(first); 606 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 607 return (NULL); 608 } 609 610 if (current->ai_family == AF_INET6) 611 memcpy(&(temp->addr.ipv6), current->ai_addr, 612 sizeof(temp->addr.ipv6)); 613 else 614 memcpy(&(temp->addr.ipv4), current->ai_addr, 615 sizeof(temp->addr.ipv4)); 616 617 /* 618 * Append the address to the list... 619 */ 620 621 if (!first) 622 first = temp; 623 624 if (addr) 625 addr->next = temp; 626 627 addr = temp; 628 } 629 630 /* 631 * Free the results from getaddrinfo()... 632 */ 633 634 freeaddrinfo(results); 635 } 636 else 637 { 638 if (error == EAI_FAIL) 639 cg->need_res_init = 1; 640 641 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerror(error), 0); 642 } 643 644 #else 645 if (hostname) 646 { 647 int i; /* Looping vars */ 648 unsigned ip[4]; /* IPv4 address components */ 649 const char *ptr; /* Pointer into hostname */ 650 struct hostent *host; /* Result of lookup */ 651 struct servent *port; /* Port number for service */ 652 int portnum; /* Port number */ 653 654 655 /* 656 * Lookup the service... 657 */ 658 659 if (!service) 660 portnum = 0; 661 else if (isdigit(*service & 255)) 662 portnum = atoi(service); 663 else if ((port = getservbyname(service, NULL)) != NULL) 664 portnum = ntohs(port->s_port); 665 else if (!strcmp(service, "http")) 666 portnum = 80; 667 else if (!strcmp(service, "https")) 668 portnum = 443; 669 else if (!strcmp(service, "ipp") || !strcmp(service, "ipps")) 670 portnum = 631; 671 else if (!strcmp(service, "lpd")) 672 portnum = 515; 673 else if (!strcmp(service, "socket")) 674 portnum = 9100; 675 else 676 return (NULL); 677 678 /* 679 * This code is needed because some operating systems have a 680 * buggy implementation of gethostbyname() that does not support 681 * IPv4 addresses. If the hostname string is an IPv4 address, then 682 * sscanf() is used to extract the IPv4 components. We then pack 683 * the components into an IPv4 address manually, since the 684 * inet_aton() function is deprecated. We use the htonl() macro 685 * to get the right byte order for the address. 686 */ 687 688 for (ptr = hostname; isdigit(*ptr & 255) || *ptr == '.'; ptr ++); 689 690 if (!*ptr) 691 { 692 /* 693 * We have an IPv4 address; break it up and create an IPv4 address... 694 */ 695 696 if (sscanf(hostname, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) == 4 && 697 ip[0] <= 255 && ip[1] <= 255 && ip[2] <= 255 && ip[3] <= 255) 698 { 699 first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 700 if (!first) 701 return (NULL); 702 703 first->addr.ipv4.sin_family = AF_INET; 704 first->addr.ipv4.sin_addr.s_addr = htonl((((((((unsigned)ip[0] << 8) | 705 (unsigned)ip[1]) << 8) | 706 (unsigned)ip[2]) << 8) | 707 (unsigned)ip[3])); 708 first->addr.ipv4.sin_port = htons(portnum); 709 } 710 } 711 else if ((host = gethostbyname(hostname)) != NULL && 712 # ifdef AF_INET6 713 (host->h_addrtype == AF_INET || host->h_addrtype == AF_INET6)) 714 # else 715 host->h_addrtype == AF_INET) 716 # endif /* AF_INET6 */ 717 { 718 for (i = 0; host->h_addr_list[i]; i ++) 719 { 720 /* 721 * Copy the address over... 722 */ 723 724 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 725 if (!temp) 726 { 727 httpAddrFreeList(first); 728 return (NULL); 729 } 730 731 # ifdef AF_INET6 732 if (host->h_addrtype == AF_INET6) 733 { 734 temp->addr.ipv6.sin6_family = AF_INET6; 735 memcpy(&(temp->addr.ipv6.sin6_addr), host->h_addr_list[i], 736 sizeof(temp->addr.ipv6)); 737 temp->addr.ipv6.sin6_port = htons(portnum); 738 } 739 else 740 # endif /* AF_INET6 */ 741 { 742 temp->addr.ipv4.sin_family = AF_INET; 743 memcpy(&(temp->addr.ipv4.sin_addr), host->h_addr_list[i], 744 sizeof(temp->addr.ipv4)); 745 temp->addr.ipv4.sin_port = htons(portnum); 746 } 747 748 /* 749 * Append the address to the list... 750 */ 751 752 if (!first) 753 first = temp; 754 755 if (addr) 756 addr->next = temp; 757 758 addr = temp; 759 } 760 } 761 else 762 { 763 if (h_errno == NO_RECOVERY) 764 cg->need_res_init = 1; 765 766 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, hstrerror(h_errno), 0); 767 } 768 } 769 #endif /* HAVE_GETADDRINFO */ 770 } 771 772 /* 773 * Detect some common errors and handle them sanely... 774 */ 775 776 if (!addr && (!hostname || !_cups_strcasecmp(hostname, "localhost"))) 777 { 778 struct servent *port; /* Port number for service */ 779 int portnum; /* Port number */ 780 781 782 /* 783 * Lookup the service... 784 */ 785 786 if (!service) 787 portnum = 0; 788 else if (isdigit(*service & 255)) 789 portnum = atoi(service); 790 else if ((port = getservbyname(service, NULL)) != NULL) 791 portnum = ntohs(port->s_port); 792 else if (!strcmp(service, "http")) 793 portnum = 80; 794 else if (!strcmp(service, "https")) 795 portnum = 443; 796 else if (!strcmp(service, "ipp") || !strcmp(service, "ipps")) 797 portnum = 631; 798 else if (!strcmp(service, "lpd")) 799 portnum = 515; 800 else if (!strcmp(service, "socket")) 801 portnum = 9100; 802 else 803 { 804 httpAddrFreeList(first); 805 806 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown service name."), 1); 807 return (NULL); 808 } 809 810 if (hostname && !_cups_strcasecmp(hostname, "localhost")) 811 { 812 /* 813 * Unfortunately, some users ignore all of the warnings in the 814 * /etc/hosts file and delete "localhost" from it. If we get here 815 * then we were unable to resolve the name, so use the IPv6 and/or 816 * IPv4 loopback interface addresses... 817 */ 818 819 #ifdef AF_INET6 820 if (family != AF_INET) 821 { 822 /* 823 * Add [::1] to the address list... 824 */ 825 826 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 827 if (!temp) 828 { 829 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 830 httpAddrFreeList(first); 831 return (NULL); 832 } 833 834 temp->addr.ipv6.sin6_family = AF_INET6; 835 temp->addr.ipv6.sin6_port = htons(portnum); 836 # ifdef WIN32 837 temp->addr.ipv6.sin6_addr.u.Byte[15] = 1; 838 # else 839 temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1); 840 # endif /* WIN32 */ 841 842 if (!first) 843 first = temp; 844 845 addr = temp; 846 } 847 848 if (family != AF_INET6) 849 #endif /* AF_INET6 */ 850 { 851 /* 852 * Add 127.0.0.1 to the address list... 853 */ 854 855 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 856 if (!temp) 857 { 858 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 859 httpAddrFreeList(first); 860 return (NULL); 861 } 862 863 temp->addr.ipv4.sin_family = AF_INET; 864 temp->addr.ipv4.sin_port = htons(portnum); 865 temp->addr.ipv4.sin_addr.s_addr = htonl(0x7f000001); 866 867 if (!first) 868 first = temp; 869 870 if (addr) 871 addr->next = temp; 872 } 873 } 874 else if (!hostname) 875 { 876 /* 877 * Provide one or more passive listening addresses... 878 */ 879 880 #ifdef AF_INET6 881 if (family != AF_INET) 882 { 883 /* 884 * Add [::] to the address list... 885 */ 886 887 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 888 if (!temp) 889 { 890 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 891 httpAddrFreeList(first); 892 return (NULL); 893 } 894 895 temp->addr.ipv6.sin6_family = AF_INET6; 896 temp->addr.ipv6.sin6_port = htons(portnum); 897 898 if (!first) 899 first = temp; 900 901 addr = temp; 902 } 903 904 if (family != AF_INET6) 905 #endif /* AF_INET6 */ 906 { 907 /* 908 * Add 0.0.0.0 to the address list... 909 */ 910 911 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 912 if (!temp) 913 { 914 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 915 httpAddrFreeList(first); 916 return (NULL); 917 } 918 919 temp->addr.ipv4.sin_family = AF_INET; 920 temp->addr.ipv4.sin_port = htons(portnum); 921 922 if (!first) 923 first = temp; 924 925 if (addr) 926 addr->next = temp; 927 } 928 } 929 } 930 931 /* 932 * Return the address list... 933 */ 934 935 return (first); 936 } 937