parent
1a3cffbddf
commit
69a0e1af95
6 changed files with 324 additions and 7 deletions
|
@ -19,6 +19,7 @@ use io;
|
||||||
use net::{ToSocketAddrs, SocketAddr, Shutdown};
|
use net::{ToSocketAddrs, SocketAddr, Shutdown};
|
||||||
use sys_common::net as net_imp;
|
use sys_common::net as net_imp;
|
||||||
use sys_common::{AsInner, FromInner};
|
use sys_common::{AsInner, FromInner};
|
||||||
|
use time::Duration;
|
||||||
|
|
||||||
/// A structure which represents a TCP stream between a local socket and a
|
/// A structure which represents a TCP stream between a local socket and a
|
||||||
/// remote socket.
|
/// remote socket.
|
||||||
|
@ -139,6 +140,50 @@ impl TcpStream {
|
||||||
pub fn set_keepalive(&self, seconds: Option<u32>) -> io::Result<()> {
|
pub fn set_keepalive(&self, seconds: Option<u32>) -> io::Result<()> {
|
||||||
self.0.set_keepalive(seconds)
|
self.0.set_keepalive(seconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the read timeout to the timeout specified.
|
||||||
|
///
|
||||||
|
/// If the value specified is `None`, then `read` calls will block
|
||||||
|
/// indefinitely. It is an error to pass the zero `Duration` to this
|
||||||
|
/// method.
|
||||||
|
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
|
||||||
|
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||||
|
self.0.set_read_timeout(dur)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the write timeout to the timeout specified.
|
||||||
|
///
|
||||||
|
/// If the value specified is `None`, then `write` calls will block
|
||||||
|
/// indefinitely. It is an error to pass the zero `Duration` to this
|
||||||
|
/// method.
|
||||||
|
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
|
||||||
|
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||||
|
self.0.set_write_timeout(dur)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the read timeout of this socket.
|
||||||
|
///
|
||||||
|
/// If the timeout is `None`, then `read` calls will block indefinitely.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// Some platforms do not provide access to the current timeout.
|
||||||
|
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
|
||||||
|
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||||
|
self.0.read_timeout()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the write timeout of this socket.
|
||||||
|
///
|
||||||
|
/// If the timeout is `None`, then `write` calls will block indefinitely.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// Some platforms do not provide access to the current timeout.
|
||||||
|
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
|
||||||
|
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||||
|
self.0.write_timeout()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
@ -262,6 +307,7 @@ mod tests {
|
||||||
use net::test::{next_test_ip4, next_test_ip6};
|
use net::test::{next_test_ip4, next_test_ip6};
|
||||||
use sync::mpsc::channel;
|
use sync::mpsc::channel;
|
||||||
use sys_common::AsInner;
|
use sys_common::AsInner;
|
||||||
|
use time::Duration;
|
||||||
use thread;
|
use thread;
|
||||||
|
|
||||||
fn each_ip(f: &mut FnMut(SocketAddr)) {
|
fn each_ip(f: &mut FnMut(SocketAddr)) {
|
||||||
|
@ -855,4 +901,69 @@ mod tests {
|
||||||
stream_inner);
|
stream_inner);
|
||||||
assert_eq!(format!("{:?}", stream), compare);
|
assert_eq!(format!("{:?}", stream), compare);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn timeouts() {
|
||||||
|
let addr = next_test_ip4();
|
||||||
|
let listener = t!(TcpListener::bind(&addr));
|
||||||
|
|
||||||
|
let stream = t!(TcpStream::connect(&("localhost", addr.port())));
|
||||||
|
let dur = Duration::new(15410, 0);
|
||||||
|
|
||||||
|
assert_eq!(None, t!(stream.read_timeout()));
|
||||||
|
|
||||||
|
t!(stream.set_read_timeout(Some(dur)));
|
||||||
|
assert_eq!(Some(dur), t!(stream.read_timeout()));
|
||||||
|
|
||||||
|
assert_eq!(None, t!(stream.write_timeout()));
|
||||||
|
|
||||||
|
t!(stream.set_write_timeout(Some(dur)));
|
||||||
|
assert_eq!(Some(dur), t!(stream.write_timeout()));
|
||||||
|
|
||||||
|
t!(stream.set_read_timeout(None));
|
||||||
|
assert_eq!(None, t!(stream.read_timeout()));
|
||||||
|
|
||||||
|
t!(stream.set_write_timeout(None));
|
||||||
|
assert_eq!(None, t!(stream.write_timeout()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_timeout() {
|
||||||
|
let addr = next_test_ip4();
|
||||||
|
let listener = t!(TcpListener::bind(&addr));
|
||||||
|
|
||||||
|
let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
|
||||||
|
t!(stream.set_read_timeout(Some(Duration::from_millis(10))));
|
||||||
|
|
||||||
|
let mut buf = [0; 10];
|
||||||
|
let wait = Duration::span(|| {
|
||||||
|
let kind = stream.read(&mut buf).err().expect("expected error").kind();
|
||||||
|
assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut);
|
||||||
|
});
|
||||||
|
assert!(wait > Duration::from_millis(5));
|
||||||
|
assert!(wait < Duration::from_millis(15));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_with_timeout() {
|
||||||
|
let addr = next_test_ip4();
|
||||||
|
let listener = t!(TcpListener::bind(&addr));
|
||||||
|
|
||||||
|
let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
|
||||||
|
t!(stream.set_read_timeout(Some(Duration::from_millis(10))));
|
||||||
|
|
||||||
|
let mut other_end = t!(listener.accept()).0;
|
||||||
|
t!(other_end.write_all(b"hello world"));
|
||||||
|
|
||||||
|
let mut buf = [0; 11];
|
||||||
|
t!(stream.read(&mut buf));
|
||||||
|
assert_eq!(b"hello world", &buf[..]);
|
||||||
|
|
||||||
|
let wait = Duration::span(|| {
|
||||||
|
let kind = stream.read(&mut buf).err().expect("expected error").kind();
|
||||||
|
assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut);
|
||||||
|
});
|
||||||
|
assert!(wait > Duration::from_millis(5));
|
||||||
|
assert!(wait < Duration::from_millis(15));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ use io::{self, Error, ErrorKind};
|
||||||
use net::{ToSocketAddrs, SocketAddr, IpAddr};
|
use net::{ToSocketAddrs, SocketAddr, IpAddr};
|
||||||
use sys_common::net as net_imp;
|
use sys_common::net as net_imp;
|
||||||
use sys_common::{AsInner, FromInner};
|
use sys_common::{AsInner, FromInner};
|
||||||
|
use time::Duration;
|
||||||
|
|
||||||
/// A User Datagram Protocol socket.
|
/// A User Datagram Protocol socket.
|
||||||
///
|
///
|
||||||
|
@ -127,6 +128,42 @@ impl UdpSocket {
|
||||||
pub fn set_time_to_live(&self, ttl: i32) -> io::Result<()> {
|
pub fn set_time_to_live(&self, ttl: i32) -> io::Result<()> {
|
||||||
self.0.time_to_live(ttl)
|
self.0.time_to_live(ttl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the read timeout to the timeout specified.
|
||||||
|
///
|
||||||
|
/// If the value specified is `None`, then `read` calls will block
|
||||||
|
/// indefinitely. It is an error to pass the zero `Duration` to this
|
||||||
|
/// method.
|
||||||
|
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
|
||||||
|
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||||
|
self.0.set_read_timeout(dur)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the write timeout to the timeout specified.
|
||||||
|
///
|
||||||
|
/// If the value specified is `None`, then `write` calls will block
|
||||||
|
/// indefinitely. It is an error to pass the zero `Duration` to this
|
||||||
|
/// method.
|
||||||
|
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
|
||||||
|
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||||
|
self.0.set_write_timeout(dur)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the read timeout of this socket.
|
||||||
|
///
|
||||||
|
/// If the timeout is `None`, then `read` calls will block indefinitely.
|
||||||
|
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
|
||||||
|
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||||
|
self.0.read_timeout()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the write timeout of this socket.
|
||||||
|
///
|
||||||
|
/// If the timeout is `None`, then `write` calls will block indefinitely.
|
||||||
|
#[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
|
||||||
|
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||||
|
self.0.write_timeout()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsInner<net_imp::UdpSocket> for UdpSocket {
|
impl AsInner<net_imp::UdpSocket> for UdpSocket {
|
||||||
|
@ -152,6 +189,7 @@ mod tests {
|
||||||
use net::test::{next_test_ip4, next_test_ip6};
|
use net::test::{next_test_ip4, next_test_ip6};
|
||||||
use sync::mpsc::channel;
|
use sync::mpsc::channel;
|
||||||
use sys_common::AsInner;
|
use sys_common::AsInner;
|
||||||
|
use time::Duration;
|
||||||
use thread;
|
use thread;
|
||||||
|
|
||||||
fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) {
|
fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) {
|
||||||
|
@ -321,4 +359,65 @@ mod tests {
|
||||||
socket_addr, name, udpsock_inner);
|
socket_addr, name, udpsock_inner);
|
||||||
assert_eq!(format!("{:?}", udpsock), compare);
|
assert_eq!(format!("{:?}", udpsock), compare);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn timeouts() {
|
||||||
|
let addr = next_test_ip4();
|
||||||
|
|
||||||
|
let stream = t!(UdpSocket::bind(&addr));
|
||||||
|
let dur = Duration::new(15410, 0);
|
||||||
|
|
||||||
|
assert_eq!(None, t!(stream.read_timeout()));
|
||||||
|
|
||||||
|
t!(stream.set_read_timeout(Some(dur)));
|
||||||
|
assert_eq!(Some(dur), t!(stream.read_timeout()));
|
||||||
|
|
||||||
|
assert_eq!(None, t!(stream.write_timeout()));
|
||||||
|
|
||||||
|
t!(stream.set_write_timeout(Some(dur)));
|
||||||
|
assert_eq!(Some(dur), t!(stream.write_timeout()));
|
||||||
|
|
||||||
|
t!(stream.set_read_timeout(None));
|
||||||
|
assert_eq!(None, t!(stream.read_timeout()));
|
||||||
|
|
||||||
|
t!(stream.set_write_timeout(None));
|
||||||
|
assert_eq!(None, t!(stream.write_timeout()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_timeout() {
|
||||||
|
let addr = next_test_ip4();
|
||||||
|
|
||||||
|
let mut stream = t!(UdpSocket::bind(&addr));
|
||||||
|
t!(stream.set_read_timeout(Some(Duration::from_millis(10))));
|
||||||
|
|
||||||
|
let mut buf = [0; 10];
|
||||||
|
let wait = Duration::span(|| {
|
||||||
|
let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
|
||||||
|
assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut);
|
||||||
|
});
|
||||||
|
assert!(wait > Duration::from_millis(5));
|
||||||
|
assert!(wait < Duration::from_millis(15));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_with_timeout() {
|
||||||
|
let addr = next_test_ip4();
|
||||||
|
|
||||||
|
let mut stream = t!(UdpSocket::bind(&addr));
|
||||||
|
t!(stream.set_read_timeout(Some(Duration::from_millis(10))));
|
||||||
|
|
||||||
|
t!(stream.send_to(b"hello world", &addr));
|
||||||
|
|
||||||
|
let mut buf = [0; 11];
|
||||||
|
t!(stream.recv_from(&mut buf));
|
||||||
|
assert_eq!(b"hello world", &buf[..]);
|
||||||
|
|
||||||
|
let wait = Duration::span(|| {
|
||||||
|
let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
|
||||||
|
assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut);
|
||||||
|
});
|
||||||
|
assert!(wait > Duration::from_millis(5));
|
||||||
|
assert!(wait < Duration::from_millis(15));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,13 @@ use str::from_utf8;
|
||||||
use sys::c;
|
use sys::c;
|
||||||
use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
|
use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
|
||||||
use sys_common::{AsInner, FromInner, IntoInner};
|
use sys_common::{AsInner, FromInner, IntoInner};
|
||||||
|
use time::Duration;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// sockaddr and misc bindings
|
// sockaddr and misc bindings
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
|
pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
|
||||||
payload: T) -> io::Result<()> {
|
payload: T) -> io::Result<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let payload = &payload as *const T as *const c_void;
|
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
|
||||||
fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
|
|
||||||
val: c_int) -> io::Result<T> {
|
val: c_int) -> io::Result<T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut slot: T = mem::zeroed();
|
let mut slot: T = mem::zeroed();
|
||||||
let mut len = mem::size_of::<T>() as socklen_t;
|
let mut len = mem::size_of::<T>() as socklen_t;
|
||||||
let ret = try!(cvt(c::getsockopt(*sock.as_inner(), opt, val,
|
try!(cvt(c::getsockopt(*sock.as_inner(), opt, val,
|
||||||
&mut slot as *mut _ as *mut _,
|
&mut slot as *mut _ as *mut _,
|
||||||
&mut len)));
|
&mut len)));
|
||||||
assert_eq!(ret as usize, mem::size_of::<T>());
|
assert_eq!(len as usize, mem::size_of::<T>());
|
||||||
Ok(slot)
|
Ok(slot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,6 +220,22 @@ impl TcpStream {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||||
|
self.inner.set_timeout(dur, libc::SO_RCVTIMEO)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||||
|
self.inner.set_timeout(dur, libc::SO_SNDTIMEO)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||||
|
self.inner.timeout(libc::SO_RCVTIMEO)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||||
|
self.inner.timeout(libc::SO_SNDTIMEO)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
self.inner.read(buf)
|
self.inner.read(buf)
|
||||||
}
|
}
|
||||||
|
@ -471,6 +487,22 @@ impl UdpSocket {
|
||||||
pub fn duplicate(&self) -> io::Result<UdpSocket> {
|
pub fn duplicate(&self) -> io::Result<UdpSocket> {
|
||||||
self.inner.duplicate().map(|s| UdpSocket { inner: s })
|
self.inner.duplicate().map(|s| UdpSocket { inner: s })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||||
|
self.inner.set_timeout(dur, libc::SO_RCVTIMEO)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||||
|
self.inner.set_timeout(dur, libc::SO_SNDTIMEO)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||||
|
self.inner.timeout(libc::SO_RCVTIMEO)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||||
|
self.inner.timeout(libc::SO_SNDTIMEO)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromInner<Socket> for UdpSocket {
|
impl FromInner<Socket> for UdpSocket {
|
||||||
|
|
|
@ -18,6 +18,8 @@ use sys::c;
|
||||||
use net::SocketAddr;
|
use net::SocketAddr;
|
||||||
use sys::fd::FileDesc;
|
use sys::fd::FileDesc;
|
||||||
use sys_common::{AsInner, FromInner};
|
use sys_common::{AsInner, FromInner};
|
||||||
|
use sys_common::net::{getsockopt, setsockopt};
|
||||||
|
use time::Duration;
|
||||||
|
|
||||||
pub use sys::{cvt, cvt_r};
|
pub use sys::{cvt, cvt_r};
|
||||||
|
|
||||||
|
@ -73,6 +75,49 @@ impl Socket {
|
||||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
self.0.read(buf)
|
self.0.read(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
|
||||||
|
let timeout = match dur {
|
||||||
|
Some(dur) => {
|
||||||
|
if dur.secs() == 0 && dur.extra_nanos() == 0 {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||||
|
"cannot set a 0 duration timeout"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let secs = if dur.secs() > libc::time_t::max_value() as u64 {
|
||||||
|
libc::time_t::max_value()
|
||||||
|
} else {
|
||||||
|
dur.secs() as libc::time_t
|
||||||
|
};
|
||||||
|
let mut timeout = libc::timeval {
|
||||||
|
tv_sec: secs,
|
||||||
|
tv_usec: (dur.extra_nanos() / 1000) as libc::suseconds_t,
|
||||||
|
};
|
||||||
|
if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
|
||||||
|
timeout.tv_usec = 1;
|
||||||
|
}
|
||||||
|
timeout
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
libc::timeval {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_usec: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
setsockopt(self, libc::SOL_SOCKET, kind, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> {
|
||||||
|
let raw: libc::timeval = try!(getsockopt(self, libc::SOL_SOCKET, kind));
|
||||||
|
if raw.tv_sec == 0 && raw.tv_usec == 0 {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
let sec = raw.tv_sec as u64;
|
||||||
|
let nsec = (raw.tv_usec as u32) * 1000;
|
||||||
|
Ok(Some(Duration::new(sec, nsec)))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsInner<c_int> for Socket {
|
impl AsInner<c_int> for Socket {
|
||||||
|
|
|
@ -60,6 +60,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
|
||||||
libc::WSAEINVAL => ErrorKind::InvalidInput,
|
libc::WSAEINVAL => ErrorKind::InvalidInput,
|
||||||
libc::WSAENOTCONN => ErrorKind::NotConnected,
|
libc::WSAENOTCONN => ErrorKind::NotConnected,
|
||||||
libc::WSAEWOULDBLOCK => ErrorKind::WouldBlock,
|
libc::WSAEWOULDBLOCK => ErrorKind::WouldBlock,
|
||||||
|
libc::WSAETIMEDOUT => ErrorKind::TimedOut,
|
||||||
|
|
||||||
_ => ErrorKind::Other,
|
_ => ErrorKind::Other,
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,11 @@ use num::One;
|
||||||
use ops::Neg;
|
use ops::Neg;
|
||||||
use rt;
|
use rt;
|
||||||
use sync::Once;
|
use sync::Once;
|
||||||
|
use sys;
|
||||||
use sys::c;
|
use sys::c;
|
||||||
use sys_common::{AsInner, FromInner};
|
use sys_common::{AsInner, FromInner};
|
||||||
|
use sys_common::net::{setsockopt, getsockopt};
|
||||||
|
use time::Duration;
|
||||||
|
|
||||||
pub type wrlen_t = i32;
|
pub type wrlen_t = i32;
|
||||||
|
|
||||||
|
@ -127,6 +130,32 @@ impl Socket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
|
||||||
|
let timeout = match dur {
|
||||||
|
Some(dur) => {
|
||||||
|
let timeout = sys::dur2timeout(dur);
|
||||||
|
if timeout == 0 {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||||
|
"cannot set a 0 duration timeout"));
|
||||||
|
}
|
||||||
|
timeout
|
||||||
|
}
|
||||||
|
None => 0
|
||||||
|
};
|
||||||
|
setsockopt(self, libc::SOL_SOCKET, kind, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> {
|
||||||
|
let raw: libc::DWORD = try!(getsockopt(self, libc::SOL_SOCKET, kind));
|
||||||
|
if raw == 0 {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
let secs = raw / 1000;
|
||||||
|
let nsec = (raw % 1000) * 1000000;
|
||||||
|
Ok(Some(Duration::new(secs as u64, nsec as u32)))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Socket {
|
impl Drop for Socket {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue