deal with connect() failing immediately
authorNiels Provos <provos@freebsd.localdomain>
Sun, 28 Feb 2010 02:59:06 +0000 (18:59 -0800)
committerNiels Provos <provos@freebsd.localdomain>
Sun, 28 Feb 2010 02:59:06 +0000 (18:59 -0800)
bufferevent-internal.h
bufferevent_sock.c
evutil.c
util-internal.h

index 81cadf1a65e4485ec31486c4b55b113cd4640991..eac318317b9c830e7c9b04fb6c9996f15e83b7fd 100644 (file)
@@ -137,6 +137,9 @@ struct bufferevent_private {
        unsigned writecb_pending : 1;
        /** Flag: set if we are currently busy connecting. */
        unsigned connecting : 1;
+       /** Flag: set if a connect failed prematurely; this is a hack for
+        * getting around the bufferevent abstraction. */
+       unsigned connection_refused : 1;
        /** Set to the events pending if we have deferred callbacks and
         * an events callback is pending. */
        short eventcb_pending;
index 2225a2a4b26a27ed5a4a784a48b1f7699d0b5960..22e76032f7c74b13f8373abc698e6f66ab067211 100644 (file)
@@ -213,6 +213,12 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
        }
        if (bufev_p->connecting) {
                int c = evutil_socket_finished_connecting(fd);
+               /* we need to fake the error if the connection was refused
+                * immediately - usually connection to localhost on BSD */
+               if (bufev_p->connection_refused) {
+                 bufev_p->connection_refused = 0;
+                 c = -1;
+               }
 
                if (c == 0)
                        goto done;
@@ -395,11 +401,19 @@ bufferevent_socket_connect(struct bufferevent *bev,
                        result = 0;
                        goto done;
                }
-       } else {
+       } if (r == 1) {
                /* The connect succeeded already. How very BSD of it. */
                result = 0;
                bufev_p->connecting = 1;
                event_active(&bev->ev_write, EV_WRITE, 1);
+       } else {
+               /* The connect failed already.  How very BSD of it. */
+               if (! be_socket_enable(bev, EV_WRITE)) {
+                       bufev_p->connection_refused = 1;
+                       bufev_p->connecting = 1;
+                       result = 0;
+                       goto done;
+               }
        }
 
        goto done;
index a4dc2ef6ad8219829c92cb301c97f37b291020c1..7df02149bc480af3761ee928a69472176f41d3ed 100644 (file)
--- a/evutil.c
+++ b/evutil.c
@@ -355,7 +355,7 @@ evutil_socket_geterror(evutil_socket_t sock)
 }
 #endif
 
-/* 1 for connected, 0 for not yet, -1 for error. */
+/* 2 for connection refused, 1 for connected, 0 for not yet, -1 for error. */
 int
 evutil_socket_connect(evutil_socket_t *fd_ptr, struct sockaddr *sa, int socklen)
 {
@@ -374,6 +374,8 @@ evutil_socket_connect(evutil_socket_t *fd_ptr, struct sockaddr *sa, int socklen)
                int e = evutil_socket_geterror(*fd_ptr);
                if (EVUTIL_ERR_CONNECT_RETRIABLE(e))
                        return 0;
+               if (EVUTIL_ERR_CONNECT_REFUSED(e))
+                       return 2;
                goto err;
        } else {
                return 1;
index 726b6939f9670e1a319258165070bf2d47e0d020..6fa4bd632e83e5cf94d568a12dc51463cfc2a271 100644 (file)
@@ -66,13 +66,17 @@ extern "C" {
 /* True iff e is an error that means a read/write operation can be retried. */
 #define EVUTIL_ERR_RW_RETRIABLE(e)                             \
        ((e) == EINTR || (e) == EAGAIN)
-/* True iff e is an error that means an accept can be retried. */
+/* True iff e is an error that means an connect can be retried. */
 #define EVUTIL_ERR_CONNECT_RETRIABLE(e)                        \
        ((e) == EINTR || (e) == EINPROGRESS)
-/* True iff e is an error that means a connect can be retried. */
+/* True iff e is an error that means a accept can be retried. */
 #define EVUTIL_ERR_ACCEPT_RETRIABLE(e)                 \
        ((e) == EINTR || (e) == EAGAIN || (e) == ECONNABORTED)
 
+/* True iff e is an error that means the connection was refused */
+#define EVUTIL_ERR_CONNECT_REFUSED(e)                                  \
+       ((e) == ECONNREFUSED)
+
 #else
 
 #define EVUTIL_ERR_RW_RETRIABLE(e)                                     \
@@ -88,6 +92,9 @@ extern "C" {
 #define EVUTIL_ERR_ACCEPT_RETRIABLE(e)                 \
        EVUTIL_ERR_RW_RETRIABLE(e)
 
+#define EVUTIL_ERR_CONNECT_REFUSED(e)                                  \
+       ((e) == WSAECONNREFUSED)
+
 #endif
 
 #ifdef _EVENT_socklen_t