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