1 /* 2 * HTTP address list routines for CUPS. 3 * 4 * Copyright 2007-2017 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@ @exclude all@ 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, j, /* Looping vars */ 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 break; 328 } 329 # ifdef HAVE_POLL 330 else if (pfds[i].revents & (POLLERR | POLLHUP)) 331 # else 332 else if (FD_ISSET(fds[i], &error_set)) 333 # endif /* HAVE_POLL */ 334 { 335 /* 336 * Error on socket, remove from the "pool"... 337 */ 338 339 httpAddrClose(NULL, fds[i]); 340 nfds --; 341 if (i < nfds) 342 { 343 memmove(fds + i, fds + i + 1, (size_t)(nfds - i) * (sizeof(fds[0]))); 344 memmove(addrs + i, addrs + i + 1, (size_t)(nfds - i) * (sizeof(addrs[0]))); 345 } 346 i --; 347 } 348 } 349 350 if (connaddr) 351 { 352 /* 353 * Connected on one address, close all of the other sockets we have so 354 * far and return... 355 */ 356 357 for (j = 0; j < i; j ++) 358 httpAddrClose(NULL, fds[j]); 359 360 for (j ++; j < nfds; j ++) 361 httpAddrClose(NULL, fds[j]); 362 363 return (connaddr); 364 } 365 } 366 #endif /* O_NONBLOCK */ 367 368 if (addrlist) 369 remaining -= 100; 370 else 371 remaining -= 250; 372 } 373 374 while (nfds > 0) 375 { 376 nfds --; 377 httpAddrClose(NULL, fds[nfds]); 378 } 379 380 #ifdef WIN32 381 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0); 382 #else 383 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0); 384 #endif /* WIN32 */ 385 386 return (NULL); 387 } 388 389 390 /* 391 * 'httpAddrCopyList()' - Copy an address list. 392 * 393 * @since CUPS 1.7/macOS 10.9@ 394 */ 395 396 http_addrlist_t * /* O - New address list or @code NULL@ on error */ 397 httpAddrCopyList( 398 http_addrlist_t *src) /* I - Source address list */ 399 { 400 http_addrlist_t *dst = NULL, /* First list entry */ 401 *prev = NULL, /* Previous list entry */ 402 *current = NULL;/* Current list entry */ 403 404 405 while (src) 406 { 407 if ((current = malloc(sizeof(http_addrlist_t))) == NULL) 408 { 409 current = dst; 410 411 while (current) 412 { 413 prev = current; 414 current = current->next; 415 416 free(prev); 417 } 418 419 return (NULL); 420 } 421 422 memcpy(current, src, sizeof(http_addrlist_t)); 423 424 current->next = NULL; 425 426 if (prev) 427 prev->next = current; 428 else 429 dst = current; 430 431 prev = current; 432 src = src->next; 433 } 434 435 return (dst); 436 } 437 438 439 /* 440 * 'httpAddrFreeList()' - Free an address list. 441 * 442 * @since CUPS 1.2/macOS 10.5@ 443 */ 444 445 void 446 httpAddrFreeList( 447 http_addrlist_t *addrlist) /* I - Address list to free */ 448 { 449 http_addrlist_t *next; /* Next address in list */ 450 451 452 /* 453 * Free each address in the list... 454 */ 455 456 while (addrlist) 457 { 458 next = addrlist->next; 459 460 free(addrlist); 461 462 addrlist = next; 463 } 464 } 465 466 467 /* 468 * 'httpAddrGetList()' - Get a list of addresses for a hostname. 469 * 470 * @since CUPS 1.2/macOS 10.5@ 471 */ 472 473 http_addrlist_t * /* O - List of addresses or NULL */ 474 httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for passive listen address */ 475 int family, /* I - Address family or AF_UNSPEC */ 476 const char *service) /* I - Service name or port number */ 477 { 478 http_addrlist_t *first, /* First address in list */ 479 *addr, /* Current address in list */ 480 *temp; /* New address */ 481 _cups_globals_t *cg = _cupsGlobals(); 482 /* Global data */ 483 484 485 #ifdef DEBUG 486 _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, " 487 "service=\"%s\")\n", 488 hostname ? hostname : "(nil)", 489 family == AF_UNSPEC ? "UNSPEC" : 490 # ifdef AF_LOCAL 491 family == AF_LOCAL ? "LOCAL" : 492 # endif /* AF_LOCAL */ 493 # ifdef AF_INET6 494 family == AF_INET6 ? "INET6" : 495 # endif /* AF_INET6 */ 496 family == AF_INET ? "INET" : "???", service); 497 #endif /* DEBUG */ 498 499 #ifdef HAVE_RES_INIT 500 /* 501 * STR #2920: Initialize resolver after failure in cups-polld 502 * 503 * If the previous lookup failed, re-initialize the resolver to prevent 504 * temporary network errors from persisting. This *should* be handled by 505 * the resolver libraries, but apparently the glibc folks do not agree. 506 * 507 * We set a flag at the end of this function if we encounter an error that 508 * requires reinitialization of the resolver functions. We then call 509 * res_init() if the flag is set on the next call here or in httpAddrLookup(). 510 */ 511 512 if (cg->need_res_init) 513 { 514 res_init(); 515 516 cg->need_res_init = 0; 517 } 518 #endif /* HAVE_RES_INIT */ 519 520 /* 521 * Lookup the address the best way we can... 522 */ 523 524 first = addr = NULL; 525 526 #ifdef AF_LOCAL 527 if (hostname && hostname[0] == '/') 528 { 529 /* 530 * Domain socket address... 531 */ 532 533 if ((first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t))) != NULL) 534 { 535 addr = first; 536 first->addr.un.sun_family = AF_LOCAL; 537 strlcpy(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path)); 538 } 539 } 540 else 541 #endif /* AF_LOCAL */ 542 if (!hostname || _cups_strcasecmp(hostname, "localhost")) 543 { 544 #ifdef HAVE_GETADDRINFO 545 struct addrinfo hints, /* Address lookup hints */ 546 *results, /* Address lookup results */ 547 *current; /* Current result */ 548 char ipv6[64], /* IPv6 address */ 549 *ipv6zone; /* Pointer to zone separator */ 550 int ipv6len; /* Length of IPv6 address */ 551 int error; /* getaddrinfo() error */ 552 553 554 /* 555 * Lookup the address as needed... 556 */ 557 558 memset(&hints, 0, sizeof(hints)); 559 hints.ai_family = family; 560 hints.ai_flags = hostname ? 0 : AI_PASSIVE; 561 hints.ai_socktype = SOCK_STREAM; 562 563 if (hostname && *hostname == '[') 564 { 565 /* 566 * Remove brackets from numeric IPv6 address... 567 */ 568 569 if (!strncmp(hostname, "[v1.", 4)) 570 { 571 /* 572 * Copy the newer address format which supports link-local addresses... 573 */ 574 575 strlcpy(ipv6, hostname + 4, sizeof(ipv6)); 576 if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']') 577 { 578 ipv6[ipv6len] = '\0'; 579 hostname = ipv6; 580 581 /* 582 * Convert "+zone" in address to "%zone"... 583 */ 584 585 if ((ipv6zone = strrchr(ipv6, '+')) != NULL) 586 *ipv6zone = '%'; 587 } 588 } 589 else 590 { 591 /* 592 * Copy the regular non-link-local IPv6 address... 593 */ 594 595 strlcpy(ipv6, hostname + 1, sizeof(ipv6)); 596 if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']') 597 { 598 ipv6[ipv6len] = '\0'; 599 hostname = ipv6; 600 } 601 } 602 } 603 604 if ((error = getaddrinfo(hostname, service, &hints, &results)) == 0) 605 { 606 /* 607 * Copy the results to our own address list structure... 608 */ 609 610 for (current = results; current; current = current->ai_next) 611 if (current->ai_family == AF_INET || current->ai_family == AF_INET6) 612 { 613 /* 614 * Copy the address over... 615 */ 616 617 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 618 if (!temp) 619 { 620 httpAddrFreeList(first); 621 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 622 return (NULL); 623 } 624 625 if (current->ai_family == AF_INET6) 626 memcpy(&(temp->addr.ipv6), current->ai_addr, 627 sizeof(temp->addr.ipv6)); 628 else 629 memcpy(&(temp->addr.ipv4), current->ai_addr, 630 sizeof(temp->addr.ipv4)); 631 632 /* 633 * Append the address to the list... 634 */ 635 636 if (!first) 637 first = temp; 638 639 if (addr) 640 addr->next = temp; 641 642 addr = temp; 643 } 644 645 /* 646 * Free the results from getaddrinfo()... 647 */ 648 649 freeaddrinfo(results); 650 } 651 else 652 { 653 if (error == EAI_FAIL) 654 cg->need_res_init = 1; 655 656 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerror(error), 0); 657 } 658 659 #else 660 if (hostname) 661 { 662 int i; /* Looping vars */ 663 unsigned ip[4]; /* IPv4 address components */ 664 const char *ptr; /* Pointer into hostname */ 665 struct hostent *host; /* Result of lookup */ 666 struct servent *port; /* Port number for service */ 667 int portnum; /* Port number */ 668 669 670 /* 671 * Lookup the service... 672 */ 673 674 if (!service) 675 portnum = 0; 676 else if (isdigit(*service & 255)) 677 portnum = atoi(service); 678 else if ((port = getservbyname(service, NULL)) != NULL) 679 portnum = ntohs(port->s_port); 680 else if (!strcmp(service, "http")) 681 portnum = 80; 682 else if (!strcmp(service, "https")) 683 portnum = 443; 684 else if (!strcmp(service, "ipp") || !strcmp(service, "ipps")) 685 portnum = 631; 686 else if (!strcmp(service, "lpd")) 687 portnum = 515; 688 else if (!strcmp(service, "socket")) 689 portnum = 9100; 690 else 691 return (NULL); 692 693 /* 694 * This code is needed because some operating systems have a 695 * buggy implementation of gethostbyname() that does not support 696 * IPv4 addresses. If the hostname string is an IPv4 address, then 697 * sscanf() is used to extract the IPv4 components. We then pack 698 * the components into an IPv4 address manually, since the 699 * inet_aton() function is deprecated. We use the htonl() macro 700 * to get the right byte order for the address. 701 */ 702 703 for (ptr = hostname; isdigit(*ptr & 255) || *ptr == '.'; ptr ++); 704 705 if (!*ptr) 706 { 707 /* 708 * We have an IPv4 address; break it up and create an IPv4 address... 709 */ 710 711 if (sscanf(hostname, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) == 4 && 712 ip[0] <= 255 && ip[1] <= 255 && ip[2] <= 255 && ip[3] <= 255) 713 { 714 first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 715 if (!first) 716 return (NULL); 717 718 first->addr.ipv4.sin_family = AF_INET; 719 first->addr.ipv4.sin_addr.s_addr = htonl((((((((unsigned)ip[0] << 8) | 720 (unsigned)ip[1]) << 8) | 721 (unsigned)ip[2]) << 8) | 722 (unsigned)ip[3])); 723 first->addr.ipv4.sin_port = htons(portnum); 724 } 725 } 726 else if ((host = gethostbyname(hostname)) != NULL && 727 # ifdef AF_INET6 728 (host->h_addrtype == AF_INET || host->h_addrtype == AF_INET6)) 729 # else 730 host->h_addrtype == AF_INET) 731 # endif /* AF_INET6 */ 732 { 733 for (i = 0; host->h_addr_list[i]; i ++) 734 { 735 /* 736 * Copy the address over... 737 */ 738 739 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 740 if (!temp) 741 { 742 httpAddrFreeList(first); 743 return (NULL); 744 } 745 746 # ifdef AF_INET6 747 if (host->h_addrtype == AF_INET6) 748 { 749 temp->addr.ipv6.sin6_family = AF_INET6; 750 memcpy(&(temp->addr.ipv6.sin6_addr), host->h_addr_list[i], 751 sizeof(temp->addr.ipv6)); 752 temp->addr.ipv6.sin6_port = htons(portnum); 753 } 754 else 755 # endif /* AF_INET6 */ 756 { 757 temp->addr.ipv4.sin_family = AF_INET; 758 memcpy(&(temp->addr.ipv4.sin_addr), host->h_addr_list[i], 759 sizeof(temp->addr.ipv4)); 760 temp->addr.ipv4.sin_port = htons(portnum); 761 } 762 763 /* 764 * Append the address to the list... 765 */ 766 767 if (!first) 768 first = temp; 769 770 if (addr) 771 addr->next = temp; 772 773 addr = temp; 774 } 775 } 776 else 777 { 778 if (h_errno == NO_RECOVERY) 779 cg->need_res_init = 1; 780 781 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, hstrerror(h_errno), 0); 782 } 783 } 784 #endif /* HAVE_GETADDRINFO */ 785 } 786 787 /* 788 * Detect some common errors and handle them sanely... 789 */ 790 791 if (!addr && (!hostname || !_cups_strcasecmp(hostname, "localhost"))) 792 { 793 struct servent *port; /* Port number for service */ 794 int portnum; /* Port number */ 795 796 797 /* 798 * Lookup the service... 799 */ 800 801 if (!service) 802 portnum = 0; 803 else if (isdigit(*service & 255)) 804 portnum = atoi(service); 805 else if ((port = getservbyname(service, NULL)) != NULL) 806 portnum = ntohs(port->s_port); 807 else if (!strcmp(service, "http")) 808 portnum = 80; 809 else if (!strcmp(service, "https")) 810 portnum = 443; 811 else if (!strcmp(service, "ipp") || !strcmp(service, "ipps")) 812 portnum = 631; 813 else if (!strcmp(service, "lpd")) 814 portnum = 515; 815 else if (!strcmp(service, "socket")) 816 portnum = 9100; 817 else 818 { 819 httpAddrFreeList(first); 820 821 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown service name."), 1); 822 return (NULL); 823 } 824 825 if (hostname && !_cups_strcasecmp(hostname, "localhost")) 826 { 827 /* 828 * Unfortunately, some users ignore all of the warnings in the 829 * /etc/hosts file and delete "localhost" from it. If we get here 830 * then we were unable to resolve the name, so use the IPv6 and/or 831 * IPv4 loopback interface addresses... 832 */ 833 834 #ifdef AF_INET6 835 if (family != AF_INET) 836 { 837 /* 838 * Add [::1] to the address list... 839 */ 840 841 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 842 if (!temp) 843 { 844 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 845 httpAddrFreeList(first); 846 return (NULL); 847 } 848 849 temp->addr.ipv6.sin6_family = AF_INET6; 850 temp->addr.ipv6.sin6_port = htons(portnum); 851 # ifdef WIN32 852 temp->addr.ipv6.sin6_addr.u.Byte[15] = 1; 853 # else 854 temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1); 855 # endif /* WIN32 */ 856 857 if (!first) 858 first = temp; 859 860 addr = temp; 861 } 862 863 if (family != AF_INET6) 864 #endif /* AF_INET6 */ 865 { 866 /* 867 * Add 127.0.0.1 to the address list... 868 */ 869 870 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 871 if (!temp) 872 { 873 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 874 httpAddrFreeList(first); 875 return (NULL); 876 } 877 878 temp->addr.ipv4.sin_family = AF_INET; 879 temp->addr.ipv4.sin_port = htons(portnum); 880 temp->addr.ipv4.sin_addr.s_addr = htonl(0x7f000001); 881 882 if (!first) 883 first = temp; 884 885 if (addr) 886 addr->next = temp; 887 } 888 } 889 else if (!hostname) 890 { 891 /* 892 * Provide one or more passive listening addresses... 893 */ 894 895 #ifdef AF_INET6 896 if (family != AF_INET) 897 { 898 /* 899 * Add [::] to the address list... 900 */ 901 902 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 903 if (!temp) 904 { 905 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 906 httpAddrFreeList(first); 907 return (NULL); 908 } 909 910 temp->addr.ipv6.sin6_family = AF_INET6; 911 temp->addr.ipv6.sin6_port = htons(portnum); 912 913 if (!first) 914 first = temp; 915 916 addr = temp; 917 } 918 919 if (family != AF_INET6) 920 #endif /* AF_INET6 */ 921 { 922 /* 923 * Add 0.0.0.0 to the address list... 924 */ 925 926 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); 927 if (!temp) 928 { 929 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 930 httpAddrFreeList(first); 931 return (NULL); 932 } 933 934 temp->addr.ipv4.sin_family = AF_INET; 935 temp->addr.ipv4.sin_port = htons(portnum); 936 937 if (!first) 938 first = temp; 939 940 if (addr) 941 addr->next = temp; 942 } 943 } 944 } 945 946 /* 947 * Return the address list... 948 */ 949 950 return (first); 951 } 952