mirror of
https://github.com/libevent/libevent.git
synced 2025-01-31 09:12:55 +08:00
Enable the full TCP KeepAlive mechanism on Windows (#1568)
#1532 implemented the full support of TCP Keep-Alives on UNIX-like OS's while leaving a `TODO` for Windows. This PR intends to resolve that `TODO`. ## References - [SIO_KEEPALIVE_VALS Control Code](https://learn.microsoft.com/en-us/windows/win32/winsock/sio-keepalive-vals) - [IPPROTO_TCP socket options](https://learn.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options) - [TCP_KEEPINVTL and TCP_KEEPIDLE - Socket Keep Alives not working](https://cygwin.com/pipermail/cygwin/2020-June/245436.html) - [Cygwin: tcp: Support TCP_KEEPIDLE, TCP_KEEPCNT, TCP_KEEPINTVL](https://sourceware.org/pipermail/cygwin-cvs/2020q3/014473.html) - [Add cross-platform support for keep-alive socket options](https://github.com/dotnet/corefx/pull/29963/files)
This commit is contained in:
parent
9c8860ec6c
commit
0054b9aadb
58
evutil.c
58
evutil.c
@ -39,6 +39,9 @@
|
|||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <winerror.h>
|
#include <winerror.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
|
#ifdef _MSC_VER /* mstcpip.h is missing on MinGW */
|
||||||
|
#include <mstcpip.h> /* for SIO_KEEPALIVE_VALS and tcp_keepalive struct */
|
||||||
|
#endif
|
||||||
#ifdef EVENT__HAVE_AFUNIX_H
|
#ifdef EVENT__HAVE_AFUNIX_H
|
||||||
#include <afunix.h>
|
#include <afunix.h>
|
||||||
#endif
|
#endif
|
||||||
@ -112,6 +115,15 @@
|
|||||||
#define mode_t int
|
#define mode_t int
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(SIO_KEEPALIVE_VALS)
|
||||||
|
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
|
||||||
|
struct tcp_keepalive {
|
||||||
|
u_long onoff;
|
||||||
|
u_long keepalivetime;
|
||||||
|
u_long keepaliveinterval;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef O_RDONLY
|
#ifndef O_RDONLY
|
||||||
#define O_RDONLY _O_RDONLY
|
#define O_RDONLY _O_RDONLY
|
||||||
#endif
|
#endif
|
||||||
@ -3096,17 +3108,43 @@ evutil_set_tcp_keepalive(evutil_socket_t fd, int on, int timeout)
|
|||||||
if (!on)
|
if (!on)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Unlike Unix-like OS's, TCP keep-alive mechanism on Windows is kind of a mess,
|
#ifdef _WIN32
|
||||||
* setting TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT on Windows could be a bit tricky.
|
idle = timeout;
|
||||||
* Check out https://learn.microsoft.com/en-us/windows/win32/winsock/sio-keepalive-vals,
|
intvl = idle/3;
|
||||||
* https://learn.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options.
|
if (intvl == 0)
|
||||||
* These three options are not available until Windows 10, version 1709 where we set them
|
intvl = 1;
|
||||||
* by `setsockopt` (slightly different from Unix-like OS's pattern), while on older Windows,
|
/* The three options TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT are not available until
|
||||||
* we have to use `WSAIoctl` instead.
|
* Windows 10 version 1709, but let's gamble here.
|
||||||
* Therefore, we skip setting those three options on Windows for now.
|
|
||||||
* TODO(panjf2000): enable the full TCP keep-alive mechanism on Windows when we find a feasible way to do it.
|
|
||||||
*/
|
*/
|
||||||
#ifndef _WIN32
|
#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
|
||||||
|
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cnt = 3;
|
||||||
|
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* For those versions prior to Windows 10 version 1709, we fall back to SIO_KEEPALIVE_VALS.
|
||||||
|
* The SIO_KEEPALIVE_VALS IOCTL is supported on Windows 2000 and later versions of the operating system. */
|
||||||
|
#elif defined(SIO_KEEPALIVE_VALS)
|
||||||
|
struct tcp_keepalive keepalive;
|
||||||
|
keepalive.onoff = on;
|
||||||
|
keepalive.keepalivetime = idle * 1000; /* the kernel expects milliseconds */
|
||||||
|
keepalive.keepaliveinterval = intvl * 1000; /* ditto */
|
||||||
|
/* On Windows Vista and later, the number of keep-alive probes (data retransmissions)
|
||||||
|
* is set to 10 and cannot be changed.
|
||||||
|
* On Windows Server 2003, Windows XP, and Windows 2000, the default setting for
|
||||||
|
* number of keep-alive probes is 5 and cannot be changed programmatically.
|
||||||
|
*/
|
||||||
|
DWORD dummy;
|
||||||
|
if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, (LPVOID) &keepalive, sizeof(keepalive), NULL, 0, &dummy, NULL, NULL))
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* !_WIN32 */
|
||||||
|
|
||||||
#ifdef __sun
|
#ifdef __sun
|
||||||
/* The implementation of TCP keep-alive on Solaris/SmartOS is a bit unusual
|
/* The implementation of TCP keep-alive on Solaris/SmartOS is a bit unusual
|
||||||
|
Loading…
x
Reference in New Issue
Block a user