]> granicus.if.org Git - libevent/commitdiff
When a bufferevent_connect() call fails, give the client an error callback.
authorNick Mathewson <nickm@torproject.org>
Wed, 14 Oct 2009 00:46:47 +0000 (00:46 +0000)
committerNick Mathewson <nickm@torproject.org>
Wed, 14 Oct 2009 00:46:47 +0000 (00:46 +0000)
Patch from Christopher Davis.

svn:r1444

ChangeLog
bufferevent_sock.c
evutil.c
util-internal.h

index 68929ee62975af594f181cc4ed260804fc1abd9e..b638bf5737c71ff03d3483754ebf11ad0e90f16e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,7 +6,7 @@ Changes in 2.0.3-alpha:
  o Try to compile better with MSVC: patches from Brodie Thiesfield
  o New evconnlistener_get_fd function to expose a listener's associated socket.
  o Expose an ev_socklen_t type for consistent use across platforms.
- o Make bufferevenr_socket_connect() work when the original fd was -1.
+ o Make bufferevent_socket_connect() work when the original fd was -1.
  o Fix a bug in bufferevent_socket_connect() when the connection succeeds too quickly.
  o Export an evutil_sockaddr_cmp() to compare to sockaddr objects for equality.
  o Add a bufferevent_get_enabled() to tell what a bufferevent has been configured to do.
@@ -26,6 +26,7 @@ Changes in 2.0.3-alpha:
  o New event_base_got_exit() and event_base_got_break() functions to tell whether an event loop exited because of an event_base_loopexit() or an event_base_loopbreak().  Patch from Ka-Hing Cheung.
  o When adding or deleting an event from a non-main thread, only wake up the main thread when its behavior actually needs to change.
  o Fix some bugs when using the old evdns interfaces to initialize the evdns module.
+ o Detect errors during bufferevent_connect().  Patch from Christopher Davis.
 
 
 Changes in 2.0.2-alpha:
index f78fc094ec0456fc5f8902d63e0e28f5fe23f9f6..b2d0175a19f058fd1215a36a48410414ae620576 100644 (file)
@@ -192,12 +192,24 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
                goto error;
        }
        if (bufev_p->connecting) {
+               int c = evutil_socket_finished_connecting(fd);
+
+               if (c == 0)
+                       goto done;
+
                bufev_p->connecting = 0;
-               connected = 1;
-               _bufferevent_run_eventcb(bufev, BEV_EVENT_CONNECTED);
-               if (!(bufev->enabled & EV_WRITE)) {
+               if (c < 0) {
                        event_del(&bufev->ev_write);
+                       event_del(&bufev->ev_read);
+                       _bufferevent_run_eventcb(bufev, BEV_EVENT_ERROR);
                        goto done;
+               } else {
+                       connected = 1;
+                       _bufferevent_run_eventcb(bufev, BEV_EVENT_CONNECTED);
+                       if (!(bufev->enabled & EV_WRITE)) {
+                               event_del(&bufev->ev_write);
+                               goto done;
+                       }
                }
        }
 
index 9273e966179d216052f9f5a01f7313b32d8e0354..b41e7819060d7d1649123dfa88dfab87c4e1f97c 100644 (file)
--- a/evutil.c
+++ b/evutil.c
@@ -297,6 +297,29 @@ err:
        return -1;
 }
 
+/* Check whether a socket on which we called connect() is done
+   connecting. Return 1 for connected, 0 for not yet, -1 for error.  In the
+   error case, set the current socket errno to the error that happened during
+   the connect operation. */
+int
+evutil_socket_finished_connecting(evutil_socket_t fd)
+{
+       int e;
+       ev_socklen_t elen = sizeof(e);
+
+       if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&e, &elen) < 0)
+               return -1;
+
+       if (e) {
+               if (EVUTIL_ERR_CONNECT_RETRIABLE(e))
+                       return 0;
+               EVUTIL_SET_SOCKET_ERROR(e);
+               return -1;
+       }
+
+       return 1;
+}
+
 #ifdef WIN32
 #define E(code, s) { code, (s " [" #code " ]") }
 static struct { int code; const char *msg; } windows_socket_errors[] = {
index 3a84209469b9ed3f6a8fd5a2e1aeb8553972cb8e..f5580eccfe8597df2c3442b4cc9d79eaf246c796 100644 (file)
@@ -130,6 +130,8 @@ extern const char EVUTIL_TOLOWER_TABLE[];
 
 int evutil_socket_connect(evutil_socket_t *fd_ptr, struct sockaddr *sa, int socklen);
 
+int evutil_socket_finished_connecting(evutil_socket_t fd);
+
 #ifdef __cplusplus
 }
 #endif