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