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