Fix windows
Also back out keepalive support for TCP since the API is perhaps not actually what we want. You can't read the interval on Windows, and we should probably separate the functionality of turning keepalive on and overriding the interval.
This commit is contained in:
parent
5d6ba17f03
commit
728d9115e8
5 changed files with 55 additions and 174 deletions
|
@ -203,34 +203,6 @@ impl TcpStream {
|
||||||
self.0.nodelay()
|
self.0.nodelay()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether keepalive messages are enabled to be sent on this socket.
|
|
||||||
///
|
|
||||||
/// On Unix, this option will set the `SO_KEEPALIVE` as well as the
|
|
||||||
/// `TCP_KEEPALIVE` or `TCP_KEEPIDLE` option (depending on your platform).
|
|
||||||
/// On Windows, this will set the `SIO_KEEPALIVE_VALS` option.
|
|
||||||
///
|
|
||||||
/// If `None` is specified then keepalive messages are disabled, otherwise
|
|
||||||
/// the duration specified will be the time to remain idle before sending a
|
|
||||||
/// TCP keepalive probe.
|
|
||||||
///
|
|
||||||
/// Some platforms specify this value in seconds, so sub-second
|
|
||||||
/// specifications may be omitted.
|
|
||||||
#[stable(feature = "net2_mutators", since = "1.9.0")]
|
|
||||||
pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> {
|
|
||||||
self.0.set_keepalive(keepalive)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether keepalive messages are enabled on this socket, and if so
|
|
||||||
/// the duration of time between them.
|
|
||||||
///
|
|
||||||
/// For more information about this option, see [`set_keepalive`][link].
|
|
||||||
///
|
|
||||||
/// [link]: #tymethod.set_keepalive
|
|
||||||
#[stable(feature = "net2_mutators", since = "1.9.0")]
|
|
||||||
pub fn keepalive(&self) -> io::Result<Option<Duration>> {
|
|
||||||
self.0.keepalive()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the value for the `IP_TTL` option on this socket.
|
/// Sets the value for the `IP_TTL` option on this socket.
|
||||||
///
|
///
|
||||||
/// This value sets the time-to-live field that is used in every packet sent
|
/// This value sets the time-to-live field that is used in every packet sent
|
||||||
|
@ -1156,21 +1128,6 @@ mod tests {
|
||||||
assert_eq!(false, t!(stream.nodelay()));
|
assert_eq!(false, t!(stream.nodelay()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn keepalive() {
|
|
||||||
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.keepalive()));
|
|
||||||
t!(stream.set_keepalive(Some(dur)));
|
|
||||||
assert_eq!(Some(dur), t!(stream.keepalive()));
|
|
||||||
t!(stream.set_keepalive(None));
|
|
||||||
assert_eq!(None, t!(stream.keepalive()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ttl() {
|
fn ttl() {
|
||||||
let ttl = 100;
|
let ttl = 100;
|
||||||
|
|
|
@ -14,7 +14,7 @@ use cmp;
|
||||||
use ffi::{CStr, CString};
|
use ffi::{CStr, CString};
|
||||||
use fmt;
|
use fmt;
|
||||||
use io::{self, Error, ErrorKind};
|
use io::{self, Error, ErrorKind};
|
||||||
use libc::{c_int, c_char, c_void};
|
use libc::{c_int, c_char, c_void, c_uint};
|
||||||
use mem;
|
use mem;
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
use net::{SocketAddr, Shutdown, IpAddr, Ipv4Addr, Ipv6Addr};
|
use net::{SocketAddr, Shutdown, IpAddr, Ipv4Addr, Ipv6Addr};
|
||||||
|
@ -84,13 +84,13 @@ fn sockaddr_to_addr(storage: &c::sockaddr_storage,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
fn to_ipv6mr_interface(value: u32) -> c::c_int {
|
fn to_ipv6mr_interface(value: u32) -> c_int {
|
||||||
value as c::c_int
|
value as c_int
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
fn to_ipv6mr_interface(value: u32) -> c::c_uint {
|
fn to_ipv6mr_interface(value: u32) -> c_uint {
|
||||||
value as c::c_uint
|
value as c_uint
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -239,20 +239,11 @@ impl TcpStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
|
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
|
||||||
setsockopt(&self.inner, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c_int)
|
self.inner.set_nodelay(nodelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nodelay(&self) -> io::Result<bool> {
|
pub fn nodelay(&self) -> io::Result<bool> {
|
||||||
let raw: c_int = try!(getsockopt(&self.inner, c::IPPROTO_TCP, c::TCP_NODELAY));
|
self.inner.nodelay()
|
||||||
Ok(raw != 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> {
|
|
||||||
self.inner.set_keepalive(keepalive)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn keepalive(&self) -> io::Result<Option<Duration>> {
|
|
||||||
self.inner.keepalive()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
||||||
|
|
|
@ -35,16 +35,6 @@ use libc::SOCK_CLOEXEC;
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
const SOCK_CLOEXEC: c_int = 0;
|
const SOCK_CLOEXEC: c_int = 0;
|
||||||
|
|
||||||
#[cfg(any(target_os = "openbsd", taret_os = "freebsd"))]
|
|
||||||
use libc::SO_KEEPALIVE as TCP_KEEPALIVE;
|
|
||||||
#[cfg(any(target_os = "macos", taret_os = "ios"))]
|
|
||||||
use libc::TCP_KEEPALIVE;
|
|
||||||
#[cfg(not(any(target_os = "openbsd",
|
|
||||||
target_os = "freebsd",
|
|
||||||
target_os = "macos",
|
|
||||||
target_os = "ios")))]
|
|
||||||
use libc::TCP_KEEPIDLE as TCP_KEEPALIVE;
|
|
||||||
|
|
||||||
pub struct Socket(FileDesc);
|
pub struct Socket(FileDesc);
|
||||||
|
|
||||||
pub fn init() {}
|
pub fn init() {}
|
||||||
|
@ -179,37 +169,13 @@ impl Socket {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> {
|
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
|
||||||
try!(setsockopt(self,
|
setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int)
|
||||||
libc::SOL_SOCKET,
|
|
||||||
libc::SO_KEEPALIVE,
|
|
||||||
keepalive.is_some() as libc::c_int));
|
|
||||||
if let Some(dur) = keepalive {
|
|
||||||
let mut raw = dur.as_secs();
|
|
||||||
if dur.subsec_nanos() > 0 {
|
|
||||||
raw = raw.saturating_add(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let raw = if raw > libc::c_int::max_value() as u64 {
|
|
||||||
libc::c_int::max_value()
|
|
||||||
} else {
|
|
||||||
raw as libc::c_int
|
|
||||||
};
|
|
||||||
|
|
||||||
try!(setsockopt(self, libc::IPPROTO_TCP, TCP_KEEPALIVE, raw));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keepalive(&self) -> io::Result<Option<Duration>> {
|
pub fn nodelay(&self) -> io::Result<bool> {
|
||||||
let raw: c_int = try!(getsockopt(self, libc::SOL_SOCKET, libc::SO_KEEPALIVE));
|
let raw: c_int = try!(getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY));
|
||||||
if raw == 0 {
|
Ok(raw != 0)
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
let raw: c_int = try!(getsockopt(self, libc::IPPROTO_TCP, TCP_KEEPALIVE));
|
|
||||||
Ok(Some(Duration::from_secs(raw as u64)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#![allow(bad_style)]
|
#![allow(bad_style)]
|
||||||
#![cfg_attr(test, allow(dead_code))]
|
#![cfg_attr(test, allow(dead_code))]
|
||||||
|
|
||||||
use os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort};
|
use os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort,};
|
||||||
use os::raw::{c_char, c_ulonglong};
|
use os::raw::{c_char, c_ulonglong};
|
||||||
use libc::{wchar_t, size_t, c_void};
|
use libc::{wchar_t, size_t, c_void};
|
||||||
use ptr;
|
use ptr;
|
||||||
|
@ -78,13 +78,6 @@ pub type SOCKET = ::os::windows::raw::SOCKET;
|
||||||
pub type socklen_t = c_int;
|
pub type socklen_t = c_int;
|
||||||
pub type ADDRESS_FAMILY = USHORT;
|
pub type ADDRESS_FAMILY = USHORT;
|
||||||
|
|
||||||
pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE =
|
|
||||||
Option<unsafe extern "system" fn(dwError: DWORD,
|
|
||||||
cbTransferred: DWORD,
|
|
||||||
lpOverlapped: LPWSAOVERLAPPED,
|
|
||||||
dwFlags: DWORD)>;
|
|
||||||
pub type LPWSAOVERLAPPED = *mut OVERLAPPED;
|
|
||||||
|
|
||||||
pub const TRUE: BOOL = 1;
|
pub const TRUE: BOOL = 1;
|
||||||
pub const FALSE: BOOL = 0;
|
pub const FALSE: BOOL = 0;
|
||||||
|
|
||||||
|
@ -121,7 +114,6 @@ pub const FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000;
|
||||||
pub const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000;
|
pub const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000;
|
||||||
pub const SECURITY_SQOS_PRESENT: DWORD = 0x00100000;
|
pub const SECURITY_SQOS_PRESENT: DWORD = 0x00100000;
|
||||||
|
|
||||||
pub const SIO_KEEPALIVE_VALS: DWORD = 0x98000004;
|
|
||||||
pub const FIONBIO: c_ulong = 0x8004667e;
|
pub const FIONBIO: c_ulong = 0x8004667e;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -233,6 +225,33 @@ pub const SOL_SOCKET: c_int = 0xffff;
|
||||||
pub const SO_RCVTIMEO: c_int = 0x1006;
|
pub const SO_RCVTIMEO: c_int = 0x1006;
|
||||||
pub const SO_SNDTIMEO: c_int = 0x1005;
|
pub const SO_SNDTIMEO: c_int = 0x1005;
|
||||||
pub const SO_REUSEADDR: c_int = 0x0004;
|
pub const SO_REUSEADDR: c_int = 0x0004;
|
||||||
|
pub const IPPROTO_IP: c_int = 0;
|
||||||
|
pub const IPPROTO_TCP: c_int = 6;
|
||||||
|
pub const IPPROTO_IPV6: c_int = 41;
|
||||||
|
pub const TCP_NODELAY: c_int = 0x0001;
|
||||||
|
pub const IP_TTL: c_int = 4;
|
||||||
|
pub const IPV6_V6ONLY: c_int = 27;
|
||||||
|
pub const SO_ERROR: c_int = 0x1007;
|
||||||
|
pub const SO_BROADCAST: c_int = 0x0020;
|
||||||
|
pub const IP_MULTICAST_LOOP: c_int = 11;
|
||||||
|
pub const IPV6_MULTICAST_LOOP: c_int = 11;
|
||||||
|
pub const IP_MULTICAST_TTL: c_int = 10;
|
||||||
|
pub const IP_ADD_MEMBERSHIP: c_int = 12;
|
||||||
|
pub const IP_DROP_MEMBERSHIP: c_int = 13;
|
||||||
|
pub const IPV6_ADD_MEMBERSHIP: c_int = 12;
|
||||||
|
pub const IPV6_DROP_MEMBERSHIP: c_int = 13;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ip_mreq {
|
||||||
|
pub imr_multiaddr: in_addr,
|
||||||
|
pub imr_interface: in_addr,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ipv6_mreq {
|
||||||
|
pub ipv6mr_multiaddr: in6_addr,
|
||||||
|
pub ipv6mr_interface: c_uint,
|
||||||
|
}
|
||||||
|
|
||||||
pub const VOLUME_NAME_DOS: DWORD = 0x0;
|
pub const VOLUME_NAME_DOS: DWORD = 0x0;
|
||||||
pub const MOVEFILE_REPLACE_EXISTING: DWORD = 1;
|
pub const MOVEFILE_REPLACE_EXISTING: DWORD = 1;
|
||||||
|
@ -785,13 +804,6 @@ pub struct in6_addr {
|
||||||
pub s6_addr: [u8; 16],
|
pub s6_addr: [u8; 16],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct tcp_keepalive {
|
|
||||||
pub onoff: c_ulong,
|
|
||||||
pub keepalivetime: c_ulong,
|
|
||||||
pub keepaliveinterval: c_ulong,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
|
#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
|
||||||
pub enum UNWIND_HISTORY_TABLE {}
|
pub enum UNWIND_HISTORY_TABLE {}
|
||||||
|
|
||||||
|
@ -850,17 +862,7 @@ extern "system" {
|
||||||
lpProtocolInfo: LPWSAPROTOCOL_INFO,
|
lpProtocolInfo: LPWSAPROTOCOL_INFO,
|
||||||
g: GROUP,
|
g: GROUP,
|
||||||
dwFlags: DWORD) -> SOCKET;
|
dwFlags: DWORD) -> SOCKET;
|
||||||
pub fn WSAIoctl(s: SOCKET,
|
pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int;
|
||||||
dwIoControlCode: DWORD,
|
|
||||||
lpvInBuffer: LPVOID,
|
|
||||||
cbInBuffer: DWORD,
|
|
||||||
lpvOutBuffer: LPVOID,
|
|
||||||
cbOutBuffer: DWORD,
|
|
||||||
lpcbBytesReturned: LPDWORD,
|
|
||||||
lpOverlapped: LPWSAOVERLAPPED,
|
|
||||||
lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE)
|
|
||||||
-> c_int;
|
|
||||||
pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut u_long) -> c_int;
|
|
||||||
pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
|
pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
|
||||||
pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
|
pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
|
||||||
pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOLEAN;
|
pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOLEAN;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use cmp;
|
use cmp;
|
||||||
use io;
|
use io;
|
||||||
use libc::{c_int, c_void};
|
use libc::{c_int, c_void, c_ulong};
|
||||||
use mem;
|
use mem;
|
||||||
use net::{SocketAddr, Shutdown};
|
use net::{SocketAddr, Shutdown};
|
||||||
use num::One;
|
use num::One;
|
||||||
|
@ -186,58 +186,23 @@ impl Socket {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> {
|
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||||
let ms = keepalive.map(sys::dur2timeout).unwrap_or(c::INFINITE);
|
let mut nonblocking = nonblocking as c_ulong;
|
||||||
let ka = c::tcp_keepalive {
|
let r = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) };
|
||||||
onoff: keepalive.is_some() as c::c_ulong,
|
if r == 0 {
|
||||||
keepalivetime: ms as c::c_ulong,
|
Ok(())
|
||||||
keepaliveinterval: ms as c::c_ulong,
|
|
||||||
};
|
|
||||||
sys::cvt(unsafe {
|
|
||||||
c::WSAIoctl(self.0,
|
|
||||||
c::SIO_KEEPALIVE_VALS,
|
|
||||||
&ka as *const _ as *mut _,
|
|
||||||
mem::size_of_val(&ka) as c::DWORD,
|
|
||||||
0 as *mut _,
|
|
||||||
0,
|
|
||||||
0 as *mut _,
|
|
||||||
0 as *mut _,
|
|
||||||
None)
|
|
||||||
}).map(|_| ())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn keepalive(&self) -> io::Result<Option<Duration>> {
|
|
||||||
let mut ka = c::tcp_keepalive {
|
|
||||||
onoff: 0,
|
|
||||||
keepalivetime: 0,
|
|
||||||
keepaliveinterval: 0,
|
|
||||||
};
|
|
||||||
try!(sys::cvt(unsafe {
|
|
||||||
WSAIoctl(self.0,
|
|
||||||
c::SIO_KEEPALIVE_VALS,
|
|
||||||
0 as *mut _,
|
|
||||||
0,
|
|
||||||
&mut ka as *mut _ as *mut _,
|
|
||||||
mem::size_of_val(&ka) as c::DWORD,
|
|
||||||
0 as *mut _,
|
|
||||||
0 as *mut _,
|
|
||||||
None)
|
|
||||||
}));
|
|
||||||
|
|
||||||
if ka.onoff == 0 {
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
} else {
|
||||||
let secs = ka.keepaliveinterval / 1000;
|
Err(io::Error::last_os_error())
|
||||||
let nsec = (ka.keepaliveinterval % 1000) * 1000000;
|
|
||||||
Ok(Some(Duration::new(secs as u64, nsec as u32)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
|
||||||
let mut nonblocking = nonblocking as c::c_ulong;
|
net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BYTE)
|
||||||
sys::cvt(unsafe {
|
}
|
||||||
c::ioctlsocket(self.0, c::FIONBIO as c::c_int, &mut nonblocking)
|
|
||||||
}).map(|_| ())
|
pub fn nodelay(&self) -> io::Result<bool> {
|
||||||
|
let raw: c::BYTE = try!(net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY));
|
||||||
|
Ok(raw != 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue