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