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