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