httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jeff Trawick <trawi...@bellsouth.net>
Subject Re: [PATCH] win32/sockets.c - remove select in connect routine
Date Wed, 20 Sep 2000 16:12:00 GMT
Gregory Nicholls <gnicholls@level8.com> writes:

>  This patch removes the select from the win32/sockets.c connect routine. It will now
permit a
> non-blocking connect.

I started playing with your patch and ended up with the patch below.

In my patch:

. I modified your Win32 apr_connect() and the existing Unix
apr_connect() to set some stuff before returning from apr_connect()
after a non-blocking connect(); these may not be required as long as
we force the app to call apr_connect() again after finding out that
connect() is finished

. I modified the client test program to wait for the connect to
complete, and then call apr_connect() again to find out what happened

. I modified (kludged) unix/canonerr.c to map WSAEWOULDBLOCK to
APR_EAGAIN; connect() on Win32 returns WSAEWOULDBLOCK in the
non-blocking case

With my patch, the client test program is broken when it does a
non-blocking apr_connect() on Win32.  I try to use apr_poll() to find
out when the connect is done, but apr_poll() doesn't return when
the connect succeeds/fails.  Maybe I need to pass a different flag?
Maybe it just won't work this way on Win32?  This needs more
research.

In your testing, what did you do to find out when the connect() is
done?  That is the missing piece.

Index: misc/unix/canonerr.c
===================================================================
RCS file: /cvs/apache/apache-2.0/src/lib/apr/misc/unix/canonerr.c,v
retrieving revision 1.5
diff -u -r1.5 canonerr.c
--- canonerr.c	2000/08/02 05:26:22	1.5
+++ canonerr.c	2000/09/20 16:01:45
@@ -63,6 +63,11 @@
         errcode = EAGAIN;
     }
 #endif
+#if defined(WIN32)
+    if (errcode == WSAEWOULDBLOCK) {
+        errcode = APR_EAGAIN;
+    }
+#endif
     return errcode;
 }
 
Index: network_io/unix/sockets.c
===================================================================
RCS file: /cvs/apache/apache-2.0/src/lib/apr/network_io/unix/sockets.c,v
retrieving revision 1.53
diff -u -r1.53 sockets.c
--- sockets.c	2000/08/06 06:07:22	1.53
+++ sockets.c	2000/09/20 16:01:45
@@ -209,24 +209,25 @@
 #endif
     }
 
-    if ((connect(sock->socketdes, (const struct sockaddr *)sock->remote_addr,
-        sock->addr_len) < 0) && (errno != EINPROGRESS)) {
-        return errno;
+    /* Fill out some info in apr_socket_t as if connect() will work. */
+    if (sock->local_addr->sin_port == 0) {
+        /* connect() got us an ephemeral port */
+        sock->local_port_unknown = 1;
     }
-    else {
-        if (sock->local_addr->sin_port == 0) {
-            /* connect() got us an ephemeral port */
-            sock->local_port_unknown = 1;
-        }
-        if (sock->local_addr->sin_addr.s_addr == 0) {
-            /* not bound to specific local interface; connect() had to assign
-             * one for the socket
-             */
-            sock->local_interface_unknown = 1;
-        }
+    if (sock->local_addr->sin_addr.s_addr == 0) {
+        /* not bound to specific local interface; connect() had to assign
+         * one for the socket
+         */
+        sock->local_interface_unknown = 1;
+    }
 #ifndef HAVE_POLL
-	sock->connected=1;
+    sock->connected = 1;
 #endif
+    if (connect(sock->socketdes, (const struct sockaddr *)sock->remote_addr,
+        sock->addr_len) < 0) {
+        return errno;
+    }
+    else {
         return APR_SUCCESS;
     }
 }
Index: network_io/win32/sockets.c
===================================================================
RCS file: /cvs/apache/apache-2.0/src/lib/apr/network_io/win32/sockets.c,v
retrieving revision 1.37
diff -u -r1.37 sockets.c
--- sockets.c	2000/08/06 06:07:24	1.37
+++ sockets.c	2000/09/20 16:01:45
@@ -215,8 +215,6 @@
 apr_status_t apr_connect(apr_socket_t *sock, char *hostname)
 {
     struct hostent *hp;
-    int lasterror;
-    fd_set temp;
 
     if ((sock->sock == INVALID_SOCKET) || (!sock->local_addr)) {
         return APR_ENOTSOCK;
@@ -239,26 +237,17 @@
     
     sock->remote_addr->sin_family = AF_INET;
 
-    if (connect(sock->sock, (const struct sockaddr *)sock->remote_addr, 
-                sock->addr_len) == SOCKET_ERROR) {
-        lasterror = WSAGetLastError();
-        if (lasterror != WSAEWOULDBLOCK) {
-            return lasterror;
-        }
-        /* wait for the connect to complete */
-        FD_ZERO(&temp);
-        FD_SET(sock->sock, &temp);
-        if (select(sock->sock+1, NULL, &temp, NULL, NULL) == SOCKET_ERROR) {
-            return WSAGetLastError();
-        }
-    }
-    /* connect was OK .. amazing */
+    /* Fill out some info in apr_socket_t as if connect() will work. */
     if (sock->local_addr->sin_port == 0) {
         sock->local_port_unknown = 1;
     }
     if (sock->local_addr->sin_addr.s_addr == 0) {
         /* must be using free-range port */
         sock->local_interface_unknown = 1;
+    }
+    if (connect(sock->sock, (const struct sockaddr *)sock->remote_addr, 
+                sock->addr_len) == SOCKET_ERROR) {
+        return WSAGetLastError();
     }
     return APR_SUCCESS;
 }
Index: test/client.c
===================================================================
RCS file: /cvs/apache/apache-2.0/src/lib/apr/test/client.c,v
retrieving revision 1.14
diff -u -r1.14 client.c
--- client.c	2000/08/06 06:07:28	1.14
+++ client.c	2000/09/20 16:01:46
@@ -52,6 +52,7 @@
  * <http://www.apache.org/>.
  */
 
+#include <assert.h>
 #include <stdlib.h>
 #include "apr_network_io.h"
 #include "apr_errno.h"
@@ -127,7 +128,9 @@
 
     stat = apr_connect(sock, dest);
 
-    if (stat != APR_SUCCESS) {
+    if (stat != APR_SUCCESS && 
+        !(apr_canonical_error(stat) == APR_EINPROGRESS ||
+            apr_canonical_error(stat) == APR_EAGAIN)) {
         apr_close_socket(sock);
         fprintf(stderr, "Could not connect: %s (%d)\n", 
 		apr_strerror(stat, msgbuf, sizeof(msgbuf)), stat);
@@ -135,6 +138,35 @@
         exit(-1);
     }
     fprintf(stdout, "OK\n");
+
+    if (stat != APR_SUCCESS) {
+        apr_pollfd_t *pfd;
+        apr_int32_t nsocks;
+
+        assert(read_timeout == -1);
+        fprintf(stdout, "\tClient:  Waiting for connect to complete (or fail).....");
+        pfd = NULL;
+        stat = apr_setup_poll(&pfd, 1, context);
+        assert(!stat);
+        stat = apr_add_poll_socket(pfd, sock, APR_POLLOUT);
+        assert(!stat);
+        nsocks = 1;
+        stat = apr_poll(pfd, &nsocks, -1);
+        assert(!stat);
+        assert(nsocks == 1);
+        fprintf(stdout, "OK\n");
+        fprintf(stdout, "\tClient:  Checking result of connect....");
+        stat = apr_connect(sock, dest);
+        if (stat != APR_SUCCESS) {
+            apr_close_socket(sock);
+            fprintf(stdout, "Failed: %s (%d)\n", 
+                    apr_strerror(stat, msgbuf, sizeof(msgbuf)), stat);
+            exit(-1);
+        }
+        else {
+            fprintf(stdout, "OK\n");
+        }
+    }
 
     apr_get_remote_ipaddr(&remote_ipaddr, sock);
     apr_get_remote_port(&remote_port, sock);

-- 
Jeff Trawick | trawick@ibm.net | PGP public key at web site:
     http://www.geocities.com/SiliconValley/Park/9289/
          Born in Roswell... married an alien...

Mime
View raw message