Skip to content

Commit

Permalink
Win32: check exceptfds in select when connecting
Browse files Browse the repository at this point in the history
When doing a nonblocking connect() on win32, select() reports failure using
exceptfds instead of writefds. Allow this narrow case when doing a non-blocking
connect on Win32.

See:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms740141(v=vs.85).aspx

Fixes #297
  • Loading branch information
alanxz committed Oct 14, 2015
1 parent 54b66ae commit 8387add
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 9 deletions.
31 changes: 23 additions & 8 deletions librabbitmq/amqp_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,27 +303,40 @@ int amqp_poll(int fd, int event, amqp_time_t deadline) {
return AMQP_STATUS_OK;
#elif defined(HAVE_SELECT)
fd_set fds;
fd_set exceptfds;
fd_set *exceptfdsp;
int res;
struct timeval tv;
struct timeval *tvp;

assert(event == AMQP_SF_POLLIN || event == AMQP_SF_POLLOUT);
assert((0 != event & AMQP_SF_POLLIN) || (0 != event & AMQP_SF_POLLOUT));
#ifndef _WIN32
/* On Win32 connect() failure is indicated through the exceptfds, it does not
* make any sense to allow POLLERR on any other platform or condition */
assert(0 == event & AMQP_SF_POLLERR);
#endif

start_select:
FD_ZERO(&fds);
FD_SET(fd, &fds);

if (event & AMQP_SF_POLLERR) {
FD_ZERO(&exceptfds);
FD_SET(fd, &exceptfds);
exceptfdsp = &exceptfds;
} else {
exceptfds = NULL;
}

res = amqp_time_tv_until(deadline, &tv, &tvp);
if (res != AMQP_STATUS_OK) {
return res;
}

switch (event) {
case AMQP_SF_POLLIN:
res = select(fd + 1, &fds, NULL, NULL, tvp);
break;
case AMQP_SF_POLLOUT:
res = select(fd + 1, NULL, &fds, NULL, tvp);
if (event & AMQP_SF_POLLIN) {
res = select(fd + 1, &fds, NULL, exceptfdsp, tvp);
} else if (event & AMQP_SF_POLLOUT) {
res = select(fd + 1, NULL, &fds, exceptfdsp, tvp);
}

if (0 < res) {
Expand Down Expand Up @@ -481,10 +494,12 @@ int amqp_open_socket_inner(char const *hostname,

#ifdef _WIN32
if (WSAEWOULDBLOCK == amqp_os_socket_error()) {
int event = AMQP_SF_POLLOUT | AMQP_SF_POLLERR;
#else
if (EINPROGRESS == amqp_os_socket_error()) {
int event = AMQP_SF_POLLOUT;
#endif
last_error = amqp_poll(sockfd, AMQP_SF_POLLOUT, deadline);
last_error = amqp_poll(sockfd, event, deadline);
if (AMQP_STATUS_OK == last_error) {
int result;
socklen_t result_len = sizeof(result);
Expand Down
3 changes: 2 additions & 1 deletion librabbitmq/amqp_socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ typedef enum {
AMQP_SF_NONE = 0,
AMQP_SF_MORE = 1,
AMQP_SF_POLLIN = 2,
AMQP_SF_POLLOUT = 4
AMQP_SF_POLLOUT = 4,
AMQP_SF_POLLERR = 8
} amqp_socket_flag_enum;

int
Expand Down

0 comments on commit 8387add

Please sign in to comment.