Skip to content

Commit

Permalink
Fix windows
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sfackler committed Feb 28, 2016
1 parent 5d6ba17 commit 728d911
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 174 deletions.
43 changes: 0 additions & 43 deletions src/libstd/net/tcp.rs
Expand Up @@ -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<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.
///
/// This value sets the time-to-live field that is used in every packet sent
Expand Down Expand Up @@ -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;
Expand Down
23 changes: 7 additions & 16 deletions src/libstd/sys/common/net.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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
}

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -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<bool> {
let raw: c_int = try!(getsockopt(&self.inner, c::IPPROTO_TCP, c::TCP_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()
self.inner.nodelay()
}

pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
Expand Down
44 changes: 5 additions & 39 deletions src/libstd/sys/unix/net.rs
Expand Up @@ -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() {}
Expand Down Expand Up @@ -179,37 +169,13 @@ impl Socket {
Ok(())
}

pub fn set_keepalive(&self, keepalive: Option<Duration>) -> 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<Option<Duration>> {
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<bool> {
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<()> {
Expand Down
56 changes: 29 additions & 27 deletions src/libstd/sys/windows/c.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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<unsafe extern "system" fn(dwError: DWORD,
cbTransferred: DWORD,
lpOverlapped: LPWSAOVERLAPPED,
dwFlags: DWORD)>;
pub type LPWSAOVERLAPPED = *mut OVERLAPPED;

pub const TRUE: BOOL = 1;
pub const FALSE: BOOL = 0;

Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {}

Expand Down Expand Up @@ -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;
Expand Down
63 changes: 14 additions & 49 deletions src/libstd/sys/windows/net.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -186,58 +186,23 @@ impl Socket {
Ok(())
}

pub fn set_keepalive(&self, keepalive: Option<Duration>) -> 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<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)
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<bool> {
let raw: c::BYTE = try!(net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY));
Ok(raw != 0)
}
}

Expand Down

0 comments on commit 728d911

Please sign in to comment.