Skip to content

Commit dad3282

Browse files
committed
RFC: Socket timesouts
1 parent e1674e3 commit dad3282

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

text/0000-socket-timeouts.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
- Feature Name: socket_timeouts
2+
- Start Date: 2015-04-08
3+
- RFC PR: (leave this empty)
4+
- Rust Issue: (leave this empty)
5+
6+
# Summary
7+
8+
Add sockopt-style timeouts to `std::net` types.
9+
10+
# Motivation
11+
12+
Currently, operations on various socket types in `std::net` block
13+
indefinitely (i.e., until the connection is closed or data is
14+
transferred). But there are many contexts in which timing out a
15+
blocking call is important.
16+
17+
The [goal of the current IO system][io-reform] is to gradually expose
18+
cross-platform, blocking APIs for IO, especially APIs that directly
19+
correspond to the underlying system APIs. Sockets are widely available
20+
with nearly identical system APIs across the platforms Rust targets,
21+
and this includes support for timeouts via [sockopts][sockopt].
22+
23+
So timeouts are well-motivated and well-suited to `std::net`.
24+
25+
# Detailed design
26+
27+
The proposal is to *directly expose* the timeout functionality
28+
provided by [`setsockopt`][sockopt], in much the same way we currently
29+
expose functionality like `set_nodelay`:
30+
31+
```rust
32+
impl TcpStream {
33+
pub fn set_read_timeout(&self, dur: Duration) -> io::Result<()> { ... }
34+
pub fn set_write_timeout(&self, dur: Duration) -> io::Result<()> { ... }
35+
}
36+
37+
impl UdpSocket {
38+
pub fn set_read_timeout(&self, dur: Duration) -> io::Result<()> { ... }
39+
pub fn set_write_timeout(&self, dur: Duration) -> io::Result<()> { ... }
40+
}
41+
```
42+
43+
These methods take an amount of time in the form of a `Duration`,
44+
which is [undergoing stabilization][duration-reform]. They are
45+
implemented via straightforward calls to `setsockopt`.
46+
47+
# Drawbacks
48+
49+
One potential downside to this design is that the timeouts are set
50+
through direct mutation of the socket state, which can lead to
51+
composition problems. For example, a socket could be passed to another
52+
function which needs to use it with a timeout, but setting the timeout
53+
clobbers any previous values. This lack of composability leads to
54+
defensive programming in the form of "callee save" resets of timeouts,
55+
for example. An alternative design is given below.
56+
57+
The advantage of binding the mutating APIs directly is that we keep a
58+
close correspondence between the `std::net` types and their underlying
59+
system types, and a close correspondence between Rust APIs and system
60+
APIs. It's not clear that this kind of composability is important
61+
enough in practice to justify a departure from the traditional API.
62+
63+
# Alternatives
64+
65+
A different approach would be to *wrap* socket types with a "timeout
66+
modifier", which would be responsible for setting and resetting the
67+
timeouts:
68+
69+
```rust
70+
struct WithTimeout<T> {
71+
timeout: Duration,
72+
innter: T
73+
}
74+
75+
impl<T> WithTimeout<T> {
76+
/// Returns the wrapped object, resetting the timeout
77+
pub fn into_inner(self) -> T { ... }
78+
}
79+
80+
impl TcpStream {
81+
/// Wraps the stream with a timeout
82+
pub fn with_timeout(self, timeout: Duration) -> WithTimeout<TcpStream> { ... }
83+
}
84+
85+
impl<T: Read> Read for WithTimeout<T> { ... }
86+
impl<T: Write> Write for WithTimeout<T> { ... }
87+
```
88+
89+
A [previous RFC][deadlines] spelled this out in more detail.
90+
91+
Unfortunately, such a "wrapping" API has problems of its own. It
92+
creates unfortunate type incompatibilities, since you cannot store a
93+
timeout-wrapped socket where a "normal" socket is expected. It is
94+
difficult to be "polymorphic" over timeouts.
95+
96+
Ultimately, it's not clear that the extra complexities of the type
97+
distinction here are worth the better theoretical composability.
98+
99+
# Unresolved questions
100+
101+
Should we consider a preliminary version of this RFC that introduces
102+
methods like `set_read_timeout_ms`, similar to `wait_timeout_ms` on
103+
`Condvar`? These methods have been introduced elsewhere to provide a
104+
stable way to use timeouts prior to `Duration` being stabilized.
105+
106+
[io-reform]: https://github.com/rust-lang/rfcs/blob/master/text/0517-io-os-reform.md
107+
[sockopt]: http://pubs.opengroup.org/onlinepubs/009695399/functions/setsockopt.html
108+
[duration-reform]: https://github.com/rust-lang/rfcs/pull/1040
109+
[deadlines]: https://github.com/rust-lang/rfcs/pull/577/

0 commit comments

Comments
 (0)