diff options
author | msweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be> | 2015-12-11 18:59:09 +0000 |
---|---|---|
committer | msweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be> | 2015-12-11 18:59:09 +0000 |
commit | d5cc05c96dc36275e5abdcaa2f6d1280d36d2b4c (patch) | |
tree | 44e4879a47164757505f56f352451e57422b71b7 /cups/http-addrlist.c | |
parent | 8935a80bd037f1b8027576d2cdd9f8397f62c224 (diff) | |
download | cups-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.c | 224 |
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. * |