Proposal
Problem statement
The current implementation of TcpStream does not expose SO_KEEPALIVE, which asks the OS to send keepalive packets over the stream automatically. This feature has been requested for a while now [1].
It seems the reason this has not yet been implemented is because the initial implementation went as far as to take the keepalive interval as a parameter. However, Windows does not directly expose these intervals for reading, causing there to be some debate about the shape of the API [2].
Motivating examples or use cases
There are two major use cases for sending keepalive packets automatically:
- On long-lived connections that are mostly idle, networking equipment (or other parties that the connection relays through) may mistake the connection to be dead when it is just idle. Keepalive packets ensure that there is enough traffic to mitigate this.
- When clients drop their side of the connection improperly (due to e.g. power outage), the TCP connection may stay open and waste resources. Keepalive packets help detect this scenario and prune the connection.
All of this happens automatically without the need for manually-implemented keepalive packets.
Solution sketch
I am proposing that this API is enabled with a bool parameter to align with the implementation in both Windows and Unix, as it is the least common denominator between the two of them. With regards to the call to setsockopt, Windows expects a disable/enable [3], and Unix does as well [4].
With this, the signatures are extremely similar to the existing patterns that call {get,set}sockopt() under the hood with on/off options:
impl TcpStream {
pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()>;
pub fn keepalive(&self) -> io::Result<bool>;
}
I believe the extra configuration for Unix that allows the behavior of SO_KEEPALIVE to be tweaked should not be handled by this API, as this API should just mirror the behavior of setting the SO_KEEPALIVE socket option. On Unix, the configuration is done through the TCP /proc interfaces [5] instead of the socket API.
I have already implemented this and put up a PR for it [6].
Alternatives
- Instead of using a
bool, use some complex enum that has variants for disabled, enabled with default behavior, and enabled with configuration parameters
- I think this would be confusing first of all, but also doesn't make sense in an API that is shared between Windows and Unix. We could return an
Err if the configuration parameters are passed on Windows, but this makes the API contract unintuitive imo.
- Use a third party crate that makes the
unsafe OS calls for you
- Works, but pulling in an entire networking crate for this seems excessive, especially when
std already has extremely similar APIs for the various socket options
- Manual implementation of keepalive packets
- Although this gives the user the most flexibility, this can be tedious. The OS already provides a fine-tuned implementation; it just needs to be switched on.
Links and related work
[1] rust-lang/rust#69774
[2] rust-lang/rust#31945 (comment)
[3] https://learn.microsoft.com/en-us/windows/win32/winsock/so-keepalive
[4] https://man7.org/linux/man-pages/man7/socket.7.html
[5] https://man7.org/linux/man-pages/man7/tcp.7.html
[6] rust-lang/rust#154025
Proposal
Problem statement
The current implementation of
TcpStreamdoes not exposeSO_KEEPALIVE, which asks the OS to send keepalive packets over the stream automatically. This feature has been requested for a while now [1].It seems the reason this has not yet been implemented is because the initial implementation went as far as to take the keepalive interval as a parameter. However, Windows does not directly expose these intervals for reading, causing there to be some debate about the shape of the API [2].
Motivating examples or use cases
There are two major use cases for sending keepalive packets automatically:
All of this happens automatically without the need for manually-implemented keepalive packets.
Solution sketch
I am proposing that this API is enabled with a
boolparameter to align with the implementation in both Windows and Unix, as it is the least common denominator between the two of them. With regards to the call tosetsockopt, Windows expects a disable/enable [3], and Unix does as well [4].With this, the signatures are extremely similar to the existing patterns that call
{get,set}sockopt()under the hood with on/off options:I believe the extra configuration for Unix that allows the behavior of
SO_KEEPALIVEto be tweaked should not be handled by this API, as this API should just mirror the behavior of setting theSO_KEEPALIVEsocket option. On Unix, the configuration is done through the TCP/procinterfaces [5] instead of the socket API.I have already implemented this and put up a PR for it [6].
Alternatives
bool, use some complexenumthat has variants for disabled, enabled with default behavior, and enabled with configuration parametersErrif the configuration parameters are passed on Windows, but this makes the API contract unintuitive imo.unsafeOS calls for youstdalready has extremely similar APIs for the various socket optionsLinks and related work
[1] rust-lang/rust#69774
[2] rust-lang/rust#31945 (comment)
[3] https://learn.microsoft.com/en-us/windows/win32/winsock/so-keepalive
[4] https://man7.org/linux/man-pages/man7/socket.7.html
[5] https://man7.org/linux/man-pages/man7/tcp.7.html
[6] rust-lang/rust#154025