summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Grunder <michael.grunder@gmail.com>2022-09-03 12:39:57 -0700
committerGitHub <noreply@github.com>2022-09-03 12:39:57 -0700
commit61b5b299f0ac4f0efbe11a45716e06a9c35f37b7 (patch)
treeaa27e6e89ac46f0fc8f1032c488924f47fcfeedc
parentfce8abc1c19ab731f5c84797aa71b4d49921913f (diff)
Use a windows specific keepalive function. (#1104)
Use a windows specific keepalive function. While it is possible to toggle `TCP_KEEPALIVE` in windows via setsockopt, you have to use `WSAIoctl` to set the interval. Since `WSAIoctl` can actually do all of this in one call (toggle the option, and set the corresponding interval), just use that in Windows and avoid the call to `setsockopt` alltogether. Fixes: #1100
-rw-r--r--net.c9
-rw-r--r--sockcompat.c17
-rw-r--r--sockcompat.h3
-rw-r--r--test.c11
4 files changed, 40 insertions, 0 deletions
diff --git a/net.c b/net.c
index 8cd3d71..2b591b9 100644
--- a/net.c
+++ b/net.c
@@ -168,6 +168,7 @@ int redisKeepAlive(redisContext *c, int interval) {
int val = 1;
redisFD fd = c->fd;
+#ifndef _WIN32
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
return REDIS_ERR;
@@ -201,7 +202,15 @@ int redisKeepAlive(redisContext *c, int interval) {
}
#endif
#endif
+#else
+ int res;
+ res = win32_redisKeepAlive(fd, interval * 1000);
+ if (res != 0) {
+ __redisSetError(c, REDIS_ERR_OTHER, strerror(res));
+ return REDIS_ERR;
+ }
+#endif
return REDIS_OK;
}
diff --git a/sockcompat.c b/sockcompat.c
index 31df325..378745f 100644
--- a/sockcompat.c
+++ b/sockcompat.c
@@ -260,4 +260,21 @@ int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}
+
+int win32_redisKeepAlive(SOCKET sockfd, int interval_ms) {
+ struct tcp_keepalive cfg;
+ DWORD bytes_in;
+ int res;
+
+ cfg.onoff = 1;
+ cfg.keepaliveinterval = interval_ms;
+ cfg.keepalivetime = interval_ms;
+
+ res = WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, &cfg,
+ sizeof(struct tcp_keepalive), NULL, 0,
+ &bytes_in, NULL, NULL);
+
+ return res == 0 ? 0 : _wsaErrorToErrno(res);
+}
+
#endif /* _WIN32 */
diff --git a/sockcompat.h b/sockcompat.h
index 85810e8..1aaf23f 100644
--- a/sockcompat.h
+++ b/sockcompat.h
@@ -50,6 +50,7 @@
#include <ws2tcpip.h>
#include <stddef.h>
#include <errno.h>
+#include <Mstcpip.h>
#ifdef _MSC_VER
typedef long long ssize_t;
@@ -71,6 +72,8 @@ ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags);
typedef ULONG nfds_t;
int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout);
+int win32_redisKeepAlive(SOCKET sockfd, int interval_ms);
+
#ifndef REDIS_SOCKCOMPAT_IMPLEMENTATION
#define getaddrinfo(node, service, hints, res) win32_getaddrinfo(node, service, hints, res)
#undef gai_strerror
diff --git a/test.c b/test.c
index e4aad54..fe9b478 100644
--- a/test.c
+++ b/test.c
@@ -405,6 +405,16 @@ static void test_append_formatted_commands(struct config config) {
disconnect(c, 0);
}
+static void test_tcp_options(struct config cfg) {
+ redisContext *c;
+
+ c = do_connect(cfg);
+ test("We can enable TCP_KEEPALIVE: ");
+ test_cond(redisEnableKeepAlive(c) == REDIS_OK);
+
+ disconnect(c, 0);
+}
+
static void test_reply_reader(void) {
redisReader *reader;
void *reply, *root;
@@ -2261,6 +2271,7 @@ int main(int argc, char **argv) {
test_blocking_io_errors(cfg);
test_invalid_timeout_errors(cfg);
test_append_formatted_commands(cfg);
+ test_tcp_options(cfg);
if (throughput) test_throughput(cfg);
printf("\nTesting against Unix socket connection (%s): ", cfg.unix_sock.path);