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 * Licensed under Apache License v2.0. See the file "LICENSE" for more
8 * information.
9 */
10
11 /*
12 * Include necessary headers...
13 */
14
15 #include "cups-private.h"
16 #include "debug-internal.h"
17 #ifdef HAVE_RESOLV_H
18 # include <resolv.h>
19 #endif /* HAVE_RESOLV_H */
20 #ifdef HAVE_POLL
21 # include <poll.h>
22 #endif /* HAVE_POLL */
23 #ifndef _WIN32
24 # include <fcntl.h>
25 #endif /* _WIN32 */
26
27
28 /*
29 * 'httpAddrConnect()' - Connect to any of the addresses in the list.
30 *
31 * @since CUPS 1.2/macOS 10.5@ @exclude all@
32 */
33
34 http_addrlist_t * /* O - Connected address or NULL on failure */
httpAddrConnect(http_addrlist_t * addrlist,int * sock)35 httpAddrConnect(
36 http_addrlist_t *addrlist, /* I - List of potential addresses */
37 int *sock) /* O - Socket */
38 {
39 DEBUG_printf(("httpAddrConnect(addrlist=%p, sock=%p)", (void *)addrlist, (void *)sock));
40
41 return (httpAddrConnect2(addrlist, sock, 30000, NULL));
42 }
43
44
45 /*
46 * 'httpAddrConnect2()' - Connect to any of the addresses in the list with a
47 * timeout and optional cancel.
48 *
49 * @since CUPS 1.7/macOS 10.9@
50 */
51
52 http_addrlist_t * /* O - Connected address or NULL on failure */
httpAddrConnect2(http_addrlist_t * addrlist,int * sock,int msec,int * cancel)53 httpAddrConnect2(
54 http_addrlist_t *addrlist, /* I - List of potential addresses */
55 int *sock, /* O - Socket */
56 int msec, /* I - Timeout in milliseconds */
57 int *cancel) /* I - Pointer to "cancel" variable */
58 {
59 int val; /* Socket option value */
60 #ifndef _WIN32
61 int i, j, /* Looping vars */
62 flags, /* Socket flags */
63 result; /* Result from select() or poll() */
64 #endif /* !_WIN32 */
65 int remaining; /* Remaining timeout */
66 int nfds, /* Number of file descriptors */
67 fds[100]; /* Socket file descriptors */
68 http_addrlist_t *addrs[100]; /* Addresses */
69 #ifndef HAVE_POLL
70 int max_fd = -1; /* Highest file descriptor */
71 #endif /* !HAVE_POLL */
72 #ifdef O_NONBLOCK
73 # ifdef HAVE_POLL
74 struct pollfd pfds[100]; /* Polled file descriptors */
75 # else
76 fd_set input_set, /* select() input set */
77 output_set, /* select() output set */
78 error_set; /* select() error set */
79 struct timeval timeout; /* Timeout */
80 # endif /* HAVE_POLL */
81 #endif /* O_NONBLOCK */
82 #ifdef DEBUG
83 # ifndef _WIN32
84 socklen_t len; /* Length of value */
85 http_addr_t peer; /* Peer address */
86 # endif /* !_WIN32 */
87 char temp[256]; /* Temporary address string */
88 #endif /* DEBUG */
89
90
91 DEBUG_printf(("httpAddrConnect2(addrlist=%p, sock=%p, msec=%d, cancel=%p)", (void *)addrlist, (void *)sock, msec, (void *)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 nfds = 0;
111 remaining = msec;
112
113 while (remaining > 0)
114 {
115 if (cancel && *cancel)
116 {
117 while (nfds > 0)
118 {
119 nfds --;
120 httpAddrClose(NULL, fds[nfds]);
121 }
122
123 return (NULL);
124 }
125
126 if (addrlist && nfds < (int)(sizeof(fds) / sizeof(fds[0])))
127 {
128 /*
129 * Create the socket...
130 */
131
132 DEBUG_printf(("2httpAddrConnect2: Trying %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr))));
133
134 if ((fds[nfds] = (int)socket(httpAddrFamily(&(addrlist->addr)), SOCK_STREAM, 0)) < 0)
135 {
136 /*
137 * Don't abort yet, as this could just be an issue with the local
138 * system not being configured with IPv4/IPv6/domain socket enabled.
139 *
140 * Just skip this address...
141 */
142
143 addrlist = addrlist->next;
144 continue;
145 }
146
147 /*
148 * Set options...
149 */
150
151 val = 1;
152 setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val));
153
154 #ifdef SO_REUSEPORT
155 val = 1;
156 setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEPORT, CUPS_SOCAST &val, sizeof(val));
157 #endif /* SO_REUSEPORT */
158
159 #ifdef SO_NOSIGPIPE
160 val = 1;
161 setsockopt(fds[nfds], SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
162 #endif /* SO_NOSIGPIPE */
163
164 /*
165 * Using TCP_NODELAY improves responsiveness, especially on systems
166 * with a slow loopback interface...
167 */
168
169 val = 1;
170 setsockopt(fds[nfds], IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val));
171
172 #ifdef FD_CLOEXEC
173 /*
174 * Close this socket when starting another process...
175 */
176
177 fcntl(fds[nfds], F_SETFD, FD_CLOEXEC);
178 #endif /* FD_CLOEXEC */
179
180 #ifdef O_NONBLOCK
181 /*
182 * Do an asynchronous connect by setting the socket non-blocking...
183 */
184
185 DEBUG_printf(("httpAddrConnect2: Setting non-blocking connect()"));
186
187 flags = fcntl(fds[nfds], F_GETFL, 0);
188 fcntl(fds[nfds], F_SETFL, flags | O_NONBLOCK);
189 #endif /* O_NONBLOCK */
190
191 /*
192 * Then connect...
193 */
194
195 if (!connect(fds[nfds], &(addrlist->addr.addr), (socklen_t)httpAddrLength(&(addrlist->addr))))
196 {
197 DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr))));
198
199 #ifdef O_NONBLOCK
200 fcntl(fds[nfds], F_SETFL, flags);
201 #endif /* O_NONBLOCK */
202
203 *sock = fds[nfds];
204
205 while (nfds > 0)
206 {
207 nfds --;
208 httpAddrClose(NULL, fds[nfds]);
209 }
210
211 return (addrlist);
212 }
213
214 #ifdef _WIN32
215 if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK)
216 #else
217 if (errno != EINPROGRESS && errno != EWOULDBLOCK)
218 #endif /* _WIN32 */
219 {
220 DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)), strerror(errno)));
221 httpAddrClose(NULL, fds[nfds]);
222 addrlist = addrlist->next;
223 continue;
224 }
225
226 #ifndef _WIN32
227 fcntl(fds[nfds], F_SETFL, flags);
228 #endif /* !_WIN32 */
229
230 #ifndef HAVE_POLL
231 if (fds[nfds] > max_fd)
232 max_fd = fds[nfds];
233 #endif /* !HAVE_POLL */
234
235 addrs[nfds] = addrlist;
236 nfds ++;
237 addrlist = addrlist->next;
238 }
239
240 if (!addrlist && nfds == 0)
241 break;
242
243 /*
244 * See if we can connect to any of the addresses so far...
245 */
246
247 #ifdef O_NONBLOCK
248 DEBUG_puts("1httpAddrConnect2: Finishing async connect()");
249
250 do
251 {
252 if (cancel && *cancel)
253 {
254 /*
255 * Close this socket and return...
256 */
257
258 DEBUG_puts("1httpAddrConnect2: Canceled connect()");
259
260 while (nfds > 0)
261 {
262 nfds --;
263 httpAddrClose(NULL, fds[nfds]);
264 }
265
266 *sock = -1;
267
268 return (NULL);
269 }
270
271 # ifdef HAVE_POLL
272 for (i = 0; i < nfds; i ++)
273 {
274 pfds[i].fd = fds[i];
275 pfds[i].events = POLLIN | POLLOUT;
276 }
277
278 result = poll(pfds, (nfds_t)nfds, addrlist ? 100 : remaining > 250 ? 250 : remaining);
279
280 DEBUG_printf(("1httpAddrConnect2: poll() returned %d (%d)", result, errno));
281
282 # else
283 FD_ZERO(&input_set);
284 for (i = 0; i < nfds; i ++)
285 FD_SET(fds[i], &input_set);
286 output_set = input_set;
287 error_set = input_set;
288
289 timeout.tv_sec = 0;
290 timeout.tv_usec = (addrlist ? 100 : remaining > 250 ? 250 : remaining) * 1000;
291
292 result = select(max_fd + 1, &input_set, &output_set, &error_set, &timeout);
293
294 DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", result, errno));
295 # endif /* HAVE_POLL */
296 }
297 # ifdef _WIN32
298 while (result < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK));
299 # else
300 while (result < 0 && (errno == EINTR || errno == EAGAIN));
301 # endif /* _WIN32 */
302
303 if (result > 0)
304 {
305 http_addrlist_t *connaddr = NULL; /* Connected address, if any */
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_set) && !FD_ISSET(fds[i], &error_set))
314 # endif /* HAVE_POLL */
315 {
316 *sock = fds[i];
317 connaddr = 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 break;
326 }
327 # ifdef HAVE_POLL
328 else if (pfds[i].revents & (POLLERR | POLLHUP))
329 # else
330 else if (FD_ISSET(fds[i], &error_set))
331 # endif /* HAVE_POLL */
332 {
333 /*
334 * Error on socket, remove from the "pool"...
335 */
336
337 httpAddrClose(NULL, fds[i]);
338 nfds --;
339 if (i < nfds)
340 {
341 memmove(fds + i, fds + i + 1, (size_t)(nfds - i) * (sizeof(fds[0])));
342 memmove(addrs + i, addrs + i + 1, (size_t)(nfds - i) * (sizeof(addrs[0])));
343 }
344 i --;
345 }
346 }
347
348 if (connaddr)
349 {
350 /*
351 * Connected on one address, close all of the other sockets we have so
352 * far and return...
353 */
354
355 for (j = 0; j < i; j ++)
356 httpAddrClose(NULL, fds[j]);
357
358 for (j ++; j < nfds; j ++)
359 httpAddrClose(NULL, fds[j]);
360
361 return (connaddr);
362 }
363 }
364 #endif /* O_NONBLOCK */
365
366 if (addrlist)
367 remaining -= 100;
368 else
369 remaining -= 250;
370 }
371
372 while (nfds > 0)
373 {
374 nfds --;
375 httpAddrClose(NULL, fds[nfds]);
376 }
377
378 #ifdef _WIN32
379 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0);
380 #else
381 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0);
382 #endif /* _WIN32 */
383
384 return (NULL);
385 }
386
387
388 /*
389 * 'httpAddrCopyList()' - Copy an address list.
390 *
391 * @since CUPS 1.7/macOS 10.9@
392 */
393
394 http_addrlist_t * /* O - New address list or @code NULL@ on error */
httpAddrCopyList(http_addrlist_t * src)395 httpAddrCopyList(
396 http_addrlist_t *src) /* I - Source address list */
397 {
398 http_addrlist_t *dst = NULL, /* First list entry */
399 *prev = NULL, /* Previous list entry */
400 *current = NULL;/* Current list entry */
401
402
403 while (src)
404 {
405 if ((current = malloc(sizeof(http_addrlist_t))) == NULL)
406 {
407 current = dst;
408
409 while (current)
410 {
411 prev = current;
412 current = current->next;
413
414 free(prev);
415 }
416
417 return (NULL);
418 }
419
420 memcpy(current, src, sizeof(http_addrlist_t));
421
422 current->next = NULL;
423
424 if (prev)
425 prev->next = current;
426 else
427 dst = current;
428
429 prev = current;
430 src = src->next;
431 }
432
433 return (dst);
434 }
435
436
437 /*
438 * 'httpAddrFreeList()' - Free an address list.
439 *
440 * @since CUPS 1.2/macOS 10.5@
441 */
442
443 void
httpAddrFreeList(http_addrlist_t * addrlist)444 httpAddrFreeList(
445 http_addrlist_t *addrlist) /* I - Address list to free */
446 {
447 http_addrlist_t *next; /* Next address in list */
448
449
450 /*
451 * Free each address in the list...
452 */
453
454 while (addrlist)
455 {
456 next = addrlist->next;
457
458 free(addrlist);
459
460 addrlist = next;
461 }
462 }
463
464
465 /*
466 * 'httpAddrGetList()' - Get a list of addresses for a hostname.
467 *
468 * @since CUPS 1.2/macOS 10.5@
469 */
470
471 http_addrlist_t * /* O - List of addresses or NULL */
httpAddrGetList(const char * hostname,int family,const char * service)472 httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for passive listen address */
473 int family, /* I - Address family or AF_UNSPEC */
474 const char *service) /* I - Service name or port number */
475 {
476 http_addrlist_t *first, /* First address in list */
477 *addr, /* Current address in list */
478 *temp; /* New address */
479 _cups_globals_t *cg = _cupsGlobals();
480 /* Global data */
481
482
483 #ifdef DEBUG
484 _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, "
485 "service=\"%s\")\n",
486 hostname ? hostname : "(nil)",
487 family == AF_UNSPEC ? "UNSPEC" :
488 # ifdef AF_LOCAL
489 family == AF_LOCAL ? "LOCAL" :
490 # endif /* AF_LOCAL */
491 # ifdef AF_INET6
492 family == AF_INET6 ? "INET6" :
493 # endif /* AF_INET6 */
494 family == AF_INET ? "INET" : "???", service);
495 #endif /* DEBUG */
496
497 #ifdef HAVE_RES_INIT
498 /*
499 * STR #2920: Initialize resolver after failure in cups-polld
500 *
501 * If the previous lookup failed, re-initialize the resolver to prevent
502 * temporary network errors from persisting. This *should* be handled by
503 * the resolver libraries, but apparently the glibc folks do not agree.
504 *
505 * We set a flag at the end of this function if we encounter an error that
506 * requires reinitialization of the resolver functions. We then call
507 * res_init() if the flag is set on the next call here or in httpAddrLookup().
508 */
509
510 if (cg->need_res_init)
511 {
512 res_init();
513
514 cg->need_res_init = 0;
515 }
516 #endif /* HAVE_RES_INIT */
517
518 /*
519 * Lookup the address the best way we can...
520 */
521
522 first = addr = NULL;
523
524 #ifdef AF_LOCAL
525 if (hostname && hostname[0] == '/')
526 {
527 /*
528 * Domain socket address...
529 */
530
531 if ((first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t))) != NULL)
532 {
533 addr = first;
534 first->addr.un.sun_family = AF_LOCAL;
535 strlcpy(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path));
536 }
537 }
538 else
539 #endif /* AF_LOCAL */
540 if (!hostname || _cups_strcasecmp(hostname, "localhost"))
541 {
542 #ifdef HAVE_GETADDRINFO
543 struct addrinfo hints, /* Address lookup hints */
544 *results, /* Address lookup results */
545 *current; /* Current result */
546 char ipv6[64], /* IPv6 address */
547 *ipv6zone; /* Pointer to zone separator */
548 int ipv6len; /* Length of IPv6 address */
549 int error; /* getaddrinfo() error */
550
551
552 /*
553 * Lookup the address as needed...
554 */
555
556 memset(&hints, 0, sizeof(hints));
557 hints.ai_family = family;
558 hints.ai_flags = hostname ? 0 : AI_PASSIVE;
559 hints.ai_socktype = SOCK_STREAM;
560
561 if (hostname && *hostname == '[')
562 {
563 /*
564 * Remove brackets from numeric IPv6 address...
565 */
566
567 if (!strncmp(hostname, "[v1.", 4))
568 {
569 /*
570 * Copy the newer address format which supports link-local addresses...
571 */
572
573 strlcpy(ipv6, hostname + 4, sizeof(ipv6));
574 if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
575 {
576 ipv6[ipv6len] = '\0';
577 hostname = ipv6;
578
579 /*
580 * Convert "+zone" in address to "%zone"...
581 */
582
583 if ((ipv6zone = strrchr(ipv6, '+')) != NULL)
584 *ipv6zone = '%';
585 }
586 }
587 else
588 {
589 /*
590 * Copy the regular non-link-local IPv6 address...
591 */
592
593 strlcpy(ipv6, hostname + 1, sizeof(ipv6));
594 if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
595 {
596 ipv6[ipv6len] = '\0';
597 hostname = ipv6;
598 }
599 }
600 }
601
602 if ((error = getaddrinfo(hostname, service, &hints, &results)) == 0)
603 {
604 /*
605 * Copy the results to our own address list structure...
606 */
607
608 for (current = results; current; current = current->ai_next)
609 if (current->ai_family == AF_INET || current->ai_family == AF_INET6)
610 {
611 /*
612 * Copy the address over...
613 */
614
615 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
616 if (!temp)
617 {
618 httpAddrFreeList(first);
619 freeaddrinfo(results);
620 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
621 return (NULL);
622 }
623
624 if (current->ai_family == AF_INET6)
625 memcpy(&(temp->addr.ipv6), current->ai_addr,
626 sizeof(temp->addr.ipv6));
627 else
628 memcpy(&(temp->addr.ipv4), current->ai_addr,
629 sizeof(temp->addr.ipv4));
630
631 /*
632 * Append the address to the list...
633 */
634
635 if (!first)
636 first = temp;
637
638 if (addr)
639 addr->next = temp;
640
641 addr = temp;
642 }
643
644 /*
645 * Free the results from getaddrinfo()...
646 */
647
648 freeaddrinfo(results);
649 }
650 else
651 {
652 if (error == EAI_FAIL)
653 cg->need_res_init = 1;
654
655 # ifdef _WIN32 /* Really, Microsoft?!? */
656 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerrorA(error), 0);
657 # else
658 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerror(error), 0);
659 # endif /* _WIN32 */
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