deal with connect() failing immediately

This commit is contained in:
Niels Provos 2010-02-27 18:59:06 -08:00
parent 98edb891f8
commit 7bc48bfd3a
4 changed files with 30 additions and 4 deletions

View File

@ -137,6 +137,9 @@ struct bufferevent_private {
unsigned writecb_pending : 1; unsigned writecb_pending : 1;
/** Flag: set if we are currently busy connecting. */ /** Flag: set if we are currently busy connecting. */
unsigned connecting : 1; 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 /** Set to the events pending if we have deferred callbacks and
* an events callback is pending. */ * an events callback is pending. */
short eventcb_pending; short eventcb_pending;

View File

@ -213,6 +213,12 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
} }
if (bufev_p->connecting) { if (bufev_p->connecting) {
int c = evutil_socket_finished_connecting(fd); 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) if (c == 0)
goto done; goto done;
@ -395,11 +401,19 @@ bufferevent_socket_connect(struct bufferevent *bev,
result = 0; result = 0;
goto done; goto done;
} }
} else { } if (r == 1) {
/* The connect succeeded already. How very BSD of it. */ /* The connect succeeded already. How very BSD of it. */
result = 0; result = 0;
bufev_p->connecting = 1; bufev_p->connecting = 1;
event_active(&bev->ev_write, EV_WRITE, 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; goto done;

View File

@ -355,7 +355,7 @@ evutil_socket_geterror(evutil_socket_t sock)
} }
#endif #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 int
evutil_socket_connect(evutil_socket_t *fd_ptr, struct sockaddr *sa, int socklen) 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); int e = evutil_socket_geterror(*fd_ptr);
if (EVUTIL_ERR_CONNECT_RETRIABLE(e)) if (EVUTIL_ERR_CONNECT_RETRIABLE(e))
return 0; return 0;
if (EVUTIL_ERR_CONNECT_REFUSED(e))
return 2;
goto err; goto err;
} else { } else {
return 1; return 1;

View File

@ -66,13 +66,17 @@ extern "C" {
/* True iff e is an error that means a read/write operation can be retried. */ /* True iff e is an error that means a read/write operation can be retried. */
#define EVUTIL_ERR_RW_RETRIABLE(e) \ #define EVUTIL_ERR_RW_RETRIABLE(e) \
((e) == EINTR || (e) == EAGAIN) ((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) \ #define EVUTIL_ERR_CONNECT_RETRIABLE(e) \
((e) == EINTR || (e) == EINPROGRESS) ((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) \ #define EVUTIL_ERR_ACCEPT_RETRIABLE(e) \
((e) == EINTR || (e) == EAGAIN || (e) == ECONNABORTED) ((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 #else
#define EVUTIL_ERR_RW_RETRIABLE(e) \ #define EVUTIL_ERR_RW_RETRIABLE(e) \
@ -88,6 +92,9 @@ extern "C" {
#define EVUTIL_ERR_ACCEPT_RETRIABLE(e) \ #define EVUTIL_ERR_ACCEPT_RETRIABLE(e) \
EVUTIL_ERR_RW_RETRIABLE(e) EVUTIL_ERR_RW_RETRIABLE(e)
#define EVUTIL_ERR_CONNECT_REFUSED(e) \
((e) == WSAECONNREFUSED)
#endif #endif
#ifdef _EVENT_socklen_t #ifdef _EVENT_socklen_t