Auto merge of #32302 - sfackler:unix-socket, r=alexcrichton
Add unix socket support to the standard library r? @alexcrichton
This commit is contained in:
commit
6c4b1f18f3
@ -1457,12 +1457,12 @@ mod tests {
|
||||
use prelude::v1::*;
|
||||
use io::prelude::*;
|
||||
|
||||
use env;
|
||||
use fs::{self, File, OpenOptions};
|
||||
use io::{ErrorKind, SeekFrom};
|
||||
use path::{Path, PathBuf};
|
||||
use rand::{self, StdRng, Rng};
|
||||
use path::Path;
|
||||
use rand::{StdRng, Rng};
|
||||
use str;
|
||||
use sys_common::io::test::{TempDir, tmpdir};
|
||||
|
||||
#[cfg(windows)]
|
||||
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
|
||||
// create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
|
||||
// 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)]
|
||||
mod tests {
|
||||
use prelude::v1::*;
|
||||
@ -58,7 +98,6 @@ mod tests {
|
||||
use super::*;
|
||||
use io;
|
||||
use io::{ErrorKind, Take, Repeat, repeat};
|
||||
use test;
|
||||
use slice::from_raw_parts;
|
||||
|
||||
struct ErrorRepeat {
|
||||
@ -129,7 +168,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_uninitialized(b: &mut test::Bencher) {
|
||||
fn bench_uninitialized(b: &mut ::test::Bencher) {
|
||||
b.iter(|| {
|
||||
let mut lr = repeat(1).take(10000000);
|
||||
let mut vec = Vec::with_capacity(1024);
|
||||
|
@ -257,12 +257,7 @@ impl TcpStream {
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
let raw: c_int = try!(getsockopt(&self.inner, c::SOL_SOCKET, c::SO_ERROR));
|
||||
if raw == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(io::Error::from_raw_os_error(raw as i32)))
|
||||
}
|
||||
self.inner.take_error()
|
||||
}
|
||||
|
||||
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>> {
|
||||
let raw: c_int = try!(getsockopt(&self.inner, c::SOL_SOCKET, c::SO_ERROR));
|
||||
if raw == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(io::Error::from_raw_os_error(raw as i32)))
|
||||
}
|
||||
self.inner.take_error()
|
||||
}
|
||||
|
||||
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>> {
|
||||
let raw: c_int = try!(getsockopt(&self.inner, c::SOL_SOCKET, c::SO_ERROR));
|
||||
if raw == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(io::Error::from_raw_os_error(raw as i32)))
|
||||
}
|
||||
self.inner.take_error()
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
|
@ -35,6 +35,7 @@ pub mod fs;
|
||||
pub mod process;
|
||||
pub mod raw;
|
||||
pub mod thread;
|
||||
pub mod net;
|
||||
|
||||
/// 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::V6(..) => libc::AF_INET6,
|
||||
};
|
||||
Socket::new_raw(fam, ty)
|
||||
}
|
||||
|
||||
pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
|
||||
unsafe {
|
||||
// On linux we first attempt to pass the SOCK_CLOEXEC flag to
|
||||
// atomically create the socket and set it as CLOEXEC. Support for
|
||||
// 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
|
||||
// fallthrough to the fallback.
|
||||
if cfg!(target_os = "linux") {
|
||||
if cfg!(linux) {
|
||||
match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) {
|
||||
Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
|
||||
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)
|
||||
-> io::Result<Socket> {
|
||||
// Unfortunately the only known way right now to accept a socket and
|
||||
@ -120,6 +148,10 @@ impl Socket {
|
||||
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<()> {
|
||||
let timeout = match dur {
|
||||
Some(dur) => {
|
||||
@ -186,6 +218,15 @@ impl Socket {
|
||||
let mut nonblocking = nonblocking as libc::c_ulong;
|
||||
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 {
|
||||
|
@ -214,6 +214,15 @@ impl Socket {
|
||||
let raw: c::BYTE = try!(net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY));
|
||||
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")]
|
||||
|
Loading…
x
Reference in New Issue
Block a user