I guess testing on windows passes.

pull/3432/head
Mihir Patel 2 months ago
parent 9397e31e77
commit 4f9b630d46

@ -58,6 +58,60 @@ public:
SOCKET fd() const { return socket_; }
int connect_socket_with_timeout(SOCKET sockfd,
const struct sockaddr *addr,
int addrlen,
const timeval &tv) {
// Blocking if no timeout
if (tv.tv_sec == 0 && tv.tv_usec == 0) {
int rv = ::connect(sockfd, addr, addrlen);
if (rv == SOCKET_ERROR && WSAGetLastError() == WSAEISCONN) return 0;
return rv;
}
// Set non-blocking
u_long mode = 1UL;
::ioctlsocket(sockfd, FIONBIO, &mode);
int rv = ::connect(sockfd, addr, addrlen);
int last_error = WSAGetLastError();
if (rv == 0 || last_error == WSAEISCONN) {
mode = 0UL;
::ioctlsocket(sockfd, FIONBIO, &mode);
return 0;
}
if (last_error != WSAEWOULDBLOCK) {
mode = 0UL;
::ioctlsocket(sockfd, FIONBIO, &mode);
return SOCKET_ERROR;
}
// Wait for writability
fd_set wfds;
FD_ZERO(&wfds);
FD_SET(sockfd, &wfds);
rv = ::select(0, nullptr, &wfds, nullptr, &tv);
mode = 0UL;
::ioctlsocket(sockfd, FIONBIO, &mode);
if (rv <= 0) {
// timeout or error
if (rv == 0) WSASetLastError(WSAETIMEDOUT);
return SOCKET_ERROR;
}
// Check socket for errors
int so_error = 0;
int len = sizeof(so_error);
::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&so_error, &len);
if (so_error != 0 && so_error != WSAEISCONN) {
WSASetLastError(so_error);
return SOCKET_ERROR;
}
return 0;
}
// try to connect or throw on failure
void connect(const std::string &host, int port, int timeout_ms) {
if (is_connected()) {
@ -71,6 +125,10 @@ public:
hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value
hints.ai_protocol = 0;
timeval tv;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
auto port_str = std::to_string(port);
struct addrinfo *addrinfo_result;
auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
@ -82,7 +140,6 @@ public:
}
// Try each address until we successfully connect(2).
for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) {
socket_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (socket_ == INVALID_SOCKET) {
@ -90,47 +147,11 @@ public:
WSACleanup();
continue;
}
// set non-blocking if timeout specified
u_long mode = (timeout_ms > 0) ? 1UL : 0UL;
::ioctlsocket(socket_, FIONBIO, &mode);
rv = ::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen);
if (rv == SOCKET_ERROR) {
last_error = WSAGetLastError();
if (timeout_ms > 0 && last_error == WSAEWOULDBLOCK) {
fd_set wfds;
FD_ZERO(&wfds);
FD_SET(socket_, &wfds);
timeval tv;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
rv = ::select(0, nullptr, &wfds, nullptr, &tv);
if (rv > 0) {
int so_error = 0;
int len = sizeof(so_error);
::getsockopt(socket_, SOL_SOCKET, SO_ERROR, (char *)&so_error, &len);
if (so_error == 0)
rv = 0;
else {
last_error = so_error;
rv = SOCKET_ERROR;
}
} else {
last_error = (rv == 0 ? WSAETIMEDOUT : WSAGetLastError());
rv = SOCKET_ERROR;
}
}
}
// restore blocking mode
mode = 0UL;
::ioctlsocket(socket_, FIONBIO, &mode);
if (rv == 0) {
if (connect_socket_with_timeout(socket_, rp->ai_addr, (int)rp->ai_addrlen, tv) == 0) {
last_error = 0;
break;
}
last_error = WSAGetLastError();
::closesocket(socket_);
socket_ = INVALID_SOCKET;
}
@ -139,10 +160,11 @@ public:
WSACleanup();
throw_winsock_error_("connect failed", last_error);
}
if (timeout_ms > 0) {
DWORD tv = static_cast<DWORD>(timeout_ms);
::setsockopt(socket_, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv));
::setsockopt(socket_, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, sizeof(tv));
}
// set TCP_NODELAY
int enable_flag = 1;

@ -151,9 +151,11 @@ public:
throw_spdlog_ex("::connect failed", last_errno);
}
if (timeout_ms > 0) {
// Set timeouts for send and recv
::setsockopt(socket_, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv));
::setsockopt(socket_, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, sizeof(tv));
}
// set TCP_NODELAY
int enable_flag = 1;

@ -31,7 +31,7 @@ namespace sinks {
struct tcp_sink_config {
std::string server_host;
int server_port;
int timeout_ms = 0;
int timeout_ms = 0; // The timeout for all 3 major socket operations that is connect, send, and recv
bool lazy_connect = false; // if true connect on first log call instead of on construction
tcp_sink_config(std::string host, int port)

Loading…
Cancel
Save