Skip to content

Commit 97040aa

Browse files
committed
Move platform specific stuff around and add tests
1 parent 04b4083 commit 97040aa

File tree

5 files changed

+161
-96
lines changed

5 files changed

+161
-96
lines changed

src/libstd/net/tcp.rs

+40
Original file line numberDiff line numberDiff line change
@@ -918,4 +918,44 @@ mod tests {
918918
t!(stream.set_write_timeout(None));
919919
assert_eq!(None, t!(stream.write_timeout()));
920920
}
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+
}
921961
}

src/libstd/net/udp.rs

+37
Original file line numberDiff line numberDiff line change
@@ -383,4 +383,41 @@ mod tests {
383383
t!(stream.set_write_timeout(None));
384384
assert_eq!(None, t!(stream.write_timeout()));
385385
}
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+
}
386423
}

src/libstd/sys/common/net.rs

+10-96
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use time::Duration;
2626
// sockaddr and misc bindings
2727
////////////////////////////////////////////////////////////////////////////////
2828

29-
fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
29+
pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
3030
payload: T) -> io::Result<()> {
3131
unsafe {
3232
let payload = &payload as *const T as *const c_void;
@@ -36,7 +36,7 @@ fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
3636
}
3737
}
3838

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();
@@ -163,92 +163,6 @@ pub fn lookup_addr(addr: &IpAddr) -> io::Result<String> {
163163
}
164164
}
165165

166-
////////////////////////////////////////////////////////////////////////////////
167-
// Timeouts
168-
////////////////////////////////////////////////////////////////////////////////
169-
170-
#[cfg(target_os = "windows")]
171-
fn set_timeout(socket: &Socket, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
172-
let timeout = match dur {
173-
Some(dur) => {
174-
if dur.secs() == 0 && dur.extra_nanos() == 0 {
175-
return Err(io::Error::new(io::ErrorKind::InvalidInput,
176-
"cannot set a 0 duration timeout"));
177-
}
178-
179-
let mut timeout = if dur.secs() > (libc::DWORD::max_value() / 1000) as u64 {
180-
libc::DWORD::max_value()
181-
} else {
182-
(dur.secs() * 1000) as libc::DWORD
183-
};
184-
timeout = timeout.saturating_add((dur.extra_nanos() / 1000000) as libc::DWORD);
185-
if timeout == 0 {
186-
timeout = 1;
187-
}
188-
timeout
189-
}
190-
None => 0
191-
};
192-
setsockopt(socket, libc::SOL_SOCKET, kind, timeout)
193-
}
194-
195-
#[cfg(not(target_os = "windows"))]
196-
fn set_timeout(socket: &Socket, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
197-
let timeout = match dur {
198-
Some(dur) => {
199-
if dur.secs() == 0 && dur.extra_nanos() == 0 {
200-
return Err(io::Error::new(io::ErrorKind::InvalidInput,
201-
"cannot set a 0 duration timeout"));
202-
}
203-
204-
let secs = if dur.secs() > libc::time_t::max_value() as u64 {
205-
libc::time_t::max_value()
206-
} else {
207-
dur.secs() as libc::time_t
208-
};
209-
let mut timeout = libc::timeval {
210-
tv_sec: secs,
211-
tv_usec: (dur.extra_nanos() / 1000) as libc::time_t,
212-
};
213-
if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
214-
timeout.tv_usec = 1;
215-
}
216-
timeout
217-
}
218-
None => {
219-
libc::timeval {
220-
tv_sec: 0,
221-
tv_usec: 0,
222-
}
223-
}
224-
};
225-
setsockopt(socket, libc::SOL_SOCKET, kind, timeout)
226-
}
227-
228-
#[cfg(target_os = "windows")]
229-
fn timeout(socket: &Socket, kind: libc::c_int) -> io::Result<Option<Duration>> {
230-
let raw: libc::DWORD = try!(getsockopt(socket, libc::SOL_SOCKET, kind));
231-
if raw == 0 {
232-
Ok(None)
233-
} else {
234-
let secs = raw / 1000;
235-
let nsec = (raw % 1000) * 1000000;
236-
Ok(Some(Duration::new(secs as u64, nsec as u32)))
237-
}
238-
}
239-
240-
#[cfg(not(target_os = "windows"))]
241-
fn timeout(socket: &Socket, kind: libc::c_int) -> io::Result<Option<Duration>> {
242-
let raw: libc::timeval = try!(getsockopt(socket, libc::SOL_SOCKET, kind));
243-
if raw.tv_sec == 0 && raw.tv_usec == 0 {
244-
Ok(None)
245-
} else {
246-
let sec = raw.tv_sec as u64;
247-
let nsec = (raw.tv_usec as u32) * 1000;
248-
Ok(Some(Duration::new(sec, nsec)))
249-
}
250-
}
251-
252166
////////////////////////////////////////////////////////////////////////////////
253167
// TCP streams
254168
////////////////////////////////////////////////////////////////////////////////
@@ -307,19 +221,19 @@ impl TcpStream {
307221
}
308222

309223
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
310-
set_timeout(&self.inner, dur, libc::SO_RCVTIMEO)
224+
self.inner.set_timeout(dur, libc::SO_RCVTIMEO)
311225
}
312226

313227
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
314-
set_timeout(&self.inner, dur, libc::SO_SNDTIMEO)
228+
self.inner.set_timeout(dur, libc::SO_SNDTIMEO)
315229
}
316230

317231
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
318-
timeout(&self.inner, libc::SO_RCVTIMEO)
232+
self.inner.timeout(libc::SO_RCVTIMEO)
319233
}
320234

321235
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
322-
timeout(&self.inner, libc::SO_SNDTIMEO)
236+
self.inner.timeout(libc::SO_SNDTIMEO)
323237
}
324238

325239
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
@@ -575,19 +489,19 @@ impl UdpSocket {
575489
}
576490

577491
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
578-
set_timeout(&self.inner, dur, libc::SO_RCVTIMEO)
492+
self.inner.set_timeout(dur, libc::SO_RCVTIMEO)
579493
}
580494

581495
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
582-
set_timeout(&self.inner, dur, libc::SO_SNDTIMEO)
496+
self.inner.set_timeout(dur, libc::SO_SNDTIMEO)
583497
}
584498

585499
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
586-
timeout(&self.inner, libc::SO_RCVTIMEO)
500+
self.inner.timeout(libc::SO_RCVTIMEO)
587501
}
588502

589503
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
590-
timeout(&self.inner, libc::SO_SNDTIMEO)
504+
self.inner.timeout(libc::SO_SNDTIMEO)
591505
}
592506
}
593507

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 {

src/libstd/sys/windows/net.rs

+29
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ use num::One;
1919
use ops::Neg;
2020
use rt;
2121
use sync::Once;
22+
use sys;
2223
use sys::c;
2324
use sys_common::{AsInner, FromInner};
25+
use sys_common::net::{setsockopt, getsockopt};
26+
use time::Duration;
2427

2528
pub type wrlen_t = i32;
2629

@@ -127,6 +130,32 @@ impl Socket {
127130
}
128131
}
129132
}
133+
134+
pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
135+
let timeout = match dur {
136+
Some(dur) => {
137+
let timeout = sys::dur2timeout(dur);
138+
if timeout == 0 {
139+
return Err(io::Error::new(io::ErrorKind::InvalidInput,
140+
"cannot set a 0 duration timeout"));
141+
}
142+
timeout
143+
}
144+
None => 0
145+
};
146+
setsockopt(self, libc::SOL_SOCKET, kind, timeout)
147+
}
148+
149+
pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> {
150+
let raw: libc::DWORD = try!(getsockopt(self, libc::SOL_SOCKET, kind));
151+
if raw == 0 {
152+
Ok(None)
153+
} else {
154+
let secs = raw / 1000;
155+
let nsec = (raw % 1000) * 1000000;
156+
Ok(Some(Duration::new(secs as u64, nsec as u32)))
157+
}
158+
}
130159
}
131160

132161
impl Drop for Socket {

0 commit comments

Comments
 (0)