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