]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/http-addrlist.c
Several libcups files did not have the Apple license exception notice (STR #4361)
[thirdparty/cups.git] / cups / http-addrlist.c
1 /*
2 * "$Id$"
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
40 http_addrlist_t * /* O - Connected address or NULL on failure */
41 httpAddrConnect(
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
58 http_addrlist_t * /* O - Connected address or NULL on failure */
59 httpAddrConnect2(
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
312 http_addrlist_t * /* O - New address list or @code NULL@ on error */
313 httpAddrCopyList(
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
361 void
362 httpAddrFreeList(
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
389 http_addrlist_t * /* O - List of addresses or NULL */
390 httpAddrGetList(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$".
872 */