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