From 728d9115e894bd3c8fc3ae03230ea46f85467c04 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 27 Feb 2016 21:05:32 -0800 Subject: [PATCH] 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. --- src/libstd/net/tcp.rs | 43 ------------------------ src/libstd/sys/common/net.rs | 23 ++++--------- src/libstd/sys/unix/net.rs | 44 +++--------------------- src/libstd/sys/windows/c.rs | 56 ++++++++++++++++--------------- src/libstd/sys/windows/net.rs | 63 ++++++++--------------------------- 5 files changed, 55 insertions(+), 174 deletions(-) diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index b8530c98398..0073b8f119a 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -203,34 +203,6 @@ impl TcpStream { 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) -> 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> { - self.0.keepalive() - } - /// 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 @@ -1156,21 +1128,6 @@ mod tests { 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] fn ttl() { let ttl = 100; diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 31d3be45372..c8738fd1ba5 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -14,7 +14,7 @@ use cmp; use ffi::{CStr, CString}; use fmt; 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; #[allow(deprecated)] use net::{SocketAddr, Shutdown, IpAddr, Ipv4Addr, Ipv6Addr}; @@ -84,13 +84,13 @@ fn sockaddr_to_addr(storage: &c::sockaddr_storage, } #[cfg(target_os = "android")] -fn to_ipv6mr_interface(value: u32) -> c::c_int { - value as c::c_int +fn to_ipv6mr_interface(value: u32) -> c_int { + value as c_int } #[cfg(not(target_os = "android"))] -fn to_ipv6mr_interface(value: u32) -> c::c_uint { - value as c::c_uint +fn to_ipv6mr_interface(value: u32) -> c_uint { + value as c_uint } //////////////////////////////////////////////////////////////////////////////// @@ -239,20 +239,11 @@ impl TcpStream { } 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 { - let raw: c_int = try!(getsockopt(&self.inner, c::IPPROTO_TCP, c::TCP_NODELAY)); - Ok(raw != 0) - } - - pub fn set_keepalive(&self, keepalive: Option) -> io::Result<()> { - self.inner.set_keepalive(keepalive) - } - - pub fn keepalive(&self) -> io::Result> { - self.inner.keepalive() + self.inner.nodelay() } pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 7a2ac7257af..8785da51986 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -35,16 +35,6 @@ use libc::SOCK_CLOEXEC; #[cfg(not(target_os = "linux"))] 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 fn init() {} @@ -179,37 +169,13 @@ impl Socket { Ok(()) } - pub fn set_keepalive(&self, keepalive: Option) -> io::Result<()> { - try!(setsockopt(self, - 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 set_nodelay(&self, nodelay: bool) -> io::Result<()> { + setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) } - pub fn keepalive(&self) -> io::Result> { - let raw: c_int = try!(getsockopt(self, libc::SOL_SOCKET, libc::SO_KEEPALIVE)); - if 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 nodelay(&self) -> io::Result { + let raw: c_int = try!(getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)); + Ok(raw != 0) } pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index cc420763fd7..472ffdf9e1d 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -13,7 +13,7 @@ #![allow(bad_style)] #![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 libc::{wchar_t, size_t, c_void}; use ptr; @@ -78,13 +78,6 @@ pub type SOCKET = ::os::windows::raw::SOCKET; pub type socklen_t = c_int; pub type ADDRESS_FAMILY = USHORT; -pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = - Option; -pub type LPWSAOVERLAPPED = *mut OVERLAPPED; - pub const TRUE: BOOL = 1; 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 SECURITY_SQOS_PRESENT: DWORD = 0x00100000; -pub const SIO_KEEPALIVE_VALS: DWORD = 0x98000004; pub const FIONBIO: c_ulong = 0x8004667e; #[repr(C)] @@ -233,6 +225,33 @@ pub const SOL_SOCKET: c_int = 0xffff; pub const SO_RCVTIMEO: c_int = 0x1006; pub const SO_SNDTIMEO: c_int = 0x1005; 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 MOVEFILE_REPLACE_EXISTING: DWORD = 1; @@ -785,13 +804,6 @@ pub struct in6_addr { 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"))] pub enum UNWIND_HISTORY_TABLE {} @@ -850,17 +862,7 @@ extern "system" { lpProtocolInfo: LPWSAPROTOCOL_INFO, g: GROUP, dwFlags: DWORD) -> SOCKET; - pub fn WSAIoctl(s: SOCKET, - 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 ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int; pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION); pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION); pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOLEAN; diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index be13657aaf4..dfa44a651e6 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -10,7 +10,7 @@ use cmp; use io; -use libc::{c_int, c_void}; +use libc::{c_int, c_void, c_ulong}; use mem; use net::{SocketAddr, Shutdown}; use num::One; @@ -186,58 +186,23 @@ impl Socket { Ok(()) } - pub fn set_keepalive(&self, keepalive: Option) -> io::Result<()> { - let ms = keepalive.map(sys::dur2timeout).unwrap_or(c::INFINITE); - let ka = c::tcp_keepalive { - onoff: keepalive.is_some() as c::c_ulong, - keepalivetime: ms as c::c_ulong, - 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> { - 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) + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + let mut nonblocking = nonblocking as c_ulong; + let r = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) }; + if r == 0 { + Ok(()) } else { - let secs = ka.keepaliveinterval / 1000; - let nsec = (ka.keepaliveinterval % 1000) * 1000000; - Ok(Some(Duration::new(secs as u64, nsec as u32))) + Err(io::Error::last_os_error()) } } - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut nonblocking = nonblocking as c::c_ulong; - sys::cvt(unsafe { - c::ioctlsocket(self.0, c::FIONBIO as c::c_int, &mut nonblocking) - }).map(|_| ()) + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BYTE) + } + + pub fn nodelay(&self) -> io::Result { + let raw: c::BYTE = try!(net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)); + Ok(raw != 0) } }