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