about summary refs log tree commit diff
path: root/src/libstd/sys/windows
diff options
context:
space:
mode:
authorSteven Fackler <sfackler@gmail.com>2016-02-27 14:15:19 -0800
committerSteven Fackler <sfackler@gmail.com>2016-02-28 09:41:33 -0800
commit827be2de0d753afb3e5a00e66afe6e3c3ac79494 (patch)
tree602ababcb35eff73ae93c3e8dd1ff1f23c60c02d /src/libstd/sys/windows
parentc5237b02b96b199abdcf1ddb472b0080fdff4ccd (diff)
Add TCP functionality from net2
Diffstat (limited to 'src/libstd/sys/windows')
-rw-r--r--src/libstd/sys/windows/c.rs28
-rw-r--r--src/libstd/sys/windows/net.rs54
2 files changed, 82 insertions, 0 deletions
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index 5cbfec01bed..cc420763fd7 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -78,6 +78,13 @@ 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;
 
@@ -114,6 +121,9 @@ 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)]
 #[derive(Copy)]
 pub struct WIN32_FIND_DATAW {
@@ -775,6 +785,13 @@ 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 {}
 
@@ -833,6 +850,17 @@ 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 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 49ba8e9c659..be13657aaf4 100644
--- a/src/libstd/sys/windows/net.rs
+++ b/src/libstd/sys/windows/net.rs
@@ -185,6 +185,60 @@ impl Socket {
         try!(cvt(unsafe { c::shutdown(self.0, how) }));
         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)
+        } else {
+            let secs = ka.keepaliveinterval / 1000;
+            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<()> {
+        let mut nonblocking = nonblocking as c::c_ulong;
+        sys::cvt(unsafe {
+            c::ioctlsocket(self.0, c::FIONBIO as c::c_int, &mut nonblocking)
+        }).map(|_| ())
+    }
 }
 
 impl Drop for Socket {