- 
                Notifications
    
You must be signed in to change notification settings  - Fork 5.2k
 
Description
Allow for configuring TCP Keepalive in a portable manner.
Rationale
TCP Keepalive is an optional feature of TCP that is implemented in most widely used OSes and the feature can already be enabled in .NET by using SocketOptionName.KeepAlive.
However, it is not possible, as of now, to set the various keepalive options using a standard .NET API.
Most platforms, more than simply allowing TCP keepalive, provide a subset of the following three options:
- Keepalive Time
 - Keepalive Interval
 - Keepalive Retry Count
 
Since Windows 2000, it has been possible to set both Keepalive Time and Keepalive Interval by using SIO_KEEPALIVE_VALS with Winsock IOCTL (Exposed via Socket.IOControl and IOControlCode.KeepAliveValues in .NET)
Under Linux, TCP Keepalive can be configured with setsockopt under the SOL_TCP level. The allowed parameters are TCP_KEEPCNT, TCP_KEEPIDLE and TCP_KEEPINTVL.
It seems OSX also has some good support for the feature since OSX Lion, only using slightly different names than Linux:
https://lists.apple.com/archives/macnetworkprog/2012/Jul/msg00005.html
From the docs, since Windows 10 version 1703 and 1709, settings that are code-compatible with Linux and OSX were introduced:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms738596(v=vs.85).aspx
As explained in https://github.com/dotnet/corefx/issues/14237, it is impossible today to configure TCP keepalive on platforms other than Windows, where Socket.IOControl can do the trick.
Proposed API
enum SocketOptionName
{
//…
	#region SocketOptionLevel.Tcp
//…
	// TCP KeepAlive options
	TcpKeepAliveRetryCount = 16, // TCP_KEEPCNT value from Ws2ipdef.h
	TcpKeepAliveTime = 3, // TCP_KEEPIDLE = TCP_KEEPALIVE value from Ws2ipdef.h
	TcpKeepAliveInterval = 17, // TCP_KEEPINTVL value from Ws2ipdef.h
	#endregion
//…
}Example
void EnableKeepAlive(Socket socket, byte retryCount, int keepAliveTimeInSeconds, int keepAliveIntervalInSeconds)
{
	socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
	socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, (int)retryCount);
	socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, keepAliveTimeInSeconds);
	socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, keepAliveIntervalInSeconds);
}Details
The PAL for each supported platform would translate the call to Socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAlive*, *) into the appropriate call for the platform.
- On Linux, and OSX ≥ 10.7, .NET enumeration values would be translated to corresponding system values for 
setsockopt(). - On Windows 10 version 1709 and newer, the flags would be transferred as-is to the underlying Winsock API, as they already are today.
 - Ideally, 
TcpKeepAliveTimeandTcpKeepAliveIntervalwould be marshalled tosocket.IOControl(IOControlCode.KeepAliveValues, KeepAliveValues, null)for previous versions of windows, whileTcpKeepAliveRetryCountwould be simply ignored. 
TCP_KEEPIDLE (or TCP_KEEPALIVE) and TCP_KEEPINTVL are expressed in seconds, while SIO_KEEPALIVE_VALS expresses durations in milliseconds.
Questions
The TCP keepalive feature being optional, it is not required that all platforms support it or provide any specific way of configuring the feature.
- Should a call to a non supported TCP keepalive option throw an exception ?
 - How should a caller determine if a given option is indeed supported on the current platform ?
 - Should an additional socket property, similar to 
Socket.LingerStatebe also added (e.g.KeepAliveStateof typeKeepAliveOption), in order to group the various options and handle everything at one place ?- The feature could be used with something like 
socket.KeepAliveState = new KeepAliveOption(true, 15, 7200, 1) - This would also be more consistent with the way the feature is configured on legacy Windows system.
 
 - The feature could be used with something like