1/*
2 * "$Id: http-addrlist.c 11645 2014-02-27 16:35:53Z msweet $"
3 *
4 * HTTP address list routines for CUPS.
5 *
6 * Copyright 2007-2014 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), (socklen_t)httpAddrLength(&(addrlist->addr))))
184    {
185      DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...",
186		    httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
187		    httpAddrPort(&(addrlist->addr))));
188
189#ifdef O_NONBLOCK
190      fcntl(*sock, F_SETFL, flags);
191#endif /* O_NONBLOCK */
192
193      return (addrlist);
194    }
195
196#ifdef O_NONBLOCK
197#  ifdef WIN32
198    if (WSAGetLastError() == WSAEINPROGRESS ||
199        WSAGetLastError() == WSAEWOULDBLOCK)
200#  else
201    if (errno == EINPROGRESS || errno == EWOULDBLOCK)
202#  endif /* WIN32 */
203    {
204      DEBUG_puts("1httpAddrConnect2: Finishing async connect()");
205
206      fcntl(*sock, F_SETFL, flags);
207
208      for (remaining = msec; remaining > 0; remaining -= 250)
209      {
210	do
211        {
212          if (cancel && *cancel)
213          {
214	   /*
215	    * Close this socket and return...
216	    */
217
218            DEBUG_puts("1httpAddrConnect2: Canceled connect()");
219
220            httpAddrClose(NULL, *sock);
221
222	    *sock = -1;
223
224	    return (NULL);
225          }
226
227#  ifdef HAVE_POLL
228	  pfd.fd     = *sock;
229	  pfd.events = POLLIN | POLLOUT;
230
231          nfds = poll(&pfd, 1, remaining > 250 ? 250 : remaining);
232
233	  DEBUG_printf(("1httpAddrConnect2: poll() returned %d (%d)", nfds,
234	                errno));
235
236#  else
237	  FD_ZERO(&input_set);
238	  FD_SET(*sock, &input_set);
239	  output_set = input_set;
240
241	  timeout.tv_sec  = 0;
242	  timeout.tv_usec = (remaining > 250 ? 250 : remaining) * 1000;
243
244	  nfds = select(*sock + 1, &input_set, &output_set, NULL, &timeout);
245
246	  DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", nfds,
247	                errno));
248#  endif /* HAVE_POLL */
249	}
250#  ifdef WIN32
251	while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
252			    WSAGetLastError() == WSAEWOULDBLOCK));
253#  else
254	while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
255#  endif /* WIN32 */
256
257        if (nfds > 0)
258        {
259          len = sizeof(peer);
260          if (!getpeername(*sock, (struct sockaddr *)&peer, &len))
261          {
262	    DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...",
263			  httpAddrString(&peer, temp, sizeof(temp)),
264			  httpAddrPort(&peer)));
265
266	    return (addrlist);
267	  }
268
269          break;
270        }
271      }
272    }
273#endif /* O_NONBLOCK */
274
275    DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s",
276		  httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
277		  httpAddrPort(&(addrlist->addr)), strerror(errno)));
278
279#ifndef WIN32
280    if (errno == EINPROGRESS)
281      errno = ETIMEDOUT;
282#endif /* !WIN32 */
283
284   /*
285    * Close this socket and move to the next address...
286    */
287
288    httpAddrClose(NULL, *sock);
289
290    *sock    = -1;
291    addrlist = addrlist->next;
292  }
293
294  if (!addrlist)
295#ifdef WIN32
296    _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0);
297#else
298    _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0);
299#endif /* WIN32 */
300
301  return (addrlist);
302}
303
304
305
306/*
307 * 'httpAddrCopyList()' - Copy an address list.
308 *
309 * @since CUPS 1.7/OS X 10.9@
310 */
311
312http_addrlist_t	*			/* O - New address list or @code NULL@ on error */
313httpAddrCopyList(
314    http_addrlist_t *src)		/* I - Source address list */
315{
316  http_addrlist_t	*dst = NULL,	/* First list entry */
317			*prev = NULL,	/* Previous list entry */
318			*current = NULL;/* Current list entry */
319
320
321  while (src)
322  {
323    if ((current = malloc(sizeof(http_addrlist_t))) == NULL)
324    {
325      current = dst;
326
327      while (current)
328      {
329        prev    = current;
330        current = current->next;
331
332        free(prev);
333      }
334
335      return (NULL);
336    }
337
338    memcpy(current, src, sizeof(http_addrlist_t));
339
340    current->next = NULL;
341
342    if (prev)
343      prev->next = current;
344    else
345      dst = current;
346
347    prev = current;
348    src  = src->next;
349  }
350
351  return (dst);
352}
353
354
355/*
356 * 'httpAddrFreeList()' - Free an address list.
357 *
358 * @since CUPS 1.2/OS X 10.5@
359 */
360
361void
362httpAddrFreeList(
363    http_addrlist_t *addrlist)		/* I - Address list to free */
364{
365  http_addrlist_t	*next;		/* Next address in list */
366
367
368 /*
369  * Free each address in the list...
370  */
371
372  while (addrlist)
373  {
374    next = addrlist->next;
375
376    free(addrlist);
377
378    addrlist = next;
379  }
380}
381
382
383/*
384 * 'httpAddrGetList()' - Get a list of addresses for a hostname.
385 *
386 * @since CUPS 1.2/OS X 10.5@
387 */
388
389http_addrlist_t	*			/* O - List of addresses or NULL */
390httpAddrGetList(const char *hostname,	/* I - Hostname, IP address, or NULL for passive listen address */
391                int        family,	/* I - Address family or AF_UNSPEC */
392		const char *service)	/* I - Service name or port number */
393{
394  http_addrlist_t	*first,		/* First address in list */
395			*addr,		/* Current address in list */
396			*temp;		/* New address */
397  _cups_globals_t	*cg = _cupsGlobals();
398					/* Global data */
399
400
401#ifdef DEBUG
402  _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, "
403                     "service=\"%s\")\n",
404		     hostname ? hostname : "(nil)",
405		     family == AF_UNSPEC ? "UNSPEC" :
406#  ifdef AF_LOCAL
407	                 family == AF_LOCAL ? "LOCAL" :
408#  endif /* AF_LOCAL */
409#  ifdef AF_INET6
410	                 family == AF_INET6 ? "INET6" :
411#  endif /* AF_INET6 */
412	                 family == AF_INET ? "INET" : "???", service);
413#endif /* DEBUG */
414
415#ifdef HAVE_RES_INIT
416 /*
417  * STR #2920: Initialize resolver after failure in cups-polld
418  *
419  * If the previous lookup failed, re-initialize the resolver to prevent
420  * temporary network errors from persisting.  This *should* be handled by
421  * the resolver libraries, but apparently the glibc folks do not agree.
422  *
423  * We set a flag at the end of this function if we encounter an error that
424  * requires reinitialization of the resolver functions.  We then call
425  * res_init() if the flag is set on the next call here or in httpAddrLookup().
426  */
427
428  if (cg->need_res_init)
429  {
430    res_init();
431
432    cg->need_res_init = 0;
433  }
434#endif /* HAVE_RES_INIT */
435
436 /*
437  * Lookup the address the best way we can...
438  */
439
440  first = addr = NULL;
441
442#ifdef AF_LOCAL
443  if (hostname && hostname[0] == '/')
444  {
445   /*
446    * Domain socket address...
447    */
448
449    if ((first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t))) != NULL)
450    {
451      addr = first;
452      first->addr.un.sun_family = AF_LOCAL;
453      strlcpy(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path));
454    }
455  }
456  else
457#endif /* AF_LOCAL */
458  if (!hostname || _cups_strcasecmp(hostname, "localhost"))
459  {
460#ifdef HAVE_GETADDRINFO
461    struct addrinfo	hints,		/* Address lookup hints */
462			*results,	/* Address lookup results */
463			*current;	/* Current result */
464    char		ipv6[64],	/* IPv6 address */
465			*ipv6zone;	/* Pointer to zone separator */
466    int			ipv6len;	/* Length of IPv6 address */
467    int			error;		/* getaddrinfo() error */
468
469
470   /*
471    * Lookup the address as needed...
472    */
473
474    memset(&hints, 0, sizeof(hints));
475    hints.ai_family   = family;
476    hints.ai_flags    = hostname ? 0 : AI_PASSIVE;
477    hints.ai_socktype = SOCK_STREAM;
478
479    if (hostname && *hostname == '[')
480    {
481     /*
482      * Remove brackets from numeric IPv6 address...
483      */
484
485      if (!strncmp(hostname, "[v1.", 4))
486      {
487       /*
488        * Copy the newer address format which supports link-local addresses...
489	*/
490
491	strlcpy(ipv6, hostname + 4, sizeof(ipv6));
492	if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
493	{
494          ipv6[ipv6len] = '\0';
495	  hostname      = ipv6;
496
497         /*
498	  * Convert "+zone" in address to "%zone"...
499	  */
500
501          if ((ipv6zone = strrchr(ipv6, '+')) != NULL)
502	    *ipv6zone = '%';
503	}
504      }
505      else
506      {
507       /*
508        * Copy the regular non-link-local IPv6 address...
509	*/
510
511	strlcpy(ipv6, hostname + 1, sizeof(ipv6));
512	if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
513	{
514          ipv6[ipv6len] = '\0';
515	  hostname      = ipv6;
516	}
517      }
518    }
519
520    if ((error = getaddrinfo(hostname, service, &hints, &results)) == 0)
521    {
522     /*
523      * Copy the results to our own address list structure...
524      */
525
526      for (current = results; current; current = current->ai_next)
527        if (current->ai_family == AF_INET || current->ai_family == AF_INET6)
528	{
529	 /*
530          * Copy the address over...
531	  */
532
533	  temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
534	  if (!temp)
535	  {
536	    httpAddrFreeList(first);
537	    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
538	    return (NULL);
539	  }
540
541          if (current->ai_family == AF_INET6)
542	    memcpy(&(temp->addr.ipv6), current->ai_addr,
543	           sizeof(temp->addr.ipv6));
544	  else
545	    memcpy(&(temp->addr.ipv4), current->ai_addr,
546	           sizeof(temp->addr.ipv4));
547
548         /*
549	  * Append the address to the list...
550	  */
551
552	  if (!first)
553	    first = temp;
554
555	  if (addr)
556	    addr->next = temp;
557
558	  addr = temp;
559	}
560
561     /*
562      * Free the results from getaddrinfo()...
563      */
564
565      freeaddrinfo(results);
566    }
567    else
568    {
569      if (error == EAI_FAIL)
570        cg->need_res_init = 1;
571
572      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerror(error), 0);
573    }
574
575#else
576    if (hostname)
577    {
578      int		i;		/* Looping vars */
579      unsigned		ip[4];		/* IPv4 address components */
580      const char	*ptr;		/* Pointer into hostname */
581      struct hostent	*host;		/* Result of lookup */
582      struct servent	*port;		/* Port number for service */
583      int		portnum;	/* Port number */
584
585
586     /*
587      * Lookup the service...
588      */
589
590      if (!service)
591	portnum = 0;
592      else if (isdigit(*service & 255))
593	portnum = atoi(service);
594      else if ((port = getservbyname(service, NULL)) != NULL)
595	portnum = ntohs(port->s_port);
596      else if (!strcmp(service, "http"))
597        portnum = 80;
598      else if (!strcmp(service, "https"))
599        portnum = 443;
600      else if (!strcmp(service, "ipp") || !strcmp(service, "ipps"))
601        portnum = 631;
602      else if (!strcmp(service, "lpd"))
603        portnum = 515;
604      else if (!strcmp(service, "socket"))
605        portnum = 9100;
606      else
607	return (NULL);
608
609     /*
610      * This code is needed because some operating systems have a
611      * buggy implementation of gethostbyname() that does not support
612      * IPv4 addresses.  If the hostname string is an IPv4 address, then
613      * sscanf() is used to extract the IPv4 components.  We then pack
614      * the components into an IPv4 address manually, since the
615      * inet_aton() function is deprecated.  We use the htonl() macro
616      * to get the right byte order for the address.
617      */
618
619      for (ptr = hostname; isdigit(*ptr & 255) || *ptr == '.'; ptr ++);
620
621      if (!*ptr)
622      {
623       /*
624	* We have an IPv4 address; break it up and create an IPv4 address...
625	*/
626
627	if (sscanf(hostname, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) == 4 &&
628            ip[0] <= 255 && ip[1] <= 255 && ip[2] <= 255 && ip[3] <= 255)
629	{
630	  first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
631	  if (!first)
632	    return (NULL);
633
634          first->addr.ipv4.sin_family = AF_INET;
635          first->addr.ipv4.sin_addr.s_addr = htonl((((((((unsigned)ip[0] << 8) |
636	                                               (unsigned)ip[1]) << 8) |
637						     (unsigned)ip[2]) << 8) |
638						   (unsigned)ip[3]));
639          first->addr.ipv4.sin_port = htons(portnum);
640	}
641      }
642      else if ((host = gethostbyname(hostname)) != NULL &&
643#  ifdef AF_INET6
644               (host->h_addrtype == AF_INET || host->h_addrtype == AF_INET6))
645#  else
646               host->h_addrtype == AF_INET)
647#  endif /* AF_INET6 */
648      {
649	for (i = 0; host->h_addr_list[i]; i ++)
650	{
651	 /*
652          * Copy the address over...
653	  */
654
655	  temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
656	  if (!temp)
657	  {
658	    httpAddrFreeList(first);
659	    return (NULL);
660	  }
661
662#  ifdef AF_INET6
663          if (host->h_addrtype == AF_INET6)
664	  {
665            temp->addr.ipv6.sin6_family = AF_INET6;
666	    memcpy(&(temp->addr.ipv6.sin6_addr), host->h_addr_list[i],
667	           sizeof(temp->addr.ipv6));
668            temp->addr.ipv6.sin6_port = htons(portnum);
669	  }
670	  else
671#  endif /* AF_INET6 */
672	  {
673            temp->addr.ipv4.sin_family = AF_INET;
674	    memcpy(&(temp->addr.ipv4.sin_addr), host->h_addr_list[i],
675	           sizeof(temp->addr.ipv4));
676            temp->addr.ipv4.sin_port = htons(portnum);
677          }
678
679	 /*
680	  * Append the address to the list...
681	  */
682
683	  if (!first)
684	    first = temp;
685
686	  if (addr)
687	    addr->next = temp;
688
689	  addr = temp;
690	}
691      }
692      else
693      {
694        if (h_errno == NO_RECOVERY)
695          cg->need_res_init = 1;
696
697	_cupsSetError(IPP_STATUS_ERROR_INTERNAL, hstrerror(h_errno), 0);
698      }
699    }
700#endif /* HAVE_GETADDRINFO */
701  }
702
703 /*
704  * Detect some common errors and handle them sanely...
705  */
706
707  if (!addr && (!hostname || !_cups_strcasecmp(hostname, "localhost")))
708  {
709    struct servent	*port;		/* Port number for service */
710    int			portnum;	/* Port number */
711
712
713   /*
714    * Lookup the service...
715    */
716
717    if (!service)
718      portnum = 0;
719    else if (isdigit(*service & 255))
720      portnum = atoi(service);
721    else if ((port = getservbyname(service, NULL)) != NULL)
722      portnum = ntohs(port->s_port);
723    else if (!strcmp(service, "http"))
724      portnum = 80;
725    else if (!strcmp(service, "https"))
726      portnum = 443;
727    else if (!strcmp(service, "ipp") || !strcmp(service, "ipps"))
728      portnum = 631;
729    else if (!strcmp(service, "lpd"))
730      portnum = 515;
731    else if (!strcmp(service, "socket"))
732      portnum = 9100;
733    else
734    {
735      httpAddrFreeList(first);
736
737      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown service name."), 1);
738      return (NULL);
739    }
740
741    if (hostname && !_cups_strcasecmp(hostname, "localhost"))
742    {
743     /*
744      * Unfortunately, some users ignore all of the warnings in the
745      * /etc/hosts file and delete "localhost" from it. If we get here
746      * then we were unable to resolve the name, so use the IPv6 and/or
747      * IPv4 loopback interface addresses...
748      */
749
750#ifdef AF_INET6
751      if (family != AF_INET)
752      {
753       /*
754        * Add [::1] to the address list...
755	*/
756
757	temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
758	if (!temp)
759	{
760	  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
761	  httpAddrFreeList(first);
762	  return (NULL);
763	}
764
765        temp->addr.ipv6.sin6_family            = AF_INET6;
766	temp->addr.ipv6.sin6_port              = htons(portnum);
767#  ifdef WIN32
768	temp->addr.ipv6.sin6_addr.u.Byte[15]   = 1;
769#  else
770	temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1);
771#  endif /* WIN32 */
772
773        if (!first)
774          first = temp;
775
776        addr = temp;
777      }
778
779      if (family != AF_INET6)
780#endif /* AF_INET6 */
781      {
782       /*
783        * Add 127.0.0.1 to the address list...
784	*/
785
786	temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
787	if (!temp)
788	{
789	  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
790	  httpAddrFreeList(first);
791	  return (NULL);
792	}
793
794        temp->addr.ipv4.sin_family      = AF_INET;
795	temp->addr.ipv4.sin_port        = htons(portnum);
796	temp->addr.ipv4.sin_addr.s_addr = htonl(0x7f000001);
797
798        if (!first)
799          first = temp;
800
801        if (addr)
802	  addr->next = temp;
803      }
804    }
805    else if (!hostname)
806    {
807     /*
808      * Provide one or more passive listening addresses...
809      */
810
811#ifdef AF_INET6
812      if (family != AF_INET)
813      {
814       /*
815        * Add [::] to the address list...
816	*/
817
818	temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
819	if (!temp)
820	{
821	  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
822	  httpAddrFreeList(first);
823	  return (NULL);
824	}
825
826        temp->addr.ipv6.sin6_family = AF_INET6;
827	temp->addr.ipv6.sin6_port   = htons(portnum);
828
829        if (!first)
830          first = temp;
831
832        addr = temp;
833      }
834
835      if (family != AF_INET6)
836#endif /* AF_INET6 */
837      {
838       /*
839        * Add 0.0.0.0 to the address list...
840	*/
841
842	temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
843	if (!temp)
844	{
845	  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
846	  httpAddrFreeList(first);
847	  return (NULL);
848	}
849
850        temp->addr.ipv4.sin_family = AF_INET;
851	temp->addr.ipv4.sin_port   = htons(portnum);
852
853        if (!first)
854          first = temp;
855
856        if (addr)
857	  addr->next = temp;
858      }
859    }
860  }
861
862 /*
863  * Return the address list...
864  */
865
866  return (first);
867}
868
869
870/*
871 * End of "$Id: http-addrlist.c 11645 2014-02-27 16:35:53Z msweet $".
872 */
873