about summary refs log tree commit diff
path: root/src/libstd/sys/windows
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-02-05 16:50:11 -0800
committerAlex Crichton <alex@alexcrichton.com>2015-02-11 15:23:34 -0800
commit395709ca6d39ba1e095e404e1d2a169d918b7f0c (patch)
treee6a3d38abb028967c3139ee234d1c69935806800 /src/libstd/sys/windows
parenta954663db66fc8efb1889beaf7bd1771ecbb9b21 (diff)
downloadrust-395709ca6d39ba1e095e404e1d2a169d918b7f0c.tar.gz
rust-395709ca6d39ba1e095e404e1d2a169d918b7f0c.zip
std: Add a `net` module for TCP/UDP
This commit is an implementation of [RFC 807][rfc] which adds a `std::net`
module for basic neworking based on top of `std::io`. This module serves as a
replacement for the `std::old_io::net` module and networking primitives in
`old_io`.

[rfc]: fillmein

The major focus of this redesign is to cut back on the level of abstraction to
the point that each of the networking types is just a bare socket. To this end
functionality such as timeouts and cloning has been removed (although cloning
can be done through `duplicate`, it may just yield an error).

With this `net` module comes a new implementation of `SocketAddr` and `IpAddr`.
This work is entirely based on #20785 and the only changes were to alter the
in-memory representation to match the `libc`-expected variants and to move from
public fields to accessors.
Diffstat (limited to 'src/libstd/sys/windows')
-rw-r--r--src/libstd/sys/windows/ext.rs11
-rw-r--r--src/libstd/sys/windows/mod.rs1
-rw-r--r--src/libstd/sys/windows/net.rs121
3 files changed, 133 insertions, 0 deletions
diff --git a/src/libstd/sys/windows/ext.rs b/src/libstd/sys/windows/ext.rs
index dc874c2c791..ac1006e653f 100644
--- a/src/libstd/sys/windows/ext.rs
+++ b/src/libstd/sys/windows/ext.rs
@@ -21,6 +21,7 @@ pub use sys_common::wtf8::{Wtf8Buf, EncodeWide};
 use ffi::{OsStr, OsString};
 use fs::{self, OpenOptions};
 use libc;
+use net;
 use sys::os_str::Buf;
 use sys_common::{AsInner, FromInner, AsInnerMut};
 
@@ -103,6 +104,16 @@ impl AsRawSocket for old_io::net::udp::UdpSocket {
     }
 }
 
+impl AsRawSocket for net::TcpStream {
+    fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
+}
+impl AsRawSocket for net::TcpListener {
+    fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
+}
+impl AsRawSocket for net::UdpSocket {
+    fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
+}
+
 // Windows-specific extensions to `OsString`.
 pub trait OsStringExt {
     /// Create an `OsString` from a potentially ill-formed UTF-16 slice of 16-bit code units.
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index 140bdb14501..0fa9aaf4323 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -43,6 +43,7 @@ pub mod fs2;
 pub mod handle;
 pub mod helper_signal;
 pub mod mutex;
+pub mod net;
 pub mod os;
 pub mod os_str;
 pub mod pipe;
diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs
new file mode 100644
index 00000000000..4df72f6d4ab
--- /dev/null
+++ b/src/libstd/sys/windows/net.rs
@@ -0,0 +1,121 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use prelude::v1::*;
+
+use io;
+use libc::consts::os::extra::INVALID_SOCKET;
+use libc::{self, c_int, c_void};
+use mem;
+use net::{SocketAddr, IpAddr};
+use num::{SignedInt, Int};
+use rt;
+use sync::{Once, ONCE_INIT};
+use sys::c;
+use sys_common::AsInner;
+
+pub type wrlen_t = i32;
+
+pub struct Socket(libc::SOCKET);
+
+pub fn init() {
+    static START: Once = ONCE_INIT;
+
+    START.call_once(|| unsafe {
+        let mut data: c::WSADATA = mem::zeroed();
+        let ret = c::WSAStartup(0x202, // version 2.2
+                                &mut data);
+        assert_eq!(ret, 0);
+
+        rt::at_exit(|| { c::WSACleanup(); })
+    });
+}
+
+fn last_error() -> io::Error {
+    io::Error::from_os_error(unsafe { c::WSAGetLastError() })
+}
+
+pub fn cvt<T: SignedInt>(t: T) -> io::Result<T> {
+    let one: T = Int::one();
+    if t == -one {
+        Err(last_error())
+    } else {
+        Ok(t)
+    }
+}
+
+pub fn cvt_gai(err: c_int) -> io::Result<()> {
+    if err == 0 { return Ok(()) }
+    cvt(err).map(|_| ())
+}
+
+pub fn cvt_r<T: SignedInt, F>(mut f: F) -> io::Result<T> where F: FnMut() -> T {
+    cvt(f())
+}
+
+impl Socket {
+    pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
+        let fam = match addr.ip {
+            IpAddr::V4(..) => libc::AF_INET,
+            IpAddr::V6(..) => libc::AF_INET6,
+        };
+        match unsafe { libc::socket(fam, ty, 0) } {
+            INVALID_SOCKET => Err(last_error()),
+            n => Ok(Socket(n)),
+        }
+    }
+
+    pub fn accept(&self, storage: *mut libc::sockaddr,
+                  len: *mut libc::socklen_t) -> io::Result<Socket> {
+        match unsafe { libc::accept(self.0, storage, len) } {
+            INVALID_SOCKET => Err(last_error()),
+            n => Ok(Socket(n)),
+        }
+    }
+
+    pub fn duplicate(&self) -> io::Result<Socket> {
+        unsafe {
+            let mut info: c::WSAPROTOCOL_INFO = mem::zeroed();
+            try!(cvt(c::WSADuplicateSocketW(self.0,
+                                            c::GetCurrentProcessId(),
+                                            &mut info)));
+            match c::WSASocketW(info.iAddressFamily,
+                                info.iSocketType,
+                                info.iProtocol,
+                                &mut info, 0, 0) {
+                INVALID_SOCKET => Err(last_error()),
+                n => Ok(Socket(n)),
+            }
+        }
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        // On unix when a socket is shut down all further reads return 0, so we
+        // do the same on windows to map a shut down socket to returning EOF.
+        unsafe {
+            match libc::recv(self.0, buf.as_mut_ptr() as *mut c_void,
+                             buf.len() as i32, 0) {
+                -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
+                -1 => Err(last_error()),
+                n => Ok(n as usize)
+            }
+        }
+    }
+}
+
+impl Drop for Socket {
+    fn drop(&mut self) {
+        unsafe { let _ = libc::closesocket(self.0); }
+    }
+}
+
+impl AsInner<libc::SOCKET> for Socket {
+    fn as_inner(&self) -> &libc::SOCKET { &self.0 }
+}