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