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