]> err.no Git - varnish/commitdiff
Back in the mists of time, the SocketWizards were so happy to get
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Fri, 30 May 2008 21:39:56 +0000 (21:39 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Fri, 30 May 2008 21:39:56 +0000 (21:39 +0000)
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
varnish-cache/bin/varnishd/tcp.c

index 62dcecd92c5df3d12fc2280bfc195b4e1cb4c1b0..252b0727f97c26c79f4ac48b2df4f8d06c64e7f0 100644 (file)
@@ -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))
index f0c9a9660793824b901f4b6d2d0dd479429f7767..9cedd8c34c87c683145fcfa51f85df68c73fc30c 100644 (file)
@@ -39,6 +39,7 @@
 #include <errno.h>
 #include <sys/ioctl.h>
 #include <netdb.h>
+#include <poll.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -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);
+}