Final edit

pull/3432/head
Mihir Patel 1 month ago
parent 6b231754f2
commit e8984f6fdf

@ -58,58 +58,81 @@ public:
SOCKET fd() const { return socket_; } SOCKET fd() const { return socket_; }
#include <winsock2.h>
#include <ws2tcpip.h>
// Returns 0 on success, SOCKET_ERROR on failure (check WSAGetLastError()).
int connect_socket_with_timeout(SOCKET sockfd, int connect_socket_with_timeout(SOCKET sockfd,
const struct sockaddr *addr, const struct sockaddr *addr,
int addrlen, int addrlen,
const timeval &tv) { const timeval &tv) {
// Blocking if no timeout // If no timeout requested, do a normal blocking connect.
if (tv.tv_sec == 0 && tv.tv_usec == 0) { if (tv.tv_sec == 0 && tv.tv_usec == 0) {
int rv = ::connect(sockfd, addr, addrlen); int rv = ::connect(sockfd, addr, addrlen);
if (rv == SOCKET_ERROR && WSAGetLastError() == WSAEISCONN) return 0; if (rv == SOCKET_ERROR && WSAGetLastError() == WSAEISCONN) {
return 0;
}
return rv; return rv;
} }
// Set non-blocking // Switch to nonblocking mode
u_long mode = 1UL; u_long mode = 1UL;
::ioctlsocket(sockfd, FIONBIO, &mode); if (::ioctlsocket(sockfd, FIONBIO, &mode) == SOCKET_ERROR) {
return SOCKET_ERROR;
}
int rv = ::connect(sockfd, addr, addrlen); int rv = ::connect(sockfd, addr, addrlen);
int last_error = WSAGetLastError(); int last_error = WSAGetLastError();
if (rv == 0 || last_error == WSAEISCONN) { if (rv == 0 || last_error == WSAEISCONN) {
mode = 0UL; mode = 0UL;
::ioctlsocket(sockfd, FIONBIO, &mode); if (::ioctlsocket(sockfd, FIONBIO, &mode) == SOCKET_ERROR) {
return SOCKET_ERROR;
}
return 0; return 0;
} }
if (last_error != WSAEWOULDBLOCK) { if (last_error != WSAEWOULDBLOCK) {
// Real error
mode = 0UL; mode = 0UL;
::ioctlsocket(sockfd, FIONBIO, &mode); if (::ioctlsocket(sockfd, FIONBIO, &mode)) {
return SOCKET_ERROR;
}
return SOCKET_ERROR; return SOCKET_ERROR;
} }
// Wait for writability // Wait until socket is writable or timeout expires
fd_set wfds; fd_set wfds;
FD_ZERO(&wfds); FD_ZERO(&wfds);
FD_SET(sockfd, &wfds); FD_SET(sockfd, &wfds);
rv = ::select(0, nullptr, &wfds, nullptr, &tv); rv = ::select(0, nullptr, &wfds, nullptr, const_cast<timeval *>(&tv));
// Restore blocking mode regardless of select result
mode = 0UL; mode = 0UL;
::ioctlsocket(sockfd, FIONBIO, &mode); if (::ioctlsocket(sockfd, FIONBIO, &mode) == SOCKET_ERROR) {
return SOCKET_ERROR;
}
if (rv <= 0) { if (rv == 0) {
// timeout or error WSASetLastError(WSAETIMEDOUT);
if (rv == 0) WSASetLastError(WSAETIMEDOUT); return SOCKET_ERROR;
}
if (rv == SOCKET_ERROR) {
return SOCKET_ERROR; return SOCKET_ERROR;
} }
// Check socket for errors
int so_error = 0; int so_error = 0;
int len = sizeof(so_error); int len = sizeof(so_error);
::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&so_error, &len); if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char *>(&so_error), &len) ==
SOCKET_ERROR) {
return SOCKET_ERROR;
}
if (so_error != 0 && so_error != WSAEISCONN) { if (so_error != 0 && so_error != WSAEISCONN) {
// connection failed
WSASetLastError(so_error); WSASetLastError(so_error);
return SOCKET_ERROR; return SOCKET_ERROR;
} }
return 0;
return 0; // success
} }
// try to connect or throw on failure // try to connect or throw on failure

Loading…
Cancel
Save