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