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