Skip to content

Commit ab9d398

Browse files
committed
Auto merge of #25818 - sfackler:socket-timeouts, r=<try>
Closes #25619 r? @alexcrichton
2 parents 1a3cffb + 97040aa commit ab9d398

File tree

5 files changed

+315
-7
lines changed

5 files changed

+315
-7
lines changed

src/libstd/net/tcp.rs

+103
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use io;
1919
use net::{ToSocketAddrs, SocketAddr, Shutdown};
2020
use sys_common::net as net_imp;
2121
use sys_common::{AsInner, FromInner};
22+
use time::Duration;
2223

2324
/// A structure which represents a TCP stream between a local socket and a
2425
/// remote socket.
@@ -139,6 +140,42 @@ impl TcpStream {
139140
pub fn set_keepalive(&self, seconds: Option<u32>) -> io::Result<()> {
140141
self.0.set_keepalive(seconds)
141142
}
143+
144+
/// Sets the read timeout to the timeout specified.
145+
///
146+
/// If the value specified is `None`, then `read` calls will block
147+
/// indefinitely. It is an error to pass the zero `Duration` to this
148+
/// method.
149+
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
150+
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
151+
self.0.set_read_timeout(dur)
152+
}
153+
154+
/// Sets the write timeout to the timeout specified.
155+
///
156+
/// If the value specified is `None`, then `write` calls will block
157+
/// indefinitely. It is an error to pass the zero `Duration` to this
158+
/// method.
159+
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
160+
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
161+
self.0.set_write_timeout(dur)
162+
}
163+
164+
/// Returns the read timeout of this socket.
165+
///
166+
/// If the timeout is `None`, then `read` calls will block indefinitely.
167+
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
168+
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
169+
self.0.read_timeout()
170+
}
171+
172+
/// Returns the write timeout of this socket.
173+
///
174+
/// If the timeout is `None`, then `write` calls will block indefinitely.
175+
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
176+
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
177+
self.0.write_timeout()
178+
}
142179
}
143180

144181
#[stable(feature = "rust1", since = "1.0.0")]
@@ -262,6 +299,7 @@ mod tests {
262299
use net::test::{next_test_ip4, next_test_ip6};
263300
use sync::mpsc::channel;
264301
use sys_common::AsInner;
302+
use time::Duration;
265303
use thread;
266304

267305
fn each_ip(f: &mut FnMut(SocketAddr)) {
@@ -855,4 +893,69 @@ mod tests {
855893
stream_inner);
856894
assert_eq!(format!("{:?}", stream), compare);
857895
}
896+
897+
#[test]
898+
fn timeouts() {
899+
let addr = next_test_ip4();
900+
let listener = t!(TcpListener::bind(&addr));
901+
902+
let stream = t!(TcpStream::connect(&("localhost", addr.port())));
903+
let dur = Duration::new(15410, 0);
904+
905+
assert_eq!(None, t!(stream.read_timeout()));
906+
907+
t!(stream.set_read_timeout(Some(dur)));
908+
assert_eq!(Some(dur), t!(stream.read_timeout()));
909+
910+
assert_eq!(None, t!(stream.write_timeout()));
911+
912+
t!(stream.set_write_timeout(Some(dur)));
913+
assert_eq!(Some(dur), t!(stream.write_timeout()));
914+
915+
t!(stream.set_read_timeout(None));
916+
assert_eq!(None, t!(stream.read_timeout()));
917+
918+
t!(stream.set_write_timeout(None));
919+
assert_eq!(None, t!(stream.write_timeout()));
920+
}
921+
922+
#[test]
923+
fn test_read_timeout() {
924+
let addr = next_test_ip4();
925+
let listener = t!(TcpListener::bind(&addr));
926+
927+
let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
928+
t!(stream.set_read_timeout(Some(Duration::from_millis(10))));
929+
930+
let mut buf = [0; 10];
931+
let wait = Duration::span(|| {
932+
assert_eq!(ErrorKind::WouldBlock,
933+
stream.read(&mut buf).err().expect("expected error").kind());
934+
});
935+
assert!(wait > Duration::from_millis(5));
936+
assert!(wait < Duration::from_millis(15));
937+
}
938+
939+
#[test]
940+
fn test_read_with_timeout() {
941+
let addr = next_test_ip4();
942+
let listener = t!(TcpListener::bind(&addr));
943+
944+
let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
945+
t!(stream.set_read_timeout(Some(Duration::from_millis(10))));
946+
947+
let mut other_end = t!(listener.accept()).0;
948+
t!(other_end.write_all(b"hello world"));
949+
950+
let mut buf = [0; 11];
951+
t!(stream.read(&mut buf));
952+
assert_eq!(b"hello world", &buf[..]);
953+
954+
let wait = Duration::span(|| {
955+
assert_eq!(ErrorKind::WouldBlock,
956+
stream.read(&mut buf).err().expect("expected error").kind());
957+
});
958+
assert!(wait > Duration::from_millis(5));
959+
assert!(wait < Duration::from_millis(15));
960+
}
858961
}

src/libstd/net/udp.rs

+99
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use io::{self, Error, ErrorKind};
1818
use net::{ToSocketAddrs, SocketAddr, IpAddr};
1919
use sys_common::net as net_imp;
2020
use sys_common::{AsInner, FromInner};
21+
use time::Duration;
2122

2223
/// A User Datagram Protocol socket.
2324
///
@@ -127,6 +128,42 @@ impl UdpSocket {
127128
pub fn set_time_to_live(&self, ttl: i32) -> io::Result<()> {
128129
self.0.time_to_live(ttl)
129130
}
131+
132+
/// Sets the read timeout to the timeout specified.
133+
///
134+
/// If the value specified is `None`, then `read` calls will block
135+
/// indefinitely. It is an error to pass the zero `Duration` to this
136+
/// method.
137+
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
138+
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
139+
self.0.set_read_timeout(dur)
140+
}
141+
142+
/// Sets the write timeout to the timeout specified.
143+
///
144+
/// If the value specified is `None`, then `write` calls will block
145+
/// indefinitely. It is an error to pass the zero `Duration` to this
146+
/// method.
147+
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
148+
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
149+
self.0.set_write_timeout(dur)
150+
}
151+
152+
/// Returns the read timeout of this socket.
153+
///
154+
/// If the timeout is `None`, then `read` calls will block indefinitely.
155+
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
156+
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
157+
self.0.read_timeout()
158+
}
159+
160+
/// Returns the write timeout of this socket.
161+
///
162+
/// If the timeout is `None`, then `write` calls will block indefinitely.
163+
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
164+
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
165+
self.0.write_timeout()
166+
}
130167
}
131168

132169
impl AsInner<net_imp::UdpSocket> for UdpSocket {
@@ -152,6 +189,7 @@ mod tests {
152189
use net::test::{next_test_ip4, next_test_ip6};
153190
use sync::mpsc::channel;
154191
use sys_common::AsInner;
192+
use time::Duration;
155193
use thread;
156194

157195
fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) {
@@ -321,4 +359,65 @@ mod tests {
321359
socket_addr, name, udpsock_inner);
322360
assert_eq!(format!("{:?}", udpsock), compare);
323361
}
362+
363+
#[test]
364+
fn timeouts() {
365+
let addr = next_test_ip4();
366+
367+
let stream = t!(UdpSocket::bind(&addr));
368+
let dur = Duration::new(15410, 0);
369+
370+
assert_eq!(None, t!(stream.read_timeout()));
371+
372+
t!(stream.set_read_timeout(Some(dur)));
373+
assert_eq!(Some(dur), t!(stream.read_timeout()));
374+
375+
assert_eq!(None, t!(stream.write_timeout()));
376+
377+
t!(stream.set_write_timeout(Some(dur)));
378+
assert_eq!(Some(dur), t!(stream.write_timeout()));
379+
380+
t!(stream.set_read_timeout(None));
381+
assert_eq!(None, t!(stream.read_timeout()));
382+
383+
t!(stream.set_write_timeout(None));
384+
assert_eq!(None, t!(stream.write_timeout()));
385+
}
386+
387+
#[test]
388+
fn test_read_timeout() {
389+
let addr = next_test_ip4();
390+
391+
let mut stream = t!(UdpSocket::bind(&addr));
392+
t!(stream.set_read_timeout(Some(Duration::from_millis(10))));
393+
394+
let mut buf = [0; 10];
395+
let wait = Duration::span(|| {
396+
assert_eq!(ErrorKind::WouldBlock,
397+
stream.recv_from(&mut buf).err().expect("expected error").kind());
398+
});
399+
assert!(wait > Duration::from_millis(5));
400+
assert!(wait < Duration::from_millis(15));
401+
}
402+
403+
#[test]
404+
fn test_read_with_timeout() {
405+
let addr = next_test_ip4();
406+
407+
let mut stream = t!(UdpSocket::bind(&addr));
408+
t!(stream.set_read_timeout(Some(Duration::from_millis(10))));
409+
410+
t!(stream.send_to(b"hello world", &addr));
411+
412+
let mut buf = [0; 11];
413+
t!(stream.recv_from(&mut buf));
414+
assert_eq!(b"hello world", &buf[..]);
415+
416+
let wait = Duration::span(|| {
417+
assert_eq!(ErrorKind::WouldBlock,
418+
stream.recv_from(&mut buf).err().expect("expected error").kind());
419+
});
420+
assert!(wait > Duration::from_millis(5));
421+
assert!(wait < Duration::from_millis(15));
422+
}
324423
}

src/libstd/sys/common/net.rs

+39-7
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ use str::from_utf8;
2020
use sys::c;
2121
use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
2222
use sys_common::{AsInner, FromInner, IntoInner};
23+
use time::Duration;
2324

2425
////////////////////////////////////////////////////////////////////////////////
2526
// sockaddr and misc bindings
2627
////////////////////////////////////////////////////////////////////////////////
2728

28-
fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
29+
pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
2930
payload: T) -> io::Result<()> {
3031
unsafe {
3132
let payload = &payload as *const T as *const c_void;
@@ -35,16 +36,15 @@ fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
3536
}
3637
}
3738

38-
#[allow(dead_code)]
39-
fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
39+
pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
4040
val: c_int) -> io::Result<T> {
4141
unsafe {
4242
let mut slot: T = mem::zeroed();
4343
let mut len = mem::size_of::<T>() as socklen_t;
44-
let ret = try!(cvt(c::getsockopt(*sock.as_inner(), opt, val,
45-
&mut slot as *mut _ as *mut _,
46-
&mut len)));
47-
assert_eq!(ret as usize, mem::size_of::<T>());
44+
try!(cvt(c::getsockopt(*sock.as_inner(), opt, val,
45+
&mut slot as *mut _ as *mut _,
46+
&mut len)));
47+
assert_eq!(len as usize, mem::size_of::<T>());
4848
Ok(slot)
4949
}
5050
}
@@ -220,6 +220,22 @@ impl TcpStream {
220220
Ok(())
221221
}
222222

223+
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
224+
self.inner.set_timeout(dur, libc::SO_RCVTIMEO)
225+
}
226+
227+
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
228+
self.inner.set_timeout(dur, libc::SO_SNDTIMEO)
229+
}
230+
231+
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
232+
self.inner.timeout(libc::SO_RCVTIMEO)
233+
}
234+
235+
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
236+
self.inner.timeout(libc::SO_SNDTIMEO)
237+
}
238+
223239
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
224240
self.inner.read(buf)
225241
}
@@ -471,6 +487,22 @@ impl UdpSocket {
471487
pub fn duplicate(&self) -> io::Result<UdpSocket> {
472488
self.inner.duplicate().map(|s| UdpSocket { inner: s })
473489
}
490+
491+
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
492+
self.inner.set_timeout(dur, libc::SO_RCVTIMEO)
493+
}
494+
495+
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
496+
self.inner.set_timeout(dur, libc::SO_SNDTIMEO)
497+
}
498+
499+
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
500+
self.inner.timeout(libc::SO_RCVTIMEO)
501+
}
502+
503+
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
504+
self.inner.timeout(libc::SO_SNDTIMEO)
505+
}
474506
}
475507

476508
impl FromInner<Socket> for UdpSocket {

src/libstd/sys/unix/net.rs

+45
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ use sys::c;
1818
use net::SocketAddr;
1919
use sys::fd::FileDesc;
2020
use sys_common::{AsInner, FromInner};
21+
use sys_common::net::{getsockopt, setsockopt};
22+
use time::Duration;
2123

2224
pub use sys::{cvt, cvt_r};
2325

@@ -73,6 +75,49 @@ impl Socket {
7375
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
7476
self.0.read(buf)
7577
}
78+
79+
pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
80+
let timeout = match dur {
81+
Some(dur) => {
82+
if dur.secs() == 0 && dur.extra_nanos() == 0 {
83+
return Err(io::Error::new(io::ErrorKind::InvalidInput,
84+
"cannot set a 0 duration timeout"));
85+
}
86+
87+
let secs = if dur.secs() > libc::time_t::max_value() as u64 {
88+
libc::time_t::max_value()
89+
} else {
90+
dur.secs() as libc::time_t
91+
};
92+
let mut timeout = libc::timeval {
93+
tv_sec: secs,
94+
tv_usec: (dur.extra_nanos() / 1000) as libc::time_t,
95+
};
96+
if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
97+
timeout.tv_usec = 1;
98+
}
99+
timeout
100+
}
101+
None => {
102+
libc::timeval {
103+
tv_sec: 0,
104+
tv_usec: 0,
105+
}
106+
}
107+
};
108+
setsockopt(self, libc::SOL_SOCKET, kind, timeout)
109+
}
110+
111+
pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> {
112+
let raw: libc::timeval = try!(getsockopt(self, libc::SOL_SOCKET, kind));
113+
if raw.tv_sec == 0 && raw.tv_usec == 0 {
114+
Ok(None)
115+
} else {
116+
let sec = raw.tv_sec as u64;
117+
let nsec = (raw.tv_usec as u32) * 1000;
118+
Ok(Some(Duration::new(sec, nsec)))
119+
}
120+
}
76121
}
77122

78123
impl AsInner<c_int> for Socket {

0 commit comments

Comments
 (0)