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