Add unix socket support to the standard library
This commit is contained in:
parent
173676efdc
commit
c0d989ed6b
7 changed files with 1141 additions and 55 deletions
|
@ -1457,12 +1457,12 @@ mod tests {
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
use io::prelude::*;
|
use io::prelude::*;
|
||||||
|
|
||||||
use env;
|
|
||||||
use fs::{self, File, OpenOptions};
|
use fs::{self, File, OpenOptions};
|
||||||
use io::{ErrorKind, SeekFrom};
|
use io::{ErrorKind, SeekFrom};
|
||||||
use path::{Path, PathBuf};
|
use path::Path;
|
||||||
use rand::{self, StdRng, Rng};
|
use rand::{StdRng, Rng};
|
||||||
use str;
|
use str;
|
||||||
|
use sys_common::io::test::{TempDir, tmpdir};
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use os::windows::fs::{symlink_dir, symlink_file};
|
use os::windows::fs::{symlink_dir, symlink_file};
|
||||||
|
@ -1490,37 +1490,6 @@ mod tests {
|
||||||
}
|
}
|
||||||
) }
|
) }
|
||||||
|
|
||||||
pub struct TempDir(PathBuf);
|
|
||||||
|
|
||||||
impl TempDir {
|
|
||||||
fn join(&self, path: &str) -> PathBuf {
|
|
||||||
let TempDir(ref p) = *self;
|
|
||||||
p.join(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path<'a>(&'a self) -> &'a Path {
|
|
||||||
let TempDir(ref p) = *self;
|
|
||||||
p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for TempDir {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
// Gee, seeing how we're testing the fs module I sure hope that we
|
|
||||||
// at least implement this correctly!
|
|
||||||
let TempDir(ref p) = *self;
|
|
||||||
check!(fs::remove_dir_all(p));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tmpdir() -> TempDir {
|
|
||||||
let p = env::temp_dir();
|
|
||||||
let mut r = rand::thread_rng();
|
|
||||||
let ret = p.join(&format!("rust-{}", r.next_u32()));
|
|
||||||
check!(fs::create_dir(&ret));
|
|
||||||
TempDir(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Several test fail on windows if the user does not have permission to
|
// Several test fail on windows if the user does not have permission to
|
||||||
// create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
|
// create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
|
||||||
// disabling these test on Windows, use this function to test whether we
|
// disabling these test on Windows, use this function to test whether we
|
||||||
|
|
|
@ -51,6 +51,46 @@ pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod test {
|
||||||
|
use prelude::v1::*;
|
||||||
|
use path::{Path, PathBuf};
|
||||||
|
use env;
|
||||||
|
use rand::{self, Rng};
|
||||||
|
use fs;
|
||||||
|
|
||||||
|
pub struct TempDir(PathBuf);
|
||||||
|
|
||||||
|
impl TempDir {
|
||||||
|
pub fn join(&self, path: &str) -> PathBuf {
|
||||||
|
let TempDir(ref p) = *self;
|
||||||
|
p.join(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path<'a>(&'a self) -> &'a Path {
|
||||||
|
let TempDir(ref p) = *self;
|
||||||
|
p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TempDir {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// Gee, seeing how we're testing the fs module I sure hope that we
|
||||||
|
// at least implement this correctly!
|
||||||
|
let TempDir(ref p) = *self;
|
||||||
|
fs::remove_dir_all(p).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tmpdir() -> TempDir {
|
||||||
|
let p = env::temp_dir();
|
||||||
|
let mut r = rand::thread_rng();
|
||||||
|
let ret = p.join(&format!("rust-{}", r.next_u32()));
|
||||||
|
fs::create_dir(&ret).unwrap();
|
||||||
|
TempDir(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
@ -58,7 +98,6 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use io;
|
use io;
|
||||||
use io::{ErrorKind, Take, Repeat, repeat};
|
use io::{ErrorKind, Take, Repeat, repeat};
|
||||||
use test;
|
|
||||||
use slice::from_raw_parts;
|
use slice::from_raw_parts;
|
||||||
|
|
||||||
struct ErrorRepeat {
|
struct ErrorRepeat {
|
||||||
|
@ -129,7 +168,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_uninitialized(b: &mut test::Bencher) {
|
fn bench_uninitialized(b: &mut ::test::Bencher) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut lr = repeat(1).take(10000000);
|
let mut lr = repeat(1).take(10000000);
|
||||||
let mut vec = Vec::with_capacity(1024);
|
let mut vec = Vec::with_capacity(1024);
|
||||||
|
|
|
@ -257,12 +257,7 @@ impl TcpStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||||
let raw: c_int = try!(getsockopt(&self.inner, c::SOL_SOCKET, c::SO_ERROR));
|
self.inner.take_error()
|
||||||
if raw == 0 {
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
Ok(Some(io::Error::from_raw_os_error(raw as i32)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||||
|
@ -367,12 +362,7 @@ impl TcpListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||||
let raw: c_int = try!(getsockopt(&self.inner, c::SOL_SOCKET, c::SO_ERROR));
|
self.inner.take_error()
|
||||||
if raw == 0 {
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
Ok(Some(io::Error::from_raw_os_error(raw as i32)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||||
|
@ -564,12 +554,7 @@ impl UdpSocket {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||||
let raw: c_int = try!(getsockopt(&self.inner, c::SOL_SOCKET, c::SO_ERROR));
|
self.inner.take_error()
|
||||||
if raw == 0 {
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
Ok(Some(io::Error::from_raw_os_error(raw as i32)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||||
|
|
|
@ -35,6 +35,7 @@ pub mod fs;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
pub mod raw;
|
pub mod raw;
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
|
pub mod net;
|
||||||
|
|
||||||
/// A prelude for conveniently writing platform-specific code.
|
/// A prelude for conveniently writing platform-specific code.
|
||||||
///
|
///
|
||||||
|
|
1042
src/libstd/sys/unix/ext/net.rs
Normal file
1042
src/libstd/sys/unix/ext/net.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -57,13 +57,17 @@ impl Socket {
|
||||||
SocketAddr::V4(..) => libc::AF_INET,
|
SocketAddr::V4(..) => libc::AF_INET,
|
||||||
SocketAddr::V6(..) => libc::AF_INET6,
|
SocketAddr::V6(..) => libc::AF_INET6,
|
||||||
};
|
};
|
||||||
|
Socket::new_raw(fam, ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
|
||||||
unsafe {
|
unsafe {
|
||||||
// On linux we first attempt to pass the SOCK_CLOEXEC flag to
|
// On linux we first attempt to pass the SOCK_CLOEXEC flag to
|
||||||
// atomically create the socket and set it as CLOEXEC. Support for
|
// atomically create the socket and set it as CLOEXEC. Support for
|
||||||
// this option, however, was added in 2.6.27, and we still support
|
// this option, however, was added in 2.6.27, and we still support
|
||||||
// 2.6.18 as a kernel, so if the returned error is EINVAL we
|
// 2.6.18 as a kernel, so if the returned error is EINVAL we
|
||||||
// fallthrough to the fallback.
|
// fallthrough to the fallback.
|
||||||
if cfg!(target_os = "linux") {
|
if cfg!(linux) {
|
||||||
match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) {
|
match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) {
|
||||||
Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
|
Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
|
||||||
Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
|
Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
|
||||||
|
@ -78,6 +82,30 @@ impl Socket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> {
|
||||||
|
unsafe {
|
||||||
|
let mut fds = [0, 0];
|
||||||
|
|
||||||
|
// Like above, see if we can set cloexec atomically
|
||||||
|
if cfg!(linux) {
|
||||||
|
match cvt(libc::socketpair(fam, ty | SOCK_CLOEXEC, 0, fds.as_mut_ptr())) {
|
||||||
|
Ok(_) => {
|
||||||
|
return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))));
|
||||||
|
}
|
||||||
|
Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {},
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr())));
|
||||||
|
let a = FileDesc::new(fds[0]);
|
||||||
|
a.set_cloexec();
|
||||||
|
let b = FileDesc::new(fds[1]);
|
||||||
|
b.set_cloexec();
|
||||||
|
Ok((Socket(a), Socket(b)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t)
|
pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t)
|
||||||
-> io::Result<Socket> {
|
-> io::Result<Socket> {
|
||||||
// Unfortunately the only known way right now to accept a socket and
|
// Unfortunately the only known way right now to accept a socket and
|
||||||
|
@ -120,6 +148,10 @@ impl Socket {
|
||||||
self.0.read_to_end(buf)
|
self.0.read_to_end(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
self.0.write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
|
pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
|
||||||
let timeout = match dur {
|
let timeout = match dur {
|
||||||
Some(dur) => {
|
Some(dur) => {
|
||||||
|
@ -186,6 +218,15 @@ impl Socket {
|
||||||
let mut nonblocking = nonblocking as libc::c_ulong;
|
let mut nonblocking = nonblocking as libc::c_ulong;
|
||||||
cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(|_| ())
|
cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||||
|
let raw: c_int = try!(getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR));
|
||||||
|
if raw == 0 {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Ok(Some(io::Error::from_raw_os_error(raw as i32)))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsInner<c_int> for Socket {
|
impl AsInner<c_int> for Socket {
|
||||||
|
|
|
@ -214,6 +214,15 @@ impl Socket {
|
||||||
let raw: c::BYTE = try!(net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY));
|
let raw: c::BYTE = try!(net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY));
|
||||||
Ok(raw != 0)
|
Ok(raw != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||||
|
let raw: c_int = try!(net::getsockopt(self, c::SOL_SOCKET, c::SO_ERROR));
|
||||||
|
if raw == 0 {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Ok(Some(io::Error::from_raw_os_error(raw as i32)))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(reason = "not public", issue = "0", feature = "fd_read")]
|
#[unstable(reason = "not public", issue = "0", feature = "fd_read")]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue