4 * HTTP address list routines for CUPS.
6 * Copyright 2007-2013 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * httpAddrConnect() - Connect to any of the addresses in the list.
18 * httpAddrConnect2() - Connect to any of the addresses in the list with a
19 * timeout and optional cancel.
20 * httpAddrCopyList() - Copy an address list.
21 * httpAddrFreeList() - Free an address list.
22 * httpAddrGetList() - Get a list of addresses for a hostname.
26 * Include necessary headers...
29 #include "cups-private.h"
32 #endif /* HAVE_RESOLV_H */
35 #endif /* HAVE_POLL */
42 * 'httpAddrConnect()' - Connect to any of the addresses in the list.
44 * @since CUPS 1.2/OS X 10.5@
47 http_addrlist_t
* /* O - Connected address or NULL on failure */
49 http_addrlist_t
*addrlist
, /* I - List of potential addresses */
50 int *sock
) /* O - Socket */
52 DEBUG_printf(("httpAddrConnect(addrlist=%p, sock=%p)", addrlist
, sock
));
54 return (httpAddrConnect2(addrlist
, sock
, 30000, NULL
));
59 * 'httpAddrConnect2()' - Connect to any of the addresses in the list with a
60 * timeout and optional cancel.
62 * @since CUPS 1.7/OS X 10.9@
65 http_addrlist_t
* /* O - Connected address or NULL on failure */
67 http_addrlist_t
*addrlist
, /* I - List of potential addresses */
68 int *sock
, /* O - Socket */
69 int msec
, /* I - Timeout in milliseconds */
70 int *cancel
) /* I - Pointer to "cancel" variable */
72 int val
; /* Socket option value */
74 socklen_t len
; /* Length of value */
75 http_addr_t peer
; /* Peer address */
76 int flags
, /* Socket flags */
77 remaining
; /* Remaining timeout */
79 struct pollfd pfd
; /* Polled file descriptor */
81 fd_set input_set
, /* select() input set */
82 output_set
; /* select() output set */
83 struct timeval timeout
; /* Timeout */
84 # endif /* HAVE_POLL */
85 int nfds
; /* Result from select()/poll() */
86 #endif /* O_NONBLOCK */
88 char temp
[256]; /* Temporary address string */
92 DEBUG_printf(("httpAddrConnect2(addrlist=%p, sock=%p, msec=%d, cancel=%p)",
93 addrlist
, sock
, msec
, cancel
));
98 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
102 if (cancel
&& *cancel
)
105 if (msec
<= 0 || getenv("CUPS_DISABLE_ASYNC_CONNECT"))
109 * Loop through each address until we connect or run out of addresses...
114 if (cancel
&& *cancel
)
118 * Create the socket...
121 DEBUG_printf(("2httpAddrConnect2: Trying %s:%d...",
122 httpAddrString(&(addrlist
->addr
), temp
, sizeof(temp
)),
123 httpAddrPort(&(addrlist
->addr
))));
125 if ((*sock
= (int)socket(httpAddrFamily(&(addrlist
->addr
)), SOCK_STREAM
,
129 * Don't abort yet, as this could just be an issue with the local
130 * system not being configured with IPv4/IPv6/domain socket enabled...
133 addrlist
= addrlist
->next
;
142 setsockopt(*sock
, SOL_SOCKET
, SO_REUSEADDR
, CUPS_SOCAST
&val
, sizeof(val
));
146 setsockopt(*sock
, SOL_SOCKET
, SO_REUSEPORT
, CUPS_SOCAST
&val
, sizeof(val
));
147 #endif /* SO_REUSEPORT */
151 setsockopt(*sock
, SOL_SOCKET
, SO_NOSIGPIPE
, CUPS_SOCAST
&val
, sizeof(val
));
152 #endif /* SO_NOSIGPIPE */
155 * Using TCP_NODELAY improves responsiveness, especially on systems
156 * with a slow loopback interface...
160 setsockopt(*sock
, IPPROTO_TCP
, TCP_NODELAY
, CUPS_SOCAST
&val
, sizeof(val
));
164 * Close this socket when starting another process...
167 fcntl(*sock
, F_SETFD
, FD_CLOEXEC
);
168 #endif /* FD_CLOEXEC */
172 * Do an asynchronous connect by setting the socket non-blocking...
175 DEBUG_printf(("httpAddrConnect2: Setting non-blocking connect()"));
177 flags
= fcntl(*sock
, F_GETFL
, 0);
180 DEBUG_puts("httpAddrConnect2: Setting non-blocking connect()");
182 fcntl(*sock
, F_SETFL
, flags
| O_NONBLOCK
);
184 #endif /* O_NONBLOCK */
190 if (!connect(*sock
, &(addrlist
->addr
.addr
),
191 httpAddrLength(&(addrlist
->addr
))))
193 DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...",
194 httpAddrString(&(addrlist
->addr
), temp
, sizeof(temp
)),
195 httpAddrPort(&(addrlist
->addr
))));
198 fcntl(*sock
, F_SETFL
, flags
);
199 #endif /* O_NONBLOCK */
206 if (WSAGetLastError() == WSAEINPROGRESS
||
207 WSAGetLastError() == WSAEWOULDBLOCK
)
209 if (errno
== EINPROGRESS
|| errno
== EWOULDBLOCK
)
212 DEBUG_puts("1httpAddrConnect2: Finishing async connect()");
214 fcntl(*sock
, F_SETFL
, flags
);
216 for (remaining
= msec
; remaining
> 0; remaining
-= 250)
220 if (cancel
&& *cancel
)
223 * Close this socket and return...
226 DEBUG_puts("1httpAddrConnect2: Canceled connect()");
228 httpAddrClose(NULL
, *sock
);
237 pfd
.events
= POLLIN
| POLLOUT
;
239 nfds
= poll(&pfd
, 1, remaining
> 250 ? 250 : remaining
);
241 DEBUG_printf(("1httpAddrConnect2: poll() returned %d (%d)", nfds
,
246 FD_SET(*sock
, &input_set
);
247 output_set
= input_set
;
250 timeout
.tv_usec
= (remaining
> 250 ? 250 : remaining
) * 1000;
252 nfds
= select(*sock
+ 1, &input_set
, &output_set
, NULL
, &timeout
);
254 DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", nfds
,
256 # endif /* HAVE_POLL */
259 while (nfds
< 0 && (WSAGetLastError() == WSAEINTR
||
260 WSAGetLastError() == WSAEWOULDBLOCK
));
262 while (nfds
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
268 if (!getpeername(*sock
, (struct sockaddr
*)&peer
, &len
))
270 DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...",
271 httpAddrString(&peer
, temp
, sizeof(temp
)),
272 httpAddrPort(&peer
)));
281 #endif /* O_NONBLOCK */
283 DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s",
284 httpAddrString(&(addrlist
->addr
), temp
, sizeof(temp
)),
285 httpAddrPort(&(addrlist
->addr
)), strerror(errno
)));
288 if (errno
== EINPROGRESS
)
293 * Close this socket and move to the next address...
296 httpAddrClose(NULL
, *sock
);
299 addrlist
= addrlist
->next
;
304 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE
, "Connection failed", 0);
306 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE
, strerror(errno
), 0);
315 * 'httpAddrCopyList()' - Copy an address list.
317 * @since CUPS 1.7/OS X 10.9@
320 http_addrlist_t
* /* O - New address list or @code NULL@ on error */
322 http_addrlist_t
*src
) /* I - Source address list */
324 http_addrlist_t
*dst
= NULL
, /* First list entry */
325 *prev
= NULL
, /* Previous list entry */
326 *current
= NULL
;/* Current list entry */
331 if ((current
= malloc(sizeof(http_addrlist_t
))) == NULL
)
338 current
= current
->next
;
346 memcpy(current
, src
, sizeof(http_addrlist_t
));
348 current
->next
= NULL
;
351 prev
->next
= current
;
364 * 'httpAddrFreeList()' - Free an address list.
366 * @since CUPS 1.2/OS X 10.5@
371 http_addrlist_t
*addrlist
) /* I - Address list to free */
373 http_addrlist_t
*next
; /* Next address in list */
377 * Free each address in the list...
382 next
= addrlist
->next
;
392 * 'httpAddrGetList()' - Get a list of addresses for a hostname.
394 * @since CUPS 1.2/OS X 10.5@
397 http_addrlist_t
* /* O - List of addresses or NULL */
398 httpAddrGetList(const char *hostname
, /* I - Hostname, IP address, or NULL for passive listen address */
399 int family
, /* I - Address family or AF_UNSPEC */
400 const char *service
) /* I - Service name or port number */
402 http_addrlist_t
*first
, /* First address in list */
403 *addr
, /* Current address in list */
404 *temp
; /* New address */
405 _cups_globals_t
*cg
= _cupsGlobals();
410 _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, "
412 hostname
? hostname
: "(nil)",
413 family
== AF_UNSPEC
? "UNSPEC" :
415 family
== AF_LOCAL
? "LOCAL" :
416 # endif /* AF_LOCAL */
418 family
== AF_INET6
? "INET6" :
419 # endif /* AF_INET6 */
420 family
== AF_INET
? "INET" : "???", service
);
425 * STR #2920: Initialize resolver after failure in cups-polld
427 * If the previous lookup failed, re-initialize the resolver to prevent
428 * temporary network errors from persisting. This *should* be handled by
429 * the resolver libraries, but apparently the glibc folks do not agree.
431 * We set a flag at the end of this function if we encounter an error that
432 * requires reinitialization of the resolver functions. We then call
433 * res_init() if the flag is set on the next call here or in httpAddrLookup().
436 if (cg
->need_res_init
)
440 cg
->need_res_init
= 0;
442 #endif /* HAVE_RES_INIT */
445 * Lookup the address the best way we can...
451 if (hostname
&& hostname
[0] == '/')
454 * Domain socket address...
457 if ((first
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
))) != NULL
)
459 first
->addr
.un
.sun_family
= AF_LOCAL
;
460 strlcpy(first
->addr
.un
.sun_path
, hostname
, sizeof(first
->addr
.un
.sun_path
));
464 #endif /* AF_LOCAL */
465 if (!hostname
|| _cups_strcasecmp(hostname
, "localhost"))
467 #ifdef HAVE_GETADDRINFO
468 struct addrinfo hints
, /* Address lookup hints */
469 *results
, /* Address lookup results */
470 *current
; /* Current result */
471 char ipv6
[64], /* IPv6 address */
472 *ipv6zone
; /* Pointer to zone separator */
473 int ipv6len
; /* Length of IPv6 address */
474 int error
; /* getaddrinfo() error */
478 * Lookup the address as needed...
481 memset(&hints
, 0, sizeof(hints
));
482 hints
.ai_family
= family
;
483 hints
.ai_flags
= hostname
? 0 : AI_PASSIVE
;
484 hints
.ai_socktype
= SOCK_STREAM
;
486 if (hostname
&& *hostname
== '[')
489 * Remove brackets from numeric IPv6 address...
492 if (!strncmp(hostname
, "[v1.", 4))
495 * Copy the newer address format which supports link-local addresses...
498 strlcpy(ipv6
, hostname
+ 4, sizeof(ipv6
));
499 if ((ipv6len
= (int)strlen(ipv6
) - 1) >= 0 && ipv6
[ipv6len
] == ']')
501 ipv6
[ipv6len
] = '\0';
505 * Convert "+zone" in address to "%zone"...
508 if ((ipv6zone
= strrchr(ipv6
, '+')) != NULL
)
515 * Copy the regular non-link-local IPv6 address...
518 strlcpy(ipv6
, hostname
+ 1, sizeof(ipv6
));
519 if ((ipv6len
= (int)strlen(ipv6
) - 1) >= 0 && ipv6
[ipv6len
] == ']')
521 ipv6
[ipv6len
] = '\0';
527 if ((error
= getaddrinfo(hostname
, service
, &hints
, &results
)) == 0)
530 * Copy the results to our own address list structure...
533 for (current
= results
; current
; current
= current
->ai_next
)
534 if (current
->ai_family
== AF_INET
|| current
->ai_family
== AF_INET6
)
537 * Copy the address over...
540 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
543 httpAddrFreeList(first
);
544 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
548 if (current
->ai_family
== AF_INET6
)
549 memcpy(&(temp
->addr
.ipv6
), current
->ai_addr
,
550 sizeof(temp
->addr
.ipv6
));
552 memcpy(&(temp
->addr
.ipv4
), current
->ai_addr
,
553 sizeof(temp
->addr
.ipv4
));
556 * Append the address to the list...
569 * Free the results from getaddrinfo()...
572 freeaddrinfo(results
);
576 if (error
== EAI_FAIL
)
577 cg
->need_res_init
= 1;
579 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, gai_strerror(error
), 0);
585 int i
; /* Looping vars */
586 unsigned ip
[4]; /* IPv4 address components */
587 const char *ptr
; /* Pointer into hostname */
588 struct hostent
*host
; /* Result of lookup */
589 struct servent
*port
; /* Port number for service */
590 int portnum
; /* Port number */
594 * Lookup the service...
599 else if (isdigit(*service
& 255))
600 portnum
= atoi(service
);
601 else if ((port
= getservbyname(service
, NULL
)) != NULL
)
602 portnum
= ntohs(port
->s_port
);
603 else if (!strcmp(service
, "http"))
605 else if (!strcmp(service
, "https"))
607 else if (!strcmp(service
, "ipp") || !strcmp(service
, "ipps"))
609 else if (!strcmp(service
, "lpd"))
611 else if (!strcmp(service
, "socket"))
617 * This code is needed because some operating systems have a
618 * buggy implementation of gethostbyname() that does not support
619 * IPv4 addresses. If the hostname string is an IPv4 address, then
620 * sscanf() is used to extract the IPv4 components. We then pack
621 * the components into an IPv4 address manually, since the
622 * inet_aton() function is deprecated. We use the htonl() macro
623 * to get the right byte order for the address.
626 for (ptr
= hostname
; isdigit(*ptr
& 255) || *ptr
== '.'; ptr
++);
631 * We have an IPv4 address; break it up and create an IPv4 address...
634 if (sscanf(hostname
, "%u.%u.%u.%u", ip
, ip
+ 1, ip
+ 2, ip
+ 3) == 4 &&
635 ip
[0] <= 255 && ip
[1] <= 255 && ip
[2] <= 255 && ip
[3] <= 255)
637 first
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
641 first
->addr
.ipv4
.sin_family
= AF_INET
;
642 first
->addr
.ipv4
.sin_addr
.s_addr
= htonl(((((((ip
[0] << 8) |
644 ip
[2]) << 8) | ip
[3]));
645 first
->addr
.ipv4
.sin_port
= htons(portnum
);
648 else if ((host
= gethostbyname(hostname
)) != NULL
&&
650 (host
->h_addrtype
== AF_INET
|| host
->h_addrtype
== AF_INET6
))
652 host
->h_addrtype
== AF_INET
)
653 # endif /* AF_INET6 */
655 for (i
= 0; host
->h_addr_list
[i
]; i
++)
658 * Copy the address over...
661 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
664 httpAddrFreeList(first
);
669 if (host
->h_addrtype
== AF_INET6
)
671 temp
->addr
.ipv6
.sin6_family
= AF_INET6
;
672 memcpy(&(temp
->addr
.ipv6
.sin6_addr
), host
->h_addr_list
[i
],
673 sizeof(temp
->addr
.ipv6
));
674 temp
->addr
.ipv6
.sin6_port
= htons(portnum
);
677 # endif /* AF_INET6 */
679 temp
->addr
.ipv4
.sin_family
= AF_INET
;
680 memcpy(&(temp
->addr
.ipv4
.sin_addr
), host
->h_addr_list
[i
],
681 sizeof(temp
->addr
.ipv4
));
682 temp
->addr
.ipv4
.sin_port
= htons(portnum
);
686 * Append the address to the list...
700 if (h_errno
== NO_RECOVERY
)
701 cg
->need_res_init
= 1;
703 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, hstrerror(h_errno
), 0);
706 #endif /* HAVE_GETADDRINFO */
710 * Detect some common errors and handle them sanely...
713 if (!addr
&& (!hostname
|| !_cups_strcasecmp(hostname
, "localhost")))
715 struct servent
*port
; /* Port number for service */
716 int portnum
; /* Port number */
720 * Lookup the service...
725 else if (isdigit(*service
& 255))
726 portnum
= atoi(service
);
727 else if ((port
= getservbyname(service
, NULL
)) != NULL
)
728 portnum
= ntohs(port
->s_port
);
729 else if (!strcmp(service
, "http"))
731 else if (!strcmp(service
, "https"))
733 else if (!strcmp(service
, "ipp") || !strcmp(service
, "ipps"))
735 else if (!strcmp(service
, "lpd"))
737 else if (!strcmp(service
, "socket"))
741 httpAddrFreeList(first
);
743 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Unknown service name."), 1);
747 if (hostname
&& !_cups_strcasecmp(hostname
, "localhost"))
750 * Unfortunately, some users ignore all of the warnings in the
751 * /etc/hosts file and delete "localhost" from it. If we get here
752 * then we were unable to resolve the name, so use the IPv6 and/or
753 * IPv4 loopback interface addresses...
757 if (family
!= AF_INET
)
760 * Add [::1] to the address list...
763 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
766 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
767 httpAddrFreeList(first
);
771 temp
->addr
.ipv6
.sin6_family
= AF_INET6
;
772 temp
->addr
.ipv6
.sin6_port
= htons(portnum
);
774 temp
->addr
.ipv6
.sin6_addr
.u
.Byte
[15] = 1;
776 temp
->addr
.ipv6
.sin6_addr
.s6_addr32
[3] = htonl(1);
785 if (family
!= AF_INET6
)
786 #endif /* AF_INET6 */
789 * Add 127.0.0.1 to the address list...
792 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
795 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
796 httpAddrFreeList(first
);
800 temp
->addr
.ipv4
.sin_family
= AF_INET
;
801 temp
->addr
.ipv4
.sin_port
= htons(portnum
);
802 temp
->addr
.ipv4
.sin_addr
.s_addr
= htonl(0x7f000001);
814 * Provide one or more passive listening addresses...
818 if (family
!= AF_INET
)
821 * Add [::] to the address list...
824 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
827 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
828 httpAddrFreeList(first
);
832 temp
->addr
.ipv6
.sin6_family
= AF_INET6
;
833 temp
->addr
.ipv6
.sin6_port
= htons(portnum
);
841 if (family
!= AF_INET6
)
842 #endif /* AF_INET6 */
845 * Add 0.0.0.0 to the address list...
848 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
851 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
852 httpAddrFreeList(first
);
856 temp
->addr
.ipv4
.sin_family
= AF_INET
;
857 temp
->addr
.ipv4
.sin_port
= htons(portnum
);
869 * Return the address list...