diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2015-02-11 15:25:40 -0800 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2015-02-11 15:25:40 -0800 |
| commit | a1056360ec85192a409c01ae53ba5703e3942eb8 (patch) | |
| tree | f9e2887261936dcaf8fa0cd32b66aa8d1e1c5635 /src/libstd/sys | |
| parent | 315730fb273c4d55c4c25d4fba2b68dcd6a54093 (diff) | |
| parent | 395709ca6d39ba1e095e404e1d2a169d918b7f0c (diff) | |
| download | rust-a1056360ec85192a409c01ae53ba5703e3942eb8.tar.gz rust-a1056360ec85192a409c01ae53ba5703e3942eb8.zip | |
rollup merge of #22015: alexcrichton/netv2
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')
| -rw-r--r-- | src/libstd/sys/common/mod.rs | 1 | ||||
| -rw-r--r-- | src/libstd/sys/common/net2.rs | 393 | ||||
| -rw-r--r-- | src/libstd/sys/unix/c.rs | 1 | ||||
| -rw-r--r-- | src/libstd/sys/unix/ext.rs | 14 | ||||
| -rw-r--r-- | src/libstd/sys/unix/fd.rs | 7 | ||||
| -rw-r--r-- | src/libstd/sys/unix/mod.rs | 4 | ||||
| -rw-r--r-- | src/libstd/sys/unix/net.rs | 74 | ||||
| -rw-r--r-- | src/libstd/sys/windows/ext.rs | 11 | ||||
| -rw-r--r-- | src/libstd/sys/windows/mod.rs | 1 | ||||
| -rw-r--r-- | src/libstd/sys/windows/net.rs | 121 |
10 files changed, 621 insertions, 6 deletions
diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index 80fa5f64597..5054f72ea98 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -24,6 +24,7 @@ pub mod condvar; pub mod helper_thread; pub mod mutex; pub mod net; +pub mod net2; pub mod rwlock; pub mod stack; pub mod thread; diff --git a/src/libstd/sys/common/net2.rs b/src/libstd/sys/common/net2.rs new file mode 100644 index 00000000000..5af59ec6d2b --- /dev/null +++ b/src/libstd/sys/common/net2.rs @@ -0,0 +1,393 @@ +// Copyright 2013-2014 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 ffi::CString; +use io::{self, Error, ErrorKind}; +use libc::{self, c_int, c_char, c_void, socklen_t}; +use mem; +use net::{IpAddr, SocketAddr, Shutdown}; +use num::Int; +use sys::c; +use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t}; +use sys_common::{AsInner, FromInner, IntoInner}; + +//////////////////////////////////////////////////////////////////////////////// +// sockaddr and misc bindings +//////////////////////////////////////////////////////////////////////////////// + +fn hton<I: Int>(i: I) -> I { i.to_be() } +fn ntoh<I: Int>(i: I) -> I { Int::from_be(i) } + +fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int, + payload: T) -> io::Result<()> { + unsafe { + let payload = &payload as *const T as *const c_void; + try!(cvt(libc::setsockopt(*sock.as_inner(), opt, val, payload, + mem::size_of::<T>() as socklen_t))); + Ok(()) + } +} + +#[allow(dead_code)] +fn getsockopt<T: Copy>(sock: &Socket, opt: c_int, + val: c_int) -> io::Result<T> { + unsafe { + let mut slot: T = mem::zeroed(); + let mut len = mem::size_of::<T>() as socklen_t; + let ret = try!(cvt(c::getsockopt(*sock.as_inner(), opt, val, + &mut slot as *mut _ as *mut _, + &mut len))); + assert_eq!(ret as usize, mem::size_of::<T>()); + Ok(slot) + } +} + +fn sockname<F>(f: F) -> io::Result<SocketAddr> + where F: FnOnce(*mut libc::sockaddr, *mut socklen_t) -> c_int +{ + unsafe { + let mut storage: libc::sockaddr_storage = mem::zeroed(); + let mut len = mem::size_of_val(&storage) as socklen_t; + try!(cvt(f(&mut storage as *mut _ as *mut _, &mut len))); + sockaddr_to_addr(&storage, len as usize) + } +} + +fn sockaddr_to_addr(storage: &libc::sockaddr_storage, + len: usize) -> io::Result<SocketAddr> { + match storage.ss_family as libc::c_int { + libc::AF_INET => { + assert!(len as usize >= mem::size_of::<libc::sockaddr_in>()); + Ok(FromInner::from_inner(unsafe { + *(storage as *const _ as *const libc::sockaddr_in) + })) + } + libc::AF_INET6 => { + assert!(len as usize >= mem::size_of::<libc::sockaddr_in6>()); + Ok(FromInner::from_inner(unsafe { + *(storage as *const _ as *const libc::sockaddr_in6) + })) + } + _ => { + Err(Error::new(ErrorKind::InvalidInput, "invalid argument", None)) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// get_host_addresses +//////////////////////////////////////////////////////////////////////////////// + +extern "system" { + fn getaddrinfo(node: *const c_char, service: *const c_char, + hints: *const libc::addrinfo, + res: *mut *mut libc::addrinfo) -> c_int; + fn freeaddrinfo(res: *mut libc::addrinfo); +} + +pub struct LookupHost { + original: *mut libc::addrinfo, + cur: *mut libc::addrinfo, +} + +impl Iterator for LookupHost { + type Item = io::Result<SocketAddr>; + fn next(&mut self) -> Option<io::Result<SocketAddr>> { + unsafe { + if self.cur.is_null() { return None } + let ret = sockaddr_to_addr(mem::transmute((*self.cur).ai_addr), + (*self.cur).ai_addrlen as usize); + self.cur = (*self.cur).ai_next as *mut libc::addrinfo; + Some(ret) + } + } +} + +impl Drop for LookupHost { + fn drop(&mut self) { + unsafe { freeaddrinfo(self.original) } + } +} + +pub fn lookup_host(host: &str) -> io::Result<LookupHost> { + init(); + + let c_host = CString::from_slice(host.as_bytes()); + let mut res = 0 as *mut _; + unsafe { + try!(cvt_gai(getaddrinfo(c_host.as_ptr(), 0 as *const _, 0 as *const _, + &mut res))); + Ok(LookupHost { original: res, cur: res }) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// TCP streams +//////////////////////////////////////////////////////////////////////////////// + +pub struct TcpStream { + inner: Socket, +} + +impl TcpStream { + pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> { + init(); + + let sock = try!(Socket::new(addr, libc::SOCK_STREAM)); + + let (addrp, len) = addr.into_inner(); + try!(cvt_r(|| unsafe { libc::connect(*sock.as_inner(), addrp, len) })); + Ok(TcpStream { inner: sock }) + } + + pub fn socket(&self) -> &Socket { &self.inner } + + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_NODELAY, + nodelay as c_int) + } + + pub fn set_keepalive(&self, seconds: Option<u32>) -> io::Result<()> { + let ret = setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_KEEPALIVE, + seconds.is_some() as c_int); + match seconds { + Some(n) => ret.and_then(|()| self.set_tcp_keepalive(n)), + None => ret, + } + } + + #[cfg(any(target_os = "macos", target_os = "ios"))] + fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> { + setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, + seconds as c_int) + } + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> { + setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, + seconds as c_int) + } + #[cfg(not(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly")))] + fn set_tcp_keepalive(&self, _seconds: u32) -> io::Result<()> { + Ok(()) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { + self.inner.read(buf) + } + + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { + let ret = try!(cvt(unsafe { + libc::send(*self.inner.as_inner(), + buf.as_ptr() as *const c_void, + buf.len() as wrlen_t, + 0) + })); + Ok(ret as usize) + } + + pub fn peer_addr(&self) -> io::Result<SocketAddr> { + sockname(|buf, len| unsafe { + libc::getpeername(*self.inner.as_inner(), buf, len) + }) + } + + pub fn socket_addr(&self) -> io::Result<SocketAddr> { + sockname(|buf, len| unsafe { + libc::getsockname(*self.inner.as_inner(), buf, len) + }) + } + + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + use libc::consts::os::bsd44::SHUT_RDWR; + + let how = match how { + Shutdown::Write => libc::SHUT_WR, + Shutdown::Read => libc::SHUT_RD, + Shutdown::Both => SHUT_RDWR, + }; + try!(cvt(unsafe { libc::shutdown(*self.inner.as_inner(), how) })); + Ok(()) + } + + pub fn duplicate(&self) -> io::Result<TcpStream> { + self.inner.duplicate().map(|s| TcpStream { inner: s }) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// TCP listeners +//////////////////////////////////////////////////////////////////////////////// + +pub struct TcpListener { + inner: Socket, +} + +impl TcpListener { + pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> { + init(); + + let sock = try!(Socket::new(addr, libc::SOCK_STREAM)); + + // On platforms with Berkeley-derived sockets, this allows + // to quickly rebind a socket, without needing to wait for + // the OS to clean up the previous one. + if !cfg!(windows) { + try!(setsockopt(&sock, libc::SOL_SOCKET, libc::SO_REUSEADDR, + 1 as c_int)); + } + + // Bind our new socket + let (addrp, len) = addr.into_inner(); + try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) })); + + // Start listening + try!(cvt(unsafe { libc::listen(*sock.as_inner(), 128) })); + Ok(TcpListener { inner: sock }) + } + + pub fn socket(&self) -> &Socket { &self.inner } + + pub fn socket_addr(&self) -> io::Result<SocketAddr> { + sockname(|buf, len| unsafe { + libc::getsockname(*self.inner.as_inner(), buf, len) + }) + } + + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; + let mut len = mem::size_of_val(&storage) as socklen_t; + let sock = try!(self.inner.accept(&mut storage as *mut _ as *mut _, + &mut len)); + let addr = try!(sockaddr_to_addr(&storage, len as usize)); + Ok((TcpStream { inner: sock, }, addr)) + } + + pub fn duplicate(&self) -> io::Result<TcpListener> { + self.inner.duplicate().map(|s| TcpListener { inner: s }) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// UDP +//////////////////////////////////////////////////////////////////////////////// + +pub struct UdpSocket { + inner: Socket, +} + +impl UdpSocket { + pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> { + init(); + + let sock = try!(Socket::new(addr, libc::SOCK_DGRAM)); + let (addrp, len) = addr.into_inner(); + try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) })); + Ok(UdpSocket { inner: sock }) + } + + pub fn socket(&self) -> &Socket { &self.inner } + + pub fn socket_addr(&self) -> io::Result<SocketAddr> { + sockname(|buf, len| unsafe { + libc::getsockname(*self.inner.as_inner(), buf, len) + }) + } + + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; + let mut addrlen = mem::size_of_val(&storage) as socklen_t; + + let n = try!(cvt(unsafe { + libc::recvfrom(*self.inner.as_inner(), + buf.as_mut_ptr() as *mut c_void, + buf.len() as wrlen_t, 0, + &mut storage as *mut _ as *mut _, &mut addrlen) + })); + Ok((n as usize, try!(sockaddr_to_addr(&storage, addrlen as usize)))) + } + + pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> { + let (dstp, dstlen) = dst.into_inner(); + let ret = try!(cvt(unsafe { + libc::sendto(*self.inner.as_inner(), + buf.as_ptr() as *const c_void, buf.len() as wrlen_t, + 0, dstp, dstlen) + })); + Ok(ret as usize) + } + + pub fn set_broadcast(&self, on: bool) -> io::Result<()> { + setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_BROADCAST, + on as c_int) + } + + pub fn set_multicast_loop(&self, on: bool) -> io::Result<()> { + setsockopt(&self.inner, libc::IPPROTO_IP, + libc::IP_MULTICAST_LOOP, on as c_int) + } + + pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> { + match *multi { + IpAddr::V4(..) => { + self.set_membership(multi, libc::IP_ADD_MEMBERSHIP) + } + IpAddr::V6(..) => { + self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP) + } + } + } + pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> { + match *multi { + IpAddr::V4(..) => { + self.set_membership(multi, libc::IP_DROP_MEMBERSHIP) + } + IpAddr::V6(..) => { + self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP) + } + } + } + fn set_membership(&self, addr: &IpAddr, opt: c_int) -> io::Result<()> { + match *addr { + IpAddr::V4(ref addr) => { + let mreq = libc::ip_mreq { + imr_multiaddr: *addr.as_inner(), + // interface == INADDR_ANY + imr_interface: libc::in_addr { s_addr: 0x0 }, + }; + setsockopt(&self.inner, libc::IPPROTO_IP, opt, mreq) + } + IpAddr::V6(ref addr) => { + let mreq = libc::ip6_mreq { + ipv6mr_multiaddr: *addr.as_inner(), + ipv6mr_interface: 0, + }; + setsockopt(&self.inner, libc::IPPROTO_IPV6, opt, mreq) + } + } + } + + pub fn multicast_time_to_live(&self, ttl: i32) -> io::Result<()> { + setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, + ttl as c_int) + } + + pub fn time_to_live(&self, ttl: i32) -> io::Result<()> { + setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int) + } + + pub fn duplicate(&self) -> io::Result<UdpSocket> { + self.inner.duplicate().map(|s| UdpSocket { inner: s }) + } +} diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs index cd246e8add5..345808189a0 100644 --- a/src/libstd/sys/unix/c.rs +++ b/src/libstd/sys/unix/c.rs @@ -157,6 +157,7 @@ extern { pub fn utimes(filename: *const libc::c_char, times: *const libc::timeval) -> libc::c_int; + pub fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char; } #[cfg(any(target_os = "macos", target_os = "ios"))] diff --git a/src/libstd/sys/unix/ext.rs b/src/libstd/sys/unix/ext.rs index 689bbda8322..1d95f1cce7e 100644 --- a/src/libstd/sys/unix/ext.rs +++ b/src/libstd/sys/unix/ext.rs @@ -32,8 +32,8 @@ #![unstable(feature = "std_misc")] use ffi::{OsStr, OsString}; -use fs::{Permissions, OpenOptions}; -use fs; +use fs::{self, Permissions, OpenOptions}; +use net; use libc; use mem; use sys::os_str::Buf; @@ -111,6 +111,16 @@ impl AsRawFd for old_io::net::udp::UdpSocket { } } +impl AsRawFd for net::TcpStream { + fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() } +} +impl AsRawFd for net::TcpListener { + fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() } +} +impl AsRawFd for net::UdpSocket { + fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() } +} + // Unix-specific extensions to `OsString`. pub trait OsStringExt { /// Create an `OsString` from a byte vector. diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index f0943de5378..327d117823e 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -15,8 +15,7 @@ use io; use libc::{self, c_int, size_t, c_void}; use mem; use sys::cvt; - -pub type fd_t = c_int; +use sys_common::AsInner; pub struct FileDesc { fd: c_int, @@ -55,6 +54,10 @@ impl FileDesc { } } +impl AsInner<c_int> for FileDesc { + fn as_inner(&self) -> &c_int { &self.fd } +} + impl Drop for FileDesc { fn drop(&mut self) { // closing stdio file handles makes no sense, so never do it. Also, note diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index b5a24278a20..96a18a956c6 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -18,12 +18,11 @@ use prelude::v1::*; use ffi; -use io::ErrorKind; +use io::{self, ErrorKind}; use libc; use num::{Int, SignedInt}; use num; use old_io::{self, IoResult, IoError}; -use io; use str; use sys_common::mkerr_libc; @@ -47,6 +46,7 @@ pub mod fs; // support for std::old_io pub mod fs2; // support for std::fs 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/unix/net.rs b/src/libstd/sys/unix/net.rs new file mode 100644 index 00000000000..54aec7cf4b1 --- /dev/null +++ b/src/libstd/sys/unix/net.rs @@ -0,0 +1,74 @@ +// 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 ffi; +use io; +use libc::{self, c_int, size_t}; +use str; +use sys::c; +use net::{SocketAddr, IpAddr}; +use sys::fd::FileDesc; +use sys_common::AsInner; + +pub use sys::{cvt, cvt_r}; + +pub type wrlen_t = size_t; + +pub struct Socket(FileDesc); + +pub fn init() {} + +pub fn cvt_gai(err: c_int) -> io::Result<()> { + if err == 0 { return Ok(()) } + + let detail = unsafe { + str::from_utf8(ffi::c_str_to_bytes(&c::gai_strerror(err))).unwrap() + .to_string() + }; + Err(io::Error::new(io::ErrorKind::Other, + "failed to lookup address information", Some(detail))) +} + +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, + }; + unsafe { + let fd = try!(cvt(libc::socket(fam, ty, 0))); + Ok(Socket(FileDesc::new(fd))) + } + } + + pub fn accept(&self, storage: *mut libc::sockaddr, + len: *mut libc::socklen_t) -> io::Result<Socket> { + let fd = try!(cvt_r(|| unsafe { + libc::accept(self.0.raw(), storage, len) + })); + Ok(Socket(FileDesc::new(fd))) + } + + pub fn duplicate(&self) -> io::Result<Socket> { + cvt(unsafe { libc::dup(self.0.raw()) }).map(|fd| { + Socket(FileDesc::new(fd)) + }) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { + self.0.read(buf) + } +} + +impl AsInner<c_int> for Socket { + fn as_inner(&self) -> &c_int { self.0.as_inner() } +} 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 } +} |
