diff options
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | bufferevent_sock.c | 18 | ||||
-rw-r--r-- | evutil.c | 23 | ||||
-rw-r--r-- | util-internal.h | 2 |
4 files changed, 42 insertions, 4 deletions
@@ -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: diff --git a/bufferevent_sock.c b/bufferevent_sock.c index f78fc094..b2d0175a 100644 --- a/bufferevent_sock.c +++ b/bufferevent_sock.c @@ -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; + } } } @@ -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[] = { diff --git a/util-internal.h b/util-internal.h index 3a842094..f5580ecc 100644 --- a/util-internal.h +++ b/util-internal.h @@ -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 |