-
Notifications
You must be signed in to change notification settings - Fork 24
Description
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 complexenumthat 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
Errif the configuration parameters are passed on Windows, but this makes the API contract unintuitive imo.
- 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
- Use a third party crate that makes the
unsafeOS calls for you- Works, but pulling in an entire networking crate for this seems excessive, especially when
stdalready has extremely similar APIs for the various socket options
- Works, but pulling in an entire networking crate for this seems excessive, especially when
- 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