summaryrefslogtreecommitdiff
path: root/cups/http-addrlist.c
diff options
context:
space:
mode:
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>2015-12-11 18:59:09 +0000
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>2015-12-11 18:59:09 +0000
commitd5cc05c96dc36275e5abdcaa2f6d1280d36d2b4c (patch)
tree44e4879a47164757505f56f352451e57422b71b7 /cups/http-addrlist.c
parent8935a80bd037f1b8027576d2cdd9f8397f62c224 (diff)
downloadcups-d5cc05c96dc36275e5abdcaa2f6d1280d36d2b4c.tar.gz
The httpAddrConnect and httpConnect* APIs now try connecting to multiple
addresses in parallel (<rdar://problem/20643153>) git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@13014 a1ca3aef-8c08-0410-bb20-df032aa958be
Diffstat (limited to 'cups/http-addrlist.c')
-rw-r--r--cups/http-addrlist.c224
1 files changed, 124 insertions, 100 deletions
diff --git a/cups/http-addrlist.c b/cups/http-addrlist.c
index 0b3f083a9..8a17f6fa6 100644
--- a/cups/http-addrlist.c
+++ b/cups/http-addrlist.c
@@ -68,14 +68,19 @@ httpAddrConnect2(
http_addr_t peer; /* Peer address */
int flags, /* Socket flags */
remaining; /* Remaining timeout */
+ int i, /* Looping var */
+ nfds, /* Number of file descriptors */
+ fds[100], /* Socket file descriptors */
+ result; /* Result from select() or poll() */
+ http_addrlist_t *addrs[100]; /* Addresses */
# ifdef HAVE_POLL
- struct pollfd pfd; /* Polled file descriptor */
+ struct pollfd pfds[100]; /* Polled file descriptors */
# else
+ int max_fd = -1; /* Highest file descriptor */
fd_set input_set, /* select() input set */
output_set; /* select() output set */
struct timeval timeout; /* Timeout */
# endif /* HAVE_POLL */
- int nfds; /* Result from select()/poll() */
#endif /* O_NONBLOCK */
#ifdef DEBUG
char temp[256]; /* Temporary address string */
@@ -95,35 +100,39 @@ httpAddrConnect2(
if (cancel && *cancel)
return (NULL);
- if (msec <= 0 || getenv("CUPS_DISABLE_ASYNC_CONNECT"))
+ if (msec <= 0)
msec = INT_MAX;
/*
* Loop through each address until we connect or run out of addresses...
*/
- while (addrlist)
+ for (nfds = 0; addrlist && nfds < (int)(sizeof(fds) / sizeof(fds[0])); addrlist = addrlist->next)
{
if (cancel && *cancel)
+ {
+ while (nfds > 0)
+ {
+ nfds --;
+ httpAddrClose(NULL, fds[nfds]);
+ }
+
return (NULL);
+ }
/*
* Create the socket...
*/
- DEBUG_printf(("2httpAddrConnect2: Trying %s:%d...",
- httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
- httpAddrPort(&(addrlist->addr))));
+ DEBUG_printf(("2httpAddrConnect2: Trying %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr))));
- if ((*sock = (int)socket(httpAddrFamily(&(addrlist->addr)), SOCK_STREAM,
- 0)) < 0)
+ if ((fds[nfds] = (int)socket(httpAddrFamily(&(addrlist->addr)), SOCK_STREAM, 0)) < 0)
{
/*
* Don't abort yet, as this could just be an issue with the local
* system not being configured with IPv4/IPv6/domain socket enabled...
*/
- addrlist = addrlist->next;
continue;
}
@@ -132,16 +141,16 @@ httpAddrConnect2(
*/
val = 1;
- setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val));
+ setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val));
#ifdef SO_REUSEPORT
val = 1;
- setsockopt(*sock, SOL_SOCKET, SO_REUSEPORT, CUPS_SOCAST &val, sizeof(val));
+ setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEPORT, CUPS_SOCAST &val, sizeof(val));
#endif /* SO_REUSEPORT */
#ifdef SO_NOSIGPIPE
val = 1;
- setsockopt(*sock, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
+ setsockopt(fds[nfds], SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
#endif /* SO_NOSIGPIPE */
/*
@@ -150,14 +159,14 @@ httpAddrConnect2(
*/
val = 1;
- setsockopt(*sock, IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val));
+ setsockopt(fds[nfds], IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val));
#ifdef FD_CLOEXEC
/*
* Close this socket when starting another process...
*/
- fcntl(*sock, F_SETFD, FD_CLOEXEC);
+ fcntl(fds[nfds], F_SETFD, FD_CLOEXEC);
#endif /* FD_CLOEXEC */
#ifdef O_NONBLOCK
@@ -167,142 +176,157 @@ httpAddrConnect2(
DEBUG_printf(("httpAddrConnect2: Setting non-blocking connect()"));
- flags = fcntl(*sock, F_GETFL, 0);
- if (msec != INT_MAX)
- {
- DEBUG_puts("httpAddrConnect2: Setting non-blocking connect()");
-
- fcntl(*sock, F_SETFL, flags | O_NONBLOCK);
- }
+ flags = fcntl(fds[nfds], F_GETFL, 0);
+ fcntl(fds[nfds], F_SETFL, flags | O_NONBLOCK);
#endif /* O_NONBLOCK */
/*
* Then connect...
*/
- if (!connect(*sock, &(addrlist->addr.addr), (socklen_t)httpAddrLength(&(addrlist->addr))))
+ if (!connect(fds[nfds], &(addrlist->addr.addr), (socklen_t)httpAddrLength(&(addrlist->addr))))
{
- DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...",
- httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
- httpAddrPort(&(addrlist->addr))));
+ DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr))));
#ifdef O_NONBLOCK
- fcntl(*sock, F_SETFL, flags);
+ fcntl(fds[nfds], F_SETFL, flags);
#endif /* O_NONBLOCK */
+ *sock = fds[nfds];
+
+ while (nfds > 0)
+ {
+ nfds --;
+ httpAddrClose(NULL, fds[nfds]);
+ }
+
return (addrlist);
}
-#ifdef O_NONBLOCK
-# ifdef WIN32
- if (WSAGetLastError() == WSAEINPROGRESS ||
- WSAGetLastError() == WSAEWOULDBLOCK)
-# else
- if (errno == EINPROGRESS || errno == EWOULDBLOCK)
-# endif /* WIN32 */
+#ifdef WIN32
+ if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK)
+#else
+ if (errno != EINPROGRESS && errno != EWOULDBLOCK)
+#endif /* WIN32 */
{
- DEBUG_puts("1httpAddrConnect2: Finishing async connect()");
+ DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)), strerror(errno)));
+ httpAddrClose(NULL, fds[nfds]);
+ continue;
+ }
+
+ fcntl(fds[nfds], F_SETFL, flags);
+
+#ifndef HAVE_POLL
+ if (fds[nfds] > max_fd)
+ max_fd = fds[nfds];
+#endif /* !HAVE_POLL */
- fcntl(*sock, F_SETFL, flags);
+ addrs[nfds] = addrlist;
+ nfds ++;
+ }
+
+#ifdef O_NONBLOCK
+ DEBUG_puts("1httpAddrConnect2: Finishing async connect()");
- for (remaining = msec; remaining > 0; remaining -= 250)
+ for (remaining = msec; remaining > 0; remaining -= 250)
+ {
+ do
+ {
+ if (cancel && *cancel)
{
- do
- {
- if (cancel && *cancel)
- {
- /*
- * Close this socket and return...
- */
+ /*
+ * Close this socket and return...
+ */
- DEBUG_puts("1httpAddrConnect2: Canceled connect()");
+ DEBUG_puts("1httpAddrConnect2: Canceled connect()");
- httpAddrClose(NULL, *sock);
+ while (nfds > 0)
+ {
+ nfds --;
+ httpAddrClose(NULL, fds[nfds]);
+ }
- *sock = -1;
+ *sock = -1;
- return (NULL);
- }
+ return (NULL);
+ }
# ifdef HAVE_POLL
- pfd.fd = *sock;
- pfd.events = POLLIN | POLLOUT;
+ for (i = 0; i < nfds; i ++)
+ {
+ pfds[i].fd = fds[i];
+ pfds[i].events = POLLIN | POLLOUT;
+ }
- nfds = poll(&pfd, 1, remaining > 250 ? 250 : remaining);
+ result = poll(pfds, (nfds_t)nfds, remaining > 250 ? 250 : remaining);
- DEBUG_printf(("1httpAddrConnect2: poll() returned %d (%d)", nfds,
- errno));
+ DEBUG_printf(("1httpAddrConnect2: poll() returned %d (%d)", result, errno));
# else
- FD_ZERO(&input_set);
- FD_SET(*sock, &input_set);
- output_set = input_set;
+ FD_ZERO(&input_set);
+ for (i = 0; i < nfds; i ++)
+ FD_SET(fds[i], &input_set);
+ output_set = input_set;
- timeout.tv_sec = 0;
- timeout.tv_usec = (remaining > 250 ? 250 : remaining) * 1000;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = (remaining > 250 ? 250 : remaining) * 1000;
- nfds = select(*sock + 1, &input_set, &output_set, NULL, &timeout);
+ result = select(max_fd + 1, &input_set, &output_set, NULL, &timeout);
- DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", nfds,
- errno));
+ DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", result, errno));
# endif /* HAVE_POLL */
- }
+ }
# ifdef WIN32
- while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
- WSAGetLastError() == WSAEWOULDBLOCK));
+ while (result < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK));
# else
- while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
+ while (result < 0 && (errno == EINTR || errno == EAGAIN));
# endif /* WIN32 */
- if (nfds > 0)
+ if (result > 0)
+ {
+ for (i = 0; i < nfds; i ++)
+ {
+# ifdef HAVE_POLL
+ DEBUG_printf(("pfds[%d].revents=%x\n", i, pfds[i].revents));
+ if (pfds[i].revents)
+# else
+ if (FD_ISSET(fds[i], &input))
+# endif /* HAVE_POLL */
{
- len = sizeof(peer);
- if (!getpeername(*sock, (struct sockaddr *)&peer, &len))
- {
- DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...",
- httpAddrString(&peer, temp, sizeof(temp)),
- httpAddrPort(&peer)));
-
- return (addrlist);
- }
+ *sock = fds[i];
+ len = sizeof(peer);
+ if (!getpeername(fds[i], (struct sockaddr *)&peer, &len))
+ {
+ DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&peer, temp, sizeof(temp)), httpAddrPort(&peer)));
- break;
- }
+ addrlist = addrs[i];
+ }
+ }
+ else
+ httpAddrClose(NULL, fds[i]);
}
+
+ return (addrlist);
}
+ }
#endif /* O_NONBLOCK */
- DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s",
- httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
- httpAddrPort(&(addrlist->addr)), strerror(errno)));
-
-#ifndef WIN32
- if (errno == EINPROGRESS)
- errno = ETIMEDOUT;
-#endif /* !WIN32 */
-
- /*
- * Close this socket and move to the next address...
- */
-
- httpAddrClose(NULL, *sock);
-
- *sock = -1;
- addrlist = addrlist->next;
+ while (nfds > 0)
+ {
+ nfds --;
+ httpAddrClose(NULL, fds[nfds]);
}
- if (!addrlist)
#ifdef WIN32
- _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0);
+ _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0);
#else
- _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0);
+ _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0);
#endif /* WIN32 */
- return (addrlist);
+ return (NULL);
}
-
/*
* 'httpAddrCopyList()' - Copy an address list.
*