From d0db89398846db754400d1e96c02f091b06e8153 Mon Sep 17 00:00:00 2001 From: phk Date: Fri, 30 May 2008 21:39:56 +0000 Subject: [PATCH] Back in the mists of time, the SocketWizards were so happy to get any connections at all, that they didn't even consider that maybe connect(2) should have a timeout argument. Add TCP_connect() which addresses this shortcoming, using what I belive is a widely supported workaround. Not to POSIX: please fix. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@2641 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- varnish-cache/bin/varnishd/common.h | 3 ++ varnish-cache/bin/varnishd/tcp.c | 53 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/varnish-cache/bin/varnishd/common.h b/varnish-cache/bin/varnishd/common.h index 62dcecd9..252b0727 100644 --- a/varnish-cache/bin/varnishd/common.h +++ b/varnish-cache/bin/varnishd/common.h @@ -46,5 +46,8 @@ void TCP_myname(int sock, char *abuf, unsigned alen, char *pbuf, unsigned plen); int TCP_filter_http(int sock); void TCP_blocking(int sock); void TCP_nonblocking(int sock); +#ifdef SOL_SOCKET +int TCP_connect(int s, const struct sockaddr *name, socklen_t namelen, int msec); +#endif #define TRUST_ME(ptr) ((void*)(uintptr_t)(ptr)) diff --git a/varnish-cache/bin/varnishd/tcp.c b/varnish-cache/bin/varnishd/tcp.c index f0c9a966..9cedd8c3 100644 --- a/varnish-cache/bin/varnishd/tcp.c +++ b/varnish-cache/bin/varnishd/tcp.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -138,3 +139,55 @@ TCP_nonblocking(int sock) i = 1; AZ(ioctl(sock, FIONBIO, &i)); } + +/*-------------------------------------------------------------------- + * On TCP a connect(2) can block for a looong time, and we don't want that. + * Unfortunately, the SocketWizards back in those days were happy to wait + * any amount of time for a connection, so the connect(2) syscall does not + * take an argument for patience. + * + * There is a little used work-around, and we employ it at our peril. + * + */ + +int +TCP_connect(int s, const struct sockaddr *name, socklen_t namelen, int msec) +{ + int i, k; + socklen_t l; + struct pollfd fds[1]; + + assert(s >= 0); + + /* Set the socket non-blocking */ + TCP_nonblocking(s); + + /* Attempt the connect */ + i = connect(s, name, namelen); + if (i == 0 || errno != EINPROGRESS) + return (i); + + /* Exercise our patience, polling for write */ + fds[0].fd = s; + fds[0].events = POLLWRNORM; + fds[0].revents = 0; + i = poll(fds, 1, msec); + + if (i == 0) { + /* Timeout, close and give up */ + errno = ETIMEDOUT; + return (-1); + } + + /* Find out if we got a connection */ + l = sizeof k; + AZ(getsockopt(s, SOL_SOCKET, SO_ERROR, &k, &l)); + + /* An error means no connection established */ + errno = k; + if (k) + return (-1); + + TCP_blocking(s); + return (0); +} -- 2.39.5