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