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