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