Home | History | Annotate | Download | only in cups
      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