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