You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Tracking issue for the socket timeout functions #27773
This is a tracking issue for the unstable socket_timeout feature in the standard library. Now that the Duration type is stable it may be the case that these methods can just be stabilized as-is.
It was pointed out in a hyper issue that the returned error when a timeout is hit is OS dependent. It might be helpful to include a Errors subheading to the documentation of these methods?
Unixy returns ErrorKind::WouldBlock
Windows returns ErrorKind::TimedOut
An alternative would be to normalize them into 1 type, but that seems more controversial.
I would like them to be normalized into one kind of error, not doing so will make code that uses these APIs non-cross-platform by default, which is very unfortunate IMO.
It's actually worse than the error codes just being inconsistent: on Windows, recv() returns WSAETIMEDOUT both when the receive call times out and when the connection itself times out, so you can't tell if the connection is still alive.
It's actually worse than the error codes just being inconsistent: on
Windows, recv() returns WSAETIMEDOUT both when the receive call times out
and when the socket itself times out, so you can't tell if the socket is
still alive.
—
Reply to this email directly or view it on GitHub #27773 (comment).
@seanmonstar, @reem, my personal inclination is to do what we do in the rest of std::io, which is to pass through exactly what the system does in as many places as possible. I've found that tampering with things like the error code and trying to unify them across platforms generally leads to weird corner cases which act differently than you may expect, so just reexposing what's happening underneath has worked quite well for us so far.
Is the connection timing out in reference to TCP keepalive or something?
It's a bit more general than that: it means that the network stack closed the connection because it couldn't get a response from the other end. That doesn't necessarily mean a keepalive; it could also mean that it hit the general retransmission limit.
@alexcrichton The problem here isn't precisely the portability of error codes; it's that recv() on Windows claims the connection is dead when it actually isn't. This means portable code must assume the connection is dead if the read timeout expires, so people will write code on Unix and find that there's no way to replicate the behavior on Windows without switching from std::net to some other networking library.
my personal inclination is to do what we do in the rest of std::io, which is to pass through exactly what the system does in as many places as possible
I'm not sure I agree with that characterization, though I know we had many debates about how to handle errors :-) In particular, though, we strove for cross-platform behavior wherever reasonable while also avoiding laying on extra semantics or overhead. Of course, the hard cases are when these constraints are at odds.
From my perspective, if there's a reasonably clear way to merge or reinterpret errors so that they are consistent across platforms without information loss, I prefer doing so. The downside is that it's more difficult to map back to the underlying system error. (IIRC we ended up having a single mapping function from system errors to our IO errors, so what I'm suggesting is indeed somewhat of a departure.)
Failing that, it's not too bad if there are multiple errors you might get depending on the platform, as long as there's a reasonable, robust way to program against them that doesn't require #[cfg].
It's not clear whether we can achieve either of these, though, without layering on some extra checking/semantics on the Windows side -- but I haven't dug into the specifics too much.
Can someone more familiar with the details propose an alternative that favors cross-platform semantics?
Alternative: don't use SO_RCVTIMEO or SO_SNDTIMEO because the semantics aren't portable. (Even if you ignore the Windows issues, the semantics are slightly different on Linux vs. *BSD.) Instead, use non-blocking sockets and select() to implement the intended functionality.
We discussed the issues in this thread fairly extensively in the last libs team meeting. The consensus was to follow the philosophy laid out in @alexcrichton's earlier comment: rather than trying to layer on additional semantics for cross-platform compatibility, we optimize for transparency, where IO functionality has a clear mapping to system APIs -- including errors. That means, in particular, sticking with a single global mapping of OS error codes to our IO error kinds.
This strategy is contingent on clear documentation of platform-specific behavior, and the ability to provide additional layers, in std and elsewhere, that try to provide higher-level bridges between platforms. In particular, @sfackler suggested that the ErrorKind enum (or perhaps the Error type itself) could provide helper methods for deciphering errors in a context-specific and more cross-platform way. This provides an opt-in semantic layering over the raw system API. We plan to prototype this approach out of tree, and then consider bringing it into std.
Activity
alexcrichton commentedon Aug 12, 2015
cc @sfackler
alexcrichton commentedon Aug 14, 2015
This feature is now entering its final comment period for stabilization.
seanmonstar commentedon Aug 14, 2015
It was pointed out in a hyper issue that the returned error when a timeout is hit is OS dependent. It might be helpful to include a
Errorssubheading to the documentation of these methods?ErrorKind::WouldBlockErrorKind::TimedOutAn alternative would be to normalize them into 1 type, but that seems more controversial.
reem commentedon Aug 14, 2015
I would like them to be normalized into one kind of error, not doing so will make code that uses these APIs non-cross-platform by default, which is very unfortunate IMO.
eefriedman commentedon Sep 3, 2015
It's actually worse than the error codes just being inconsistent: on Windows, recv() returns WSAETIMEDOUT both when the receive call times out and when the connection itself times out, so you can't tell if the connection is still alive.
droundy commentedon Sep 3, 2015
What does it mean for a socket itself to time out?
On Thu, Sep 3, 2015, 4:38 AM eefriedman notifications@github.com wrote:
eefriedman commentedon Sep 3, 2015
Err, sorry, I meant the connection, not the socket.
sfackler commentedon Sep 3, 2015
Is the connection timing out in reference to TCP keepalive or something?
alexcrichton commentedon Sep 3, 2015
@seanmonstar, @reem, my personal inclination is to do what we do in the rest of
std::io, which is to pass through exactly what the system does in as many places as possible. I've found that tampering with things like the error code and trying to unify them across platforms generally leads to weird corner cases which act differently than you may expect, so just reexposing what's happening underneath has worked quite well for us so far.eefriedman commentedon Sep 3, 2015
It's a bit more general than that: it means that the network stack closed the connection because it couldn't get a response from the other end. That doesn't necessarily mean a keepalive; it could also mean that it hit the general retransmission limit.
@alexcrichton The problem here isn't precisely the portability of error codes; it's that recv() on Windows claims the connection is dead when it actually isn't. This means portable code must assume the connection is dead if the read timeout expires, so people will write code on Unix and find that there's no way to replicate the behavior on Windows without switching from std::net to some other networking library.
aturon commentedon Sep 9, 2015
@alexcrichton
I'm not sure I agree with that characterization, though I know we had many debates about how to handle errors :-) In particular, though, we strove for cross-platform behavior wherever reasonable while also avoiding laying on extra semantics or overhead. Of course, the hard cases are when these constraints are at odds.
From my perspective, if there's a reasonably clear way to merge or reinterpret errors so that they are consistent across platforms without information loss, I prefer doing so. The downside is that it's more difficult to map back to the underlying system error. (IIRC we ended up having a single mapping function from system errors to our IO errors, so what I'm suggesting is indeed somewhat of a departure.)
Failing that, it's not too bad if there are multiple errors you might get depending on the platform, as long as there's a reasonable, robust way to program against them that doesn't require
#[cfg].It's not clear whether we can achieve either of these, though, without layering on some extra checking/semantics on the Windows side -- but I haven't dug into the specifics too much.
Can someone more familiar with the details propose an alternative that favors cross-platform semantics?
eefriedman commentedon Sep 9, 2015
Alternative: don't use SO_RCVTIMEO or SO_SNDTIMEO because the semantics aren't portable. (Even if you ignore the Windows issues, the semantics are slightly different on Linux vs. *BSD.) Instead, use non-blocking sockets and select() to implement the intended functionality.
aturon commentedon Sep 11, 2015
We discussed the issues in this thread fairly extensively in the last libs team meeting. The consensus was to follow the philosophy laid out in @alexcrichton's earlier comment: rather than trying to layer on additional semantics for cross-platform compatibility, we optimize for transparency, where IO functionality has a clear mapping to system APIs -- including errors. That means, in particular, sticking with a single global mapping of OS error codes to our IO error kinds.
This strategy is contingent on clear documentation of platform-specific behavior, and the ability to provide additional layers, in
stdand elsewhere, that try to provide higher-level bridges between platforms. In particular, @sfackler suggested that theErrorKindenum (or perhaps theErrortype itself) could provide helper methods for deciphering errors in a context-specific and more cross-platform way. This provides an opt-in semantic layering over the raw system API. We plan to prototype this approach out of tree, and then consider bringing it intostd.std: Stabilize/deprecate features for 1.4
Auto merge of #28339 - alexcrichton:stabilize-1.4, r=aturon