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