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