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