aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/sys/unix/ext
diff options
context:
space:
mode:
authorValentin <[email protected]>2018-06-15 18:57:24 +0200
committerFenrirWolf <[email protected]>2018-06-15 10:57:24 -0600
commitf2a90174bb36b9ad528e863ab34c02ebce002b02 (patch)
tree959e8d67883d3a89e179b3549b1f30d28e51a87c /ctr-std/src/sys/unix/ext
parentMerge pull request #68 from linouxis9/master (diff)
downloadctru-rs-f2a90174bb36b9ad528e863ab34c02ebce002b02.tar.xz
ctru-rs-f2a90174bb36b9ad528e863ab34c02ebce002b02.zip
Update for latest nightly 2018-06-09 (#70)
* Update for latest nightly 2018-06-09 * We now have a proper horizon os and sys modules in libstd
Diffstat (limited to 'ctr-std/src/sys/unix/ext')
-rw-r--r--ctr-std/src/sys/unix/ext/ffi.rs8
-rw-r--r--ctr-std/src/sys/unix/ext/fs.rs736
-rw-r--r--ctr-std/src/sys/unix/ext/mod.rs28
-rw-r--r--ctr-std/src/sys/unix/ext/net.rs1818
-rw-r--r--ctr-std/src/sys/unix/ext/process.rs203
-rw-r--r--ctr-std/src/sys/unix/ext/raw.rs17
-rw-r--r--ctr-std/src/sys/unix/ext/thread.rs51
7 files changed, 2839 insertions, 22 deletions
diff --git a/ctr-std/src/sys/unix/ext/ffi.rs b/ctr-std/src/sys/unix/ext/ffi.rs
index fb9984c..8347145 100644
--- a/ctr-std/src/sys/unix/ext/ffi.rs
+++ b/ctr-std/src/sys/unix/ext/ffi.rs
@@ -17,7 +17,9 @@ use mem;
use sys::os_str::Buf;
use sys_common::{FromInner, IntoInner, AsInner};
-/// Unix-specific extensions to `OsString`.
+/// Unix-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
/// Creates an [`OsString`] from a byte vector.
@@ -66,7 +68,9 @@ impl OsStringExt for OsString {
}
}
-/// Unix-specific extensions to `OsStr`.
+/// Unix-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt {
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/ctr-std/src/sys/unix/ext/fs.rs b/ctr-std/src/sys/unix/ext/fs.rs
new file mode 100644
index 0000000..4e98101
--- /dev/null
+++ b/ctr-std/src/sys/unix/ext/fs.rs
@@ -0,0 +1,736 @@
+// 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.
+
+//! Unix-specific extensions to primitives in the `std::fs` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use fs::{self, Permissions, OpenOptions};
+use io;
+use libc;
+use path::Path;
+use sys;
+use sys_common::{FromInner, AsInner, AsInnerMut};
+use sys::platform::fs::MetadataExt as UnixMetadataExt;
+
+/// Unix-specific extensions to [`File`].
+///
+/// [`File`]: ../../../../std/fs/struct.File.html
+#[stable(feature = "file_offset", since = "1.15.0")]
+pub trait FileExt {
+ /// Reads a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes read.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// Note that similar to [`File::read`], it is not an error to return with a
+ /// short read.
+ ///
+ /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs::File;
+ /// use std::os::unix::prelude::FileExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut buf = [0u8; 8];
+ /// let file = File::open("foo.txt")?;
+ ///
+ /// // We now read 8 bytes from the offset 10.
+ /// let num_bytes_read = file.read_at(&mut buf, 10)?;
+ /// println!("read {} bytes: {:?}", num_bytes_read, buf);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+ /// Writes a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes written.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// When writing beyond the end of the file, the file is appropriately
+ /// extended and the intermediate bytes are initialized with the value 0.
+ ///
+ /// Note that similar to [`File::write`], it is not an error to return a
+ /// short write.
+ ///
+ /// [`File::write`]: ../../../../std/fs/struct.File.html#write.v
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io;
+ /// use std::os::unix::prelude::FileExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let file = File::open("foo.txt")?;
+ ///
+ /// // We now write at the offset 10.
+ /// file.write_at(b"sushi", 10)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+}
+
+#[stable(feature = "file_offset", since = "1.15.0")]
+impl FileExt for fs::File {
+ fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().read_at(buf, offset)
+ }
+ fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().write_at(buf, offset)
+ }
+}
+
+/// Unix-specific extensions to [`fs::Permissions`].
+///
+/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait PermissionsExt {
+ /// Returns the underlying raw `st_mode` bits that contain the standard
+ /// Unix permissions for this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::os::unix::fs::PermissionsExt;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
+ /// let permissions = metadata.permissions();
+ ///
+ /// println!("permissions: {}", permissions.mode());
+ /// Ok(()) }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn mode(&self) -> u32;
+
+ /// Sets the underlying raw bits for this set of permissions.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::os::unix::fs::PermissionsExt;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
+ /// let mut permissions = metadata.permissions();
+ ///
+ /// permissions.set_mode(0o644); // Read/write for owner and read for others.
+ /// assert_eq!(permissions.mode(), 0o644);
+ /// Ok(()) }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn set_mode(&mut self, mode: u32);
+
+ /// Creates a new instance of `Permissions` from the given set of Unix
+ /// permission bits.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::Permissions;
+ /// use std::os::unix::fs::PermissionsExt;
+ ///
+ /// // Read/write for owner and read for others.
+ /// let permissions = Permissions::from_mode(0o644);
+ /// assert_eq!(permissions.mode(), 0o644);
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn from_mode(mode: u32) -> Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl PermissionsExt for Permissions {
+ fn mode(&self) -> u32 {
+ self.as_inner().mode()
+ }
+
+ fn set_mode(&mut self, mode: u32) {
+ *self = Permissions::from_inner(FromInner::from_inner(mode));
+ }
+
+ fn from_mode(mode: u32) -> Permissions {
+ Permissions::from_inner(FromInner::from_inner(mode))
+ }
+}
+
+/// Unix-specific extensions to [`fs::OpenOptions`].
+///
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait OpenOptionsExt {
+ /// Sets the mode bits that a new file will be created with.
+ ///
+ /// If a new file is created as part of a `File::open_opts` call then this
+ /// specified `mode` will be used as the permission bits for the new file.
+ /// If no `mode` is set, the default of `0o666` will be used.
+ /// The operating system masks out bits with the systems `umask`, to produce
+ /// the final permissions.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::OpenOptions;
+ /// use std::os::unix::fs::OpenOptionsExt;
+ ///
+ /// # fn main() {
+ /// let mut options = OpenOptions::new();
+ /// options.mode(0o644); // Give read/write for owner and read for others.
+ /// let file = options.open("foo.txt");
+ /// # }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn mode(&mut self, mode: u32) -> &mut Self;
+
+ /// Pass custom flags to the `flags` argument of `open`.
+ ///
+ /// The bits that define the access mode are masked out with `O_ACCMODE`, to
+ /// ensure they do not interfere with the access mode set by Rusts options.
+ ///
+ /// Custom flags can only set flags, not remove flags set by Rusts options.
+ /// This options overwrites any previously set custom flags.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![feature(libc)]
+ /// extern crate libc;
+ /// use std::fs::OpenOptions;
+ /// use std::os::unix::fs::OpenOptionsExt;
+ ///
+ /// # fn main() {
+ /// let mut options = OpenOptions::new();
+ /// options.write(true);
+ /// if cfg!(unix) {
+ /// options.custom_flags(libc::O_NOFOLLOW);
+ /// }
+ /// let file = options.open("foo.txt");
+ /// # }
+ /// ```
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn custom_flags(&mut self, flags: i32) -> &mut Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl OpenOptionsExt for OpenOptions {
+ fn mode(&mut self, mode: u32) -> &mut OpenOptions {
+ self.as_inner_mut().mode(mode); self
+ }
+
+ fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
+ self.as_inner_mut().custom_flags(flags); self
+ }
+}
+
+/// Unix-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Returns the ID of the device containing the file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let dev_id = meta.dev();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn dev(&self) -> u64;
+ /// Returns the inode number.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let inode = meta.ino();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ino(&self) -> u64;
+ /// Returns the rights applied to this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let mode = meta.mode();
+ /// let user_has_write_access = mode & 0o200;
+ /// let user_has_read_write_access = mode & 0o600;
+ /// let group_has_read_access = mode & 0o040;
+ /// let others_have_exec_access = mode & 0o001;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mode(&self) -> u32;
+ /// Returns the number of hard links pointing to this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let nb_hard_links = meta.nlink();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn nlink(&self) -> u64;
+ /// Returns the user ID of the owner of this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let user_id = meta.uid();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn uid(&self) -> u32;
+ /// Returns the group ID of the owner of this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let group_id = meta.gid();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn gid(&self) -> u32;
+ /// Returns the device ID of this file (if it is a special one).
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let device_id = meta.rdev();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn rdev(&self) -> u64;
+ /// Returns the total size of this file in bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let file_size = meta.size();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn size(&self) -> u64;
+ /// Returns the time of the last access to the file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let last_access_time = meta.atime();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn atime(&self) -> i64;
+ /// Returns the time of the last access to the file in nanoseconds.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let nano_last_access_time = meta.atime_nsec();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn atime_nsec(&self) -> i64;
+ /// Returns the time of the last modification of the file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let last_modification_time = meta.mtime();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mtime(&self) -> i64;
+ /// Returns the time of the last modification of the file in nanoseconds.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let nano_last_modification_time = meta.mtime_nsec();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mtime_nsec(&self) -> i64;
+ /// Returns the time of the last status change of the file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let last_status_change_time = meta.ctime();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ctime(&self) -> i64;
+ /// Returns the time of the last status change of the file in nanoseconds.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let nano_last_status_change_time = meta.ctime_nsec();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ctime_nsec(&self) -> i64;
+ /// Returns the blocksize for filesystem I/O.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let blocksize = meta.blksize();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn blksize(&self) -> u64;
+ /// Returns the number of blocks allocated to the file, in 512-byte units.
+ ///
+ /// Please note that this may be smaller than `st_size / 512` when the file has holes.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::MetadataExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let blocks = meta.blocks();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for fs::Metadata {
+ fn dev(&self) -> u64 { self.st_dev() }
+ fn ino(&self) -> u64 { self.st_ino() }
+ fn mode(&self) -> u32 { self.st_mode() }
+ fn nlink(&self) -> u64 { self.st_nlink() }
+ fn uid(&self) -> u32 { self.st_uid() }
+ fn gid(&self) -> u32 { self.st_gid() }
+ fn rdev(&self) -> u64 { self.st_rdev() }
+ fn size(&self) -> u64 { self.st_size() }
+ fn atime(&self) -> i64 { self.st_atime() }
+ fn atime_nsec(&self) -> i64 { self.st_atime_nsec() }
+ fn mtime(&self) -> i64 { self.st_mtime() }
+ fn mtime_nsec(&self) -> i64 { self.st_mtime_nsec() }
+ fn ctime(&self) -> i64 { self.st_ctime() }
+ fn ctime_nsec(&self) -> i64 { self.st_ctime_nsec() }
+ fn blksize(&self) -> u64 { self.st_blksize() }
+ fn blocks(&self) -> u64 { self.st_blocks() }
+}
+
+/// Unix-specific extensions for [`FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+pub trait FileTypeExt {
+ /// Returns whether this file type is a block device.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::FileTypeExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("block_device_file")?;
+ /// let file_type = meta.file_type();
+ /// assert!(file_type.is_block_device());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_block_device(&self) -> bool;
+ /// Returns whether this file type is a char device.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::FileTypeExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("char_device_file")?;
+ /// let file_type = meta.file_type();
+ /// assert!(file_type.is_char_device());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_char_device(&self) -> bool;
+ /// Returns whether this file type is a fifo.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::FileTypeExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("fifo_file")?;
+ /// let file_type = meta.file_type();
+ /// assert!(file_type.is_fifo());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_fifo(&self) -> bool;
+ /// Returns whether this file type is a socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::os::unix::fs::FileTypeExt;
+ /// use std::io;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("unix.socket")?;
+ /// let file_type = meta.file_type();
+ /// assert!(file_type.is_socket());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_socket(&self) -> bool;
+}
+
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+impl FileTypeExt for fs::FileType {
+ fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) }
+ fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) }
+ fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) }
+ fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) }
+}
+
+/// Unix-specific extension methods for [`fs::DirEntry`].
+///
+/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html
+#[stable(feature = "dir_entry_ext", since = "1.1.0")]
+pub trait DirEntryExt {
+ /// Returns the underlying `d_ino` field in the contained `dirent`
+ /// structure.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs;
+ /// use std::os::unix::fs::DirEntryExt;
+ ///
+ /// if let Ok(entries) = fs::read_dir(".") {
+ /// for entry in entries {
+ /// if let Ok(entry) = entry {
+ /// // Here, `entry` is a `DirEntry`.
+ /// println!("{:?}: {}", entry.file_name(), entry.ino());
+ /// }
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "dir_entry_ext", since = "1.1.0")]
+ fn ino(&self) -> u64;
+}
+
+#[stable(feature = "dir_entry_ext", since = "1.1.0")]
+impl DirEntryExt for fs::DirEntry {
+ fn ino(&self) -> u64 { self.as_inner().ino() }
+}
+
+/// Creates a new symbolic link on the filesystem.
+///
+/// The `dst` path will be a symbolic link pointing to the `src` path.
+///
+/// # Note
+///
+/// On Windows, you must specify whether a symbolic link points to a file
+/// or directory. Use `os::windows::fs::symlink_file` to create a
+/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
+/// symbolic link to a directory. Additionally, the process must have
+/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
+/// symbolic link.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::symlink("a.txt", "b.txt")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
+{
+ sys::fs::symlink(src.as_ref(), dst.as_ref())
+}
+
+/// Unix-specific extensions to [`fs::DirBuilder`].
+///
+/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
+#[stable(feature = "dir_builder", since = "1.6.0")]
+pub trait DirBuilderExt {
+ /// Sets the mode to create new directories with. This option defaults to
+ /// 0o777.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::DirBuilder;
+ /// use std::os::unix::fs::DirBuilderExt;
+ ///
+ /// let mut builder = DirBuilder::new();
+ /// builder.mode(0o755);
+ /// ```
+ #[stable(feature = "dir_builder", since = "1.6.0")]
+ fn mode(&mut self, mode: u32) -> &mut Self;
+}
+
+#[stable(feature = "dir_builder", since = "1.6.0")]
+impl DirBuilderExt for fs::DirBuilder {
+ fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
+ self.as_inner_mut().set_mode(mode);
+ self
+ }
+}
diff --git a/ctr-std/src/sys/unix/ext/mod.rs b/ctr-std/src/sys/unix/ext/mod.rs
index 7b0d175..c221f7c 100644
--- a/ctr-std/src/sys/unix/ext/mod.rs
+++ b/ctr-std/src/sys/unix/ext/mod.rs
@@ -38,11 +38,11 @@
pub mod io;
pub mod ffi;
-//pub mod fs;
-//pub mod process;
+pub mod fs;
+pub mod process;
pub mod raw;
-//pub mod thread;
-//pub mod net;
+pub mod thread;
+pub mod net;
/// A prelude for conveniently writing platform-specific code.
///
@@ -53,14 +53,14 @@ pub mod prelude {
pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::ffi::{OsStrExt, OsStringExt};
- //#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
- //pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
- //#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
- //pub use super::fs::DirEntryExt;
- //#[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
- //pub use super::fs::FileExt;
- //#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
- //pub use super::thread::JoinHandleExt;
- //#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
- //pub use super::process::{CommandExt, ExitStatusExt};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::fs::DirEntryExt;
+ #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
+ pub use super::fs::FileExt;
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::thread::JoinHandleExt;
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::process::{CommandExt, ExitStatusExt};
}
diff --git a/ctr-std/src/sys/unix/ext/net.rs b/ctr-std/src/sys/unix/ext/net.rs
new file mode 100644
index 0000000..e277b1a
--- /dev/null
+++ b/ctr-std/src/sys/unix/ext/net.rs
@@ -0,0 +1,1818 @@
+// Copyright 2016 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.
+
+#![stable(feature = "unix_socket", since = "1.10.0")]
+
+//! Unix-specific networking functionality
+
+#[cfg(unix)]
+use libc;
+
+// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
+#[cfg(not(unix))]
+mod libc {
+ pub use libc::c_int;
+ pub type socklen_t = u32;
+ pub struct sockaddr;
+ #[derive(Clone)]
+ pub struct sockaddr_un;
+}
+
+use ascii;
+use ffi::OsStr;
+use fmt;
+use io::{self, Initializer};
+use mem;
+use net::{self, Shutdown};
+use os::unix::ffi::OsStrExt;
+use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
+use path::Path;
+use time::Duration;
+use sys::{self, cvt};
+use sys::net::Socket;
+use sys_common::{self, AsInner, FromInner, IntoInner};
+
+#[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "dragonfly", target_os = "freebsd",
+ target_os = "openbsd", target_os = "netbsd",
+ target_os = "haiku", target_os = "bitrig"))]
+use libc::MSG_NOSIGNAL;
+#[cfg(not(any(target_os = "linux", target_os = "android",
+ target_os = "dragonfly", target_os = "freebsd",
+ target_os = "openbsd", target_os = "netbsd",
+ target_os = "haiku", target_os = "bitrig")))]
+const MSG_NOSIGNAL: libc::c_int = 0x0;
+
+fn sun_path_offset() -> usize {
+ // Work with an actual instance of the type since using a null pointer is UB
+ let addr: libc::sockaddr_un = unsafe { mem::uninitialized() };
+ let base = &addr as *const _ as usize;
+ let path = &addr.sun_path as *const _ as usize;
+ path - base
+}
+
+unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
+ let mut addr: libc::sockaddr_un = mem::zeroed();
+ addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
+
+ let bytes = path.as_os_str().as_bytes();
+
+ if bytes.contains(&0) {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "paths may not contain interior null bytes"));
+ }
+
+ if bytes.len() >= addr.sun_path.len() {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "path must be shorter than SUN_LEN"));
+ }
+ for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) {
+ *dst = *src as libc::c_char;
+ }
+ // null byte for pathname addresses is already there because we zeroed the
+ // struct
+
+ let mut len = sun_path_offset() + bytes.len();
+ match bytes.get(0) {
+ Some(&0) | None => {}
+ Some(_) => len += 1,
+ }
+ Ok((addr, len as libc::socklen_t))
+}
+
+enum AddressKind<'a> {
+ Unnamed,
+ Pathname(&'a Path),
+ Abstract(&'a [u8]),
+}
+
+/// An address associated with a Unix socket.
+///
+/// # Examples
+///
+/// ```
+/// use std::os::unix::net::UnixListener;
+///
+/// let socket = match UnixListener::bind("/tmp/sock") {
+/// Ok(sock) => sock,
+/// Err(e) => {
+/// println!("Couldn't bind: {:?}", e);
+/// return
+/// }
+/// };
+/// let addr = socket.local_addr().expect("Couldn't get local address");
+/// ```
+#[derive(Clone)]
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct SocketAddr {
+ addr: libc::sockaddr_un,
+ len: libc::socklen_t,
+}
+
+impl SocketAddr {
+ fn new<F>(f: F) -> io::Result<SocketAddr>
+ where F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int
+ {
+ unsafe {
+ let mut addr: libc::sockaddr_un = mem::zeroed();
+ let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
+ cvt(f(&mut addr as *mut _ as *mut _, &mut len))?;
+ SocketAddr::from_parts(addr, len)
+ }
+ }
+
+ fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result<SocketAddr> {
+ if len == 0 {
+ // When there is a datagram from unnamed unix socket
+ // linux returns zero bytes of address
+ len = sun_path_offset() as libc::socklen_t; // i.e. zero-length address
+ } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "file descriptor did not correspond to a Unix socket"));
+ }
+
+ Ok(SocketAddr {
+ addr,
+ len,
+ })
+ }
+
+ /// Returns true if and only if the address is unnamed.
+ ///
+ /// # Examples
+ ///
+ /// A named address:
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let socket = UnixListener::bind("/tmp/sock").unwrap();
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.is_unnamed(), false);
+ /// ```
+ ///
+ /// An unnamed address:
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let socket = UnixDatagram::unbound().unwrap();
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.is_unnamed(), true);
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn is_unnamed(&self) -> bool {
+ if let AddressKind::Unnamed = self.address() {
+ true
+ } else {
+ false
+ }
+ }
+
+ /// Returns the contents of this address if it is a `pathname` address.
+ ///
+ /// # Examples
+ ///
+ /// With a pathname:
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ /// use std::path::Path;
+ ///
+ /// let socket = UnixListener::bind("/tmp/sock").unwrap();
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
+ /// ```
+ ///
+ /// Without a pathname:
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let socket = UnixDatagram::unbound().unwrap();
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.as_pathname(), None);
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn as_pathname(&self) -> Option<&Path> {
+ if let AddressKind::Pathname(path) = self.address() {
+ Some(path)
+ } else {
+ None
+ }
+ }
+
+ fn address<'a>(&'a self) -> AddressKind<'a> {
+ let len = self.len as usize - sun_path_offset();
+ let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
+
+ // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
+ if len == 0
+ || (cfg!(not(any(target_os = "linux", target_os = "android")))
+ && self.addr.sun_path[0] == 0)
+ {
+ AddressKind::Unnamed
+ } else if self.addr.sun_path[0] == 0 {
+ AddressKind::Abstract(&path[1..len])
+ } else {
+ AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
+ }
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for SocketAddr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match self.address() {
+ AddressKind::Unnamed => write!(fmt, "(unnamed)"),
+ AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
+ AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
+ }
+ }
+}
+
+struct AsciiEscaped<'a>(&'a [u8]);
+
+impl<'a> fmt::Display for AsciiEscaped<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "\"")?;
+ for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
+ write!(fmt, "{}", byte as char)?;
+ }
+ write!(fmt, "\"")
+ }
+}
+
+/// A Unix stream socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixStream;
+/// use std::io::prelude::*;
+///
+/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap();
+/// stream.write_all(b"hello world").unwrap();
+/// let mut response = String::new();
+/// stream.read_to_string(&mut response).unwrap();
+/// println!("{}", response);
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixStream(Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for UnixStream {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let mut builder = fmt.debug_struct("UnixStream");
+ builder.field("fd", self.0.as_inner());
+ if let Ok(addr) = self.local_addr() {
+ builder.field("local", &addr);
+ }
+ if let Ok(addr) = self.peer_addr() {
+ builder.field("peer", &addr);
+ }
+ builder.finish()
+ }
+}
+
+impl UnixStream {
+ /// Connects to the socket named by `path`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = match UnixStream::connect("/tmp/sock") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
+ fn inner(path: &Path) -> io::Result<UnixStream> {
+ unsafe {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ let (addr, len) = sockaddr_un(path)?;
+
+ cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?;
+ Ok(UnixStream(inner))
+ }
+ }
+ inner(path.as_ref())
+ }
+
+ /// Creates an unnamed pair of connected sockets.
+ ///
+ /// Returns two `UnixStream`s which are connected to each other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let (sock1, sock2) = match UnixStream::pair() {
+ /// Ok((sock1, sock2)) => (sock1, sock2),
+ /// Err(e) => {
+ /// println!("Couldn't create a pair of sockets: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
+ let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ Ok((UnixStream(i1), UnixStream(i2)))
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixStream` is a reference to the same stream that this
+ /// object references. Both handles will read and write the same stream of
+ /// data, and options set on one stream will be propagated to the other
+ /// stream.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// let sock_copy = socket.try_clone().expect("Couldn't clone socket");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn try_clone(&self) -> io::Result<UnixStream> {
+ self.0.duplicate().map(UnixStream)
+ }
+
+ /// Returns the socket address of the local half of this connection.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+ }
+
+ /// Returns the socket address of the remote half of this connection.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// let addr = socket.peer_addr().expect("Couldn't get peer address");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
+ }
+
+ /// Sets the read timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`read`] calls will block
+ /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method.
+ ///
+ /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+ /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
+ /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read
+ /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+ self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
+ }
+
+ /// Sets the write timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`write`] calls will block
+ /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
+ /// passed to this method.
+ ///
+ /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+ /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
+ /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write
+ /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::net::UdpSocket;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap();
+ /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+ self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
+ }
+
+ /// Returns the read timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+ /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0)));
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.timeout(libc::SO_RCVTIMEO)
+ }
+
+ /// Returns the write timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
+ /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0)));
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.timeout(libc::SO_SNDTIMEO)
+ }
+
+ /// Moves the socket into or out of nonblocking mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_nonblocking(true).expect("Couldn't set nonblocking");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// if let Ok(Some(err)) = socket.take_error() {
+ /// println!("Got error: {:?}", err);
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// Shuts down the read, write, or both halves of this connection.
+ ///
+ /// This function will cause all pending and future I/O calls on the
+ /// specified portions to immediately return with an appropriate value
+ /// (see the documentation of [`Shutdown`]).
+ ///
+ /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::net::Shutdown;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.shutdown(Shutdown::Both).expect("shutdown function failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.0.shutdown(how)
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl io::Read for UnixStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ io::Read::read(&mut &*self, buf)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> io::Read for &'a UnixStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl io::Write for UnixStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ io::Write::write(&mut &*self, buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ io::Write::flush(&mut &*self)
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> io::Write for &'a UnixStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixStream {
+ fn as_raw_fd(&self) -> RawFd {
+ *self.0.as_inner()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixStream {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
+ UnixStream(Socket::from_inner(fd))
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixStream {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_inner()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpStream {
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpListener {
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::UdpSocket {
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpStream {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket))
+ }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpListener {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket))
+ }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::UdpSocket {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket))
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpStream {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_socket().into_inner()
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpListener {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_socket().into_inner()
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::UdpSocket {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_socket().into_inner()
+ }
+}
+
+/// A structure representing a Unix domain socket server.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+/// // ...
+/// }
+///
+/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+///
+/// // accept connections and process them, spawning a new thread for each one
+/// for stream in listener.incoming() {
+/// match stream {
+/// Ok(stream) => {
+/// /* connection succeeded */
+/// thread::spawn(|| handle_client(stream));
+/// }
+/// Err(err) => {
+/// /* connection failed */
+/// break;
+/// }
+/// }
+/// }
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixListener(Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for UnixListener {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let mut builder = fmt.debug_struct("UnixListener");
+ builder.field("fd", self.0.as_inner());
+ if let Ok(addr) = self.local_addr() {
+ builder.field("local", &addr);
+ }
+ builder.finish()
+ }
+}
+
+impl UnixListener {
+ /// Creates a new `UnixListener` bound to the specified socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = match UnixListener::bind("/path/to/the/socket") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
+ fn inner(path: &Path) -> io::Result<UnixListener> {
+ unsafe {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ let (addr, len) = sockaddr_un(path)?;
+
+ cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?;
+ cvt(libc::listen(*inner.as_inner(), 128))?;
+
+ Ok(UnixListener(inner))
+ }
+ }
+ inner(path.as_ref())
+ }
+
+ /// Accepts a new incoming connection to this listener.
+ ///
+ /// This function will block the calling thread until a new Unix connection
+ /// is established. When established, the corresponding [`UnixStream`] and
+ /// the remote peer's address will be returned.
+ ///
+ /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// match listener.accept() {
+ /// Ok((socket, addr)) => println!("Got a client: {:?}", addr),
+ /// Err(e) => println!("accept function failed: {:?}", e),
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
+ let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
+ let mut len = mem::size_of_val(&storage) as libc::socklen_t;
+ let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?;
+ let addr = SocketAddr::from_parts(storage, len)?;
+ Ok((UnixStream(sock), addr))
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixListener` is a reference to the same socket that this
+ /// object references. Both handles can be used to accept incoming
+ /// connections and options set on one listener will affect the other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// let listener_copy = listener.try_clone().expect("try_clone failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn try_clone(&self) -> io::Result<UnixListener> {
+ self.0.duplicate().map(UnixListener)
+ }
+
+ /// Returns the local socket address of this listener.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// let addr = listener.local_addr().expect("Couldn't get local address");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+ }
+
+ /// Moves the socket into or out of nonblocking mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// listener.set_nonblocking(true).expect("Couldn't set non blocking");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/tmp/sock").unwrap();
+ ///
+ /// if let Ok(Some(err)) = listener.take_error() {
+ /// println!("Got error: {:?}", err);
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// Returns an iterator over incoming connections.
+ ///
+ /// The iterator will never return [`None`] and will also not yield the
+ /// peer's [`SocketAddr`] structure.
+ ///
+ /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+ /// [`SocketAddr`]: struct.SocketAddr.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::thread;
+ /// use std::os::unix::net::{UnixStream, UnixListener};
+ ///
+ /// fn handle_client(stream: UnixStream) {
+ /// // ...
+ /// }
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// for stream in listener.incoming() {
+ /// match stream {
+ /// Ok(stream) => {
+ /// thread::spawn(|| handle_client(stream));
+ /// }
+ /// Err(err) => {
+ /// break;
+ /// }
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn incoming<'a>(&'a self) -> Incoming<'a> {
+ Incoming { listener: self }
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixListener {
+ fn as_raw_fd(&self) -> RawFd {
+ *self.0.as_inner()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixListener {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
+ UnixListener(Socket::from_inner(fd))
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixListener {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_inner()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> IntoIterator for &'a UnixListener {
+ type Item = io::Result<UnixStream>;
+ type IntoIter = Incoming<'a>;
+
+ fn into_iter(self) -> Incoming<'a> {
+ self.incoming()
+ }
+}
+
+/// An iterator over incoming connections to a [`UnixListener`].
+///
+/// It will never return [`None`].
+///
+/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+/// [`UnixListener`]: struct.UnixListener.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+/// // ...
+/// }
+///
+/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+///
+/// for stream in listener.incoming() {
+/// match stream {
+/// Ok(stream) => {
+/// thread::spawn(|| handle_client(stream));
+/// }
+/// Err(err) => {
+/// break;
+/// }
+/// }
+/// }
+/// ```
+#[derive(Debug)]
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct Incoming<'a> {
+ listener: &'a UnixListener,
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> Iterator for Incoming<'a> {
+ type Item = io::Result<UnixStream>;
+
+ fn next(&mut self) -> Option<io::Result<UnixStream>> {
+ Some(self.listener.accept().map(|s| s.0))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (usize::max_value(), None)
+ }
+}
+
+/// A Unix datagram socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixDatagram;
+///
+/// let socket = UnixDatagram::bind("/path/to/my/socket").unwrap();
+/// socket.send_to(b"hello world", "/path/to/other/socket").unwrap();
+/// let mut buf = [0; 100];
+/// let (count, address) = socket.recv_from(&mut buf).unwrap();
+/// println!("socket {:?} sent {:?}", address, &buf[..count]);
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixDatagram(Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for UnixDatagram {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let mut builder = fmt.debug_struct("UnixDatagram");
+ builder.field("fd", self.0.as_inner());
+ if let Ok(addr) = self.local_addr() {
+ builder.field("local", &addr);
+ }
+ if let Ok(addr) = self.peer_addr() {
+ builder.field("peer", &addr);
+ }
+ builder.finish()
+ }
+}
+
+impl UnixDatagram {
+ /// Creates a Unix datagram socket bound to the given path.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = match UnixDatagram::bind("/path/to/the/socket") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't bind: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
+ fn inner(path: &Path) -> io::Result<UnixDatagram> {
+ unsafe {
+ let socket = UnixDatagram::unbound()?;
+ let (addr, len) = sockaddr_un(path)?;
+
+ cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?;
+
+ Ok(socket)
+ }
+ }
+ inner(path.as_ref())
+ }
+
+ /// Creates a Unix Datagram socket which is not bound to any address.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = match UnixDatagram::unbound() {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't unbound: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn unbound() -> io::Result<UnixDatagram> {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?;
+ Ok(UnixDatagram(inner))
+ }
+
+ /// Create an unnamed pair of connected sockets.
+ ///
+ /// Returns two `UnixDatagrams`s which are connected to each other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let (sock1, sock2) = match UnixDatagram::pair() {
+ /// Ok((sock1, sock2)) => (sock1, sock2),
+ /// Err(e) => {
+ /// println!("Couldn't unbound: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
+ let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?;
+ Ok((UnixDatagram(i1), UnixDatagram(i2)))
+ }
+
+ /// Connects the socket to the specified address.
+ ///
+ /// The [`send`] method may be used to send data to the specified address.
+ /// [`recv`] and [`recv_from`] will only receive data from that address.
+ ///
+ /// [`send`]: #method.send
+ /// [`recv`]: #method.recv
+ /// [`recv_from`]: #method.recv_from
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// match sock.connect("/path/to/the/socket") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+ fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> {
+ unsafe {
+ let (addr, len) = sockaddr_un(path)?;
+
+ cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?;
+
+ Ok(())
+ }
+ }
+ inner(self, path.as_ref())
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixDatagram` is a reference to the same socket that this
+ /// object references. Both handles can be used to accept incoming
+ /// connections and options set on one side will affect the other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
+ ///
+ /// let sock_copy = sock.try_clone().expect("try_clone failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn try_clone(&self) -> io::Result<UnixDatagram> {
+ self.0.duplicate().map(UnixDatagram)
+ }
+
+ /// Returns the address of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
+ ///
+ /// let addr = sock.local_addr().expect("Couldn't get local address");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+ }
+
+ /// Returns the address of this socket's peer.
+ ///
+ /// The [`connect`] method will connect the socket to a peer.
+ ///
+ /// [`connect`]: #method.connect
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.connect("/path/to/the/socket").unwrap();
+ ///
+ /// let addr = sock.peer_addr().expect("Couldn't get peer address");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
+ }
+
+ /// Receives data from the socket.
+ ///
+ /// On success, returns the number of bytes read and the address from
+ /// whence the data came.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// let mut buf = vec![0; 10];
+ /// match sock.recv_from(buf.as_mut_slice()) {
+ /// Ok((size, sender)) => println!("received {} bytes from {:?}", size, sender),
+ /// Err(e) => println!("recv_from function failed: {:?}", e),
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ let mut count = 0;
+ let addr = SocketAddr::new(|addr, len| {
+ unsafe {
+ count = libc::recvfrom(*self.0.as_inner(),
+ buf.as_mut_ptr() as *mut _,
+ buf.len(),
+ 0,
+ addr,
+ len);
+ if count > 0 {
+ 1
+ } else if count == 0 {
+ 0
+ } else {
+ -1
+ }
+ }
+ })?;
+
+ Ok((count as usize, addr))
+ }
+
+ /// Receives data from the socket.
+ ///
+ /// On success, returns the number of bytes read.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
+ /// let mut buf = vec![0; 10];
+ /// sock.recv(buf.as_mut_slice()).expect("recv function failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ /// Sends data on the socket to the specified address.
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
+ fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result<usize> {
+ unsafe {
+ let (addr, len) = sockaddr_un(path)?;
+
+ let count = cvt(libc::sendto(*d.0.as_inner(),
+ buf.as_ptr() as *const _,
+ buf.len(),
+ MSG_NOSIGNAL,
+ &addr as *const _ as *const _,
+ len))?;
+ Ok(count as usize)
+ }
+ }
+ inner(self, buf, path.as_ref())
+ }
+
+ /// Sends data on the socket to the socket's peer.
+ ///
+ /// The peer address may be set by the `connect` method, and this method
+ /// will return an error if the socket has not already been connected.
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.connect("/some/sock").expect("Couldn't connect");
+ /// sock.send(b"omelette au fromage").expect("send_to function failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ /// Sets the read timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will
+ /// block indefinitely. An [`Err`] is returned if the zero [`Duration`]
+ /// is passed to this method.
+ ///
+ /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+ /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
+ /// [`recv`]: #method.recv
+ /// [`recv_from`]: #method.recv_from
+ /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixDatagram::unbound().unwrap();
+ /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+ self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
+ }
+
+ /// Sets the write timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will
+ /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method.
+ ///
+ /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+ /// [`send`]: #method.send
+ /// [`send_to`]: #method.send_to
+ /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.set_write_timeout(Some(Duration::new(1, 0)))
+ /// .expect("set_write_timeout function failed");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixDatagram::unbound().unwrap();
+ /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+ self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
+ }
+
+ /// Returns the read timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed");
+ /// assert_eq!(sock.read_timeout().unwrap(), Some(Duration::new(1, 0)));
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.timeout(libc::SO_RCVTIMEO)
+ }
+
+ /// Returns the write timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.set_write_timeout(Some(Duration::new(1, 0)))
+ /// .expect("set_write_timeout function failed");
+ /// assert_eq!(sock.write_timeout().unwrap(), Some(Duration::new(1, 0)));
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.timeout(libc::SO_SNDTIMEO)
+ }
+
+ /// Moves the socket into or out of nonblocking mode.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.set_nonblocking(true).expect("set_nonblocking function failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// if let Ok(Some(err)) = sock.take_error() {
+ /// println!("Got error: {:?}", err);
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0.take_error()
+ }
+
+ /// Shut down the read, write, or both halves of this connection.
+ ///
+ /// This function will cause all pending and future I/O calls on the
+ /// specified portions to immediately return with an appropriate value
+ /// (see the documentation of [`Shutdown`]).
+ ///
+ /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::net::Shutdown;
+ ///
+ /// let sock = UnixDatagram::unbound().unwrap();
+ /// sock.shutdown(Shutdown::Both).expect("shutdown function failed");
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.0.shutdown(how)
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixDatagram {
+ fn as_raw_fd(&self) -> RawFd {
+ *self.0.as_inner()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixDatagram {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
+ UnixDatagram(Socket::from_inner(fd))
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixDatagram {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_inner()
+ }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod test {
+ use thread;
+ use io::{self, ErrorKind};
+ use io::prelude::*;
+ use time::Duration;
+ use sys_common::io::test::tmpdir;
+
+ use super::*;
+
+ macro_rules! or_panic {
+ ($e:expr) => {
+ match $e {
+ Ok(e) => e,
+ Err(e) => panic!("{}", e),
+ }
+ }
+ }
+
+ #[test]
+ fn basic() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+ let msg1 = b"hello";
+ let msg2 = b"world!";
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+ let thread = thread::spawn(move || {
+ let mut stream = or_panic!(listener.accept()).0;
+ let mut buf = [0; 5];
+ or_panic!(stream.read(&mut buf));
+ assert_eq!(&msg1[..], &buf[..]);
+ or_panic!(stream.write_all(msg2));
+ });
+
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ assert_eq!(Some(&*socket_path),
+ stream.peer_addr().unwrap().as_pathname());
+ or_panic!(stream.write_all(msg1));
+ let mut buf = vec![];
+ or_panic!(stream.read_to_end(&mut buf));
+ assert_eq!(&msg2[..], &buf[..]);
+ drop(stream);
+
+ thread.join().unwrap();
+ }
+
+ #[test]
+ fn pair() {
+ let msg1 = b"hello";
+ let msg2 = b"world!";
+
+ let (mut s1, mut s2) = or_panic!(UnixStream::pair());
+ let thread = thread::spawn(move || {
+ // s1 must be moved in or the test will hang!
+ let mut buf = [0; 5];
+ or_panic!(s1.read(&mut buf));
+ assert_eq!(&msg1[..], &buf[..]);
+ or_panic!(s1.write_all(msg2));
+ });
+
+ or_panic!(s2.write_all(msg1));
+ let mut buf = vec![];
+ or_panic!(s2.read_to_end(&mut buf));
+ assert_eq!(&msg2[..], &buf[..]);
+ drop(s2);
+
+ thread.join().unwrap();
+ }
+
+ #[test]
+ fn try_clone() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+ let msg1 = b"hello";
+ let msg2 = b"world";
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+ let thread = thread::spawn(move || {
+ let mut stream = or_panic!(listener.accept()).0;
+ or_panic!(stream.write_all(msg1));
+ or_panic!(stream.write_all(msg2));
+ });
+
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ let mut stream2 = or_panic!(stream.try_clone());
+
+ let mut buf = [0; 5];
+ or_panic!(stream.read(&mut buf));
+ assert_eq!(&msg1[..], &buf[..]);
+ or_panic!(stream2.read(&mut buf));
+ assert_eq!(&msg2[..], &buf[..]);
+
+ thread.join().unwrap();
+ }
+
+ #[test]
+ fn iter() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+ let thread = thread::spawn(move || {
+ for stream in listener.incoming().take(2) {
+ let mut stream = or_panic!(stream);
+ let mut buf = [0];
+ or_panic!(stream.read(&mut buf));
+ }
+ });
+
+ for _ in 0..2 {
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ or_panic!(stream.write_all(&[0]));
+ }
+
+ thread.join().unwrap();
+ }
+
+ #[test]
+ fn long_path() {
+ let dir = tmpdir();
+ let socket_path = dir.path()
+ .join("asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\
+ sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf");
+ match UnixStream::connect(&socket_path) {
+ Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+ Err(e) => panic!("unexpected error {}", e),
+ Ok(_) => panic!("unexpected success"),
+ }
+
+ match UnixListener::bind(&socket_path) {
+ Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+ Err(e) => panic!("unexpected error {}", e),
+ Ok(_) => panic!("unexpected success"),
+ }
+
+ match UnixDatagram::bind(&socket_path) {
+ Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+ Err(e) => panic!("unexpected error {}", e),
+ Ok(_) => panic!("unexpected success"),
+ }
+ }
+
+ #[test]
+ fn timeouts() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let _listener = or_panic!(UnixListener::bind(&socket_path));
+
+ let stream = or_panic!(UnixStream::connect(&socket_path));
+ let dur = Duration::new(15410, 0);
+
+ assert_eq!(None, or_panic!(stream.read_timeout()));
+
+ or_panic!(stream.set_read_timeout(Some(dur)));
+ assert_eq!(Some(dur), or_panic!(stream.read_timeout()));
+
+ assert_eq!(None, or_panic!(stream.write_timeout()));
+
+ or_panic!(stream.set_write_timeout(Some(dur)));
+ assert_eq!(Some(dur), or_panic!(stream.write_timeout()));
+
+ or_panic!(stream.set_read_timeout(None));
+ assert_eq!(None, or_panic!(stream.read_timeout()));
+
+ or_panic!(stream.set_write_timeout(None));
+ assert_eq!(None, or_panic!(stream.write_timeout()));
+ }
+
+ #[test]
+ fn test_read_timeout() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let _listener = or_panic!(UnixListener::bind(&socket_path));
+
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut buf = [0; 10];
+ let kind = stream.read(&mut buf).err().expect("expected error").kind();
+ assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut);
+ }
+
+ #[test]
+ fn test_read_with_timeout() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+
+ let mut stream = or_panic!(UnixStream::connect(&socket_path));
+ or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut other_end = or_panic!(listener.accept()).0;
+ or_panic!(other_end.write_all(b"hello world"));
+
+ let mut buf = [0; 11];
+ or_panic!(stream.read(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+
+ let kind = stream.read(&mut buf).err().expect("expected error").kind();
+ assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut);
+ }
+
+ // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+ // when passed zero Durations
+ #[test]
+ fn test_unix_stream_timeout_zero_duration() {
+ let dir = tmpdir();
+ let socket_path = dir.path().join("sock");
+
+ let listener = or_panic!(UnixListener::bind(&socket_path));
+ let stream = or_panic!(UnixStream::connect(&socket_path));
+
+ let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+ let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+ drop(listener);
+ }
+
+ #[test]
+ fn test_unix_datagram() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+ let path2 = dir.path().join("sock2");
+
+ let sock1 = or_panic!(UnixDatagram::bind(&path1));
+ let sock2 = or_panic!(UnixDatagram::bind(&path2));
+
+ let msg = b"hello world";
+ or_panic!(sock1.send_to(msg, &path2));
+ let mut buf = [0; 11];
+ or_panic!(sock2.recv_from(&mut buf));
+ assert_eq!(msg, &buf[..]);
+ }
+
+ #[test]
+ fn test_unnamed_unix_datagram() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+
+ let sock1 = or_panic!(UnixDatagram::bind(&path1));
+ let sock2 = or_panic!(UnixDatagram::unbound());
+
+ let msg = b"hello world";
+ or_panic!(sock2.send_to(msg, &path1));
+ let mut buf = [0; 11];
+ let (usize, addr) = or_panic!(sock1.recv_from(&mut buf));
+ assert_eq!(usize, 11);
+ assert!(addr.is_unnamed());
+ assert_eq!(msg, &buf[..]);
+ }
+
+ #[test]
+ fn test_connect_unix_datagram() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+ let path2 = dir.path().join("sock2");
+
+ let bsock1 = or_panic!(UnixDatagram::bind(&path1));
+ let bsock2 = or_panic!(UnixDatagram::bind(&path2));
+ let sock = or_panic!(UnixDatagram::unbound());
+ or_panic!(sock.connect(&path1));
+
+ // Check send()
+ let msg = b"hello there";
+ or_panic!(sock.send(msg));
+ let mut buf = [0; 11];
+ let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf));
+ assert_eq!(usize, 11);
+ assert!(addr.is_unnamed());
+ assert_eq!(msg, &buf[..]);
+
+ // Changing default socket works too
+ or_panic!(sock.connect(&path2));
+ or_panic!(sock.send(msg));
+ or_panic!(bsock2.recv_from(&mut buf));
+ }
+
+ #[test]
+ fn test_unix_datagram_recv() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock1");
+
+ let sock1 = or_panic!(UnixDatagram::bind(&path1));
+ let sock2 = or_panic!(UnixDatagram::unbound());
+ or_panic!(sock2.connect(&path1));
+
+ let msg = b"hello world";
+ or_panic!(sock2.send(msg));
+ let mut buf = [0; 11];
+ let size = or_panic!(sock1.recv(&mut buf));
+ assert_eq!(size, 11);
+ assert_eq!(msg, &buf[..]);
+ }
+
+ #[test]
+ fn datagram_pair() {
+ let msg1 = b"hello";
+ let msg2 = b"world!";
+
+ let (s1, s2) = or_panic!(UnixDatagram::pair());
+ let thread = thread::spawn(move || {
+ // s1 must be moved in or the test will hang!
+ let mut buf = [0; 5];
+ or_panic!(s1.recv(&mut buf));
+ assert_eq!(&msg1[..], &buf[..]);
+ or_panic!(s1.send(msg2));
+ });
+
+ or_panic!(s2.send(msg1));
+ let mut buf = [0; 6];
+ or_panic!(s2.recv(&mut buf));
+ assert_eq!(&msg2[..], &buf[..]);
+ drop(s2);
+
+ thread.join().unwrap();
+ }
+
+ // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+ // when passed zero Durations
+ #[test]
+ fn test_unix_datagram_timeout_zero_duration() {
+ let dir = tmpdir();
+ let path = dir.path().join("sock");
+
+ let datagram = or_panic!(UnixDatagram::bind(&path));
+
+ let result = datagram.set_write_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+ let result = datagram.set_read_timeout(Some(Duration::new(0, 0)));
+ let err = result.unwrap_err();
+ assert_eq!(err.kind(), ErrorKind::InvalidInput);
+ }
+
+ #[test]
+ fn abstract_namespace_not_allowed() {
+ assert!(UnixStream::connect("\0asdf").is_err());
+ }
+}
diff --git a/ctr-std/src/sys/unix/ext/process.rs b/ctr-std/src/sys/unix/ext/process.rs
new file mode 100644
index 0000000..21630ae
--- /dev/null
+++ b/ctr-std/src/sys/unix/ext/process.rs
@@ -0,0 +1,203 @@
+// 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.
+
+//! Unix-specific extensions to primitives in the `std::process` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use io;
+use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
+use process;
+use sys;
+use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
+
+/// Unix-specific extensions to the [`process::Command`] builder.
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait CommandExt {
+ /// Sets the child process's user id. This translates to a
+ /// `setuid` call in the child process. Failure in the `setuid`
+ /// call will cause the spawn to fail.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn uid(&mut self, id: u32) -> &mut process::Command;
+
+ /// Similar to `uid`, but sets the group id of the child process. This has
+ /// the same semantics as the `uid` field.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn gid(&mut self, id: u32) -> &mut process::Command;
+
+ /// Schedules a closure to be run just before the `exec` function is
+ /// invoked.
+ ///
+ /// The closure is allowed to return an I/O error whose OS error code will
+ /// be communicated back to the parent and returned as an error from when
+ /// the spawn was requested.
+ ///
+ /// Multiple closures can be registered and they will be called in order of
+ /// their registration. If a closure returns `Err` then no further closures
+ /// will be called and the spawn operation will immediately return with a
+ /// failure.
+ ///
+ /// # Notes
+ ///
+ /// This closure will be run in the context of the child process after a
+ /// `fork`. This primarily means that any modifications made to memory on
+ /// behalf of this closure will **not** be visible to the parent process.
+ /// This is often a very constrained environment where normal operations
+ /// like `malloc` or acquiring a mutex are not guaranteed to work (due to
+ /// other threads perhaps still running when the `fork` was run).
+ ///
+ /// When this closure is run, aspects such as the stdio file descriptors and
+ /// working directory have successfully been changed, so output to these
+ /// locations may not appear where intended.
+ #[stable(feature = "process_exec", since = "1.15.0")]
+ fn before_exec<F>(&mut self, f: F) -> &mut process::Command
+ where F: FnMut() -> io::Result<()> + Send + Sync + 'static;
+
+ /// Performs all the required setup by this `Command`, followed by calling
+ /// the `execvp` syscall.
+ ///
+ /// On success this function will not return, and otherwise it will return
+ /// an error indicating why the exec (or another part of the setup of the
+ /// `Command`) failed.
+ ///
+ /// `exec` not returning has the same implications as calling
+ /// [`process::exit`] – no destructors on the current stack or any other
+ /// thread’s stack will be run. Therefore, it is recommended to only call
+ /// `exec` at a point where it is fine to not run any destructors. Note,
+ /// that the `execvp` syscall independently guarantees that all memory is
+ /// freed and all file descriptors with the `CLOEXEC` option (set by default
+ /// on all file descriptors opened by the standard library) are closed.
+ ///
+ /// This function, unlike `spawn`, will **not** `fork` the process to create
+ /// a new child. Like spawn, however, the default behavior for the stdio
+ /// descriptors will be to inherited from the current process.
+ ///
+ /// [`process::exit`]: ../../../process/fn.exit.html
+ ///
+ /// # Notes
+ ///
+ /// The process may be in a "broken state" if this function returns in
+ /// error. For example the working directory, environment variables, signal
+ /// handling settings, various user/group information, or aspects of stdio
+ /// file descriptors may have changed. If a "transactional spawn" is
+ /// required to gracefully handle errors it is recommended to use the
+ /// cross-platform `spawn` instead.
+ #[stable(feature = "process_exec2", since = "1.9.0")]
+ fn exec(&mut self) -> io::Error;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl CommandExt for process::Command {
+ fn uid(&mut self, id: u32) -> &mut process::Command {
+ self.as_inner_mut().uid(id);
+ self
+ }
+
+ fn gid(&mut self, id: u32) -> &mut process::Command {
+ self.as_inner_mut().gid(id);
+ self
+ }
+
+ fn before_exec<F>(&mut self, f: F) -> &mut process::Command
+ where F: FnMut() -> io::Result<()> + Send + Sync + 'static
+ {
+ self.as_inner_mut().before_exec(Box::new(f));
+ self
+ }
+
+ fn exec(&mut self) -> io::Error {
+ self.as_inner_mut().exec(sys::process::Stdio::Inherit)
+ }
+}
+
+/// Unix-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait ExitStatusExt {
+ /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
+ /// a process.
+ #[stable(feature = "exit_status_from", since = "1.12.0")]
+ fn from_raw(raw: i32) -> Self;
+
+ /// If the process was terminated by a signal, returns that signal.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn signal(&self) -> Option<i32>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ExitStatusExt for process::ExitStatus {
+ fn from_raw(raw: i32) -> Self {
+ process::ExitStatus::from_inner(From::from(raw))
+ }
+
+ fn signal(&self) -> Option<i32> {
+ self.as_inner().signal()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawFd for process::Stdio {
+ unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
+ let fd = sys::fd::FileDesc::new(fd);
+ let io = sys::process::Stdio::Fd(fd);
+ process::Stdio::from_inner(io)
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdin {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdout {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStderr {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdin {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdout {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStderr {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+/// Returns the OS-assigned process identifier associated with this process's parent.
+#[stable(feature = "unix_ppid", since = "1.27.0")]
+pub fn parent_id() -> u32 {
+ ::sys::os::getppid()
+}
diff --git a/ctr-std/src/sys/unix/ext/raw.rs b/ctr-std/src/sys/unix/ext/raw.rs
index a51f5c1..7972990 100644
--- a/ctr-std/src/sys/unix/ext/raw.rs
+++ b/ctr-std/src/sys/unix/ext/raw.rs
@@ -16,13 +16,18 @@
the standard library, the `libc` crate on \
crates.io should be used instead for the correct \
definitions")]
-#![allow(deprecated, warnings)]
+#![allow(deprecated)]
-#[allow(missing_docs)]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type uid_t = u32;
-
-#[allow(missing_docs)]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type gid_t = u32;
-
-#[allow(missing_docs)]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type pid_t = i32;
+
+#[doc(inline)]
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub use sys::platform::raw::pthread_t;
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use sys::platform::raw::{dev_t, ino_t, mode_t, nlink_t, off_t, blksize_t};
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use sys::platform::raw::{blkcnt_t, time_t};
diff --git a/ctr-std/src/sys/unix/ext/thread.rs b/ctr-std/src/sys/unix/ext/thread.rs
new file mode 100644
index 0000000..8dadf29
--- /dev/null
+++ b/ctr-std/src/sys/unix/ext/thread.rs
@@ -0,0 +1,51 @@
+// 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.
+
+//! Unix-specific extensions to primitives in the `std::thread` module.
+
+#![stable(feature = "thread_extensions", since = "1.9.0")]
+
+#[allow(deprecated)]
+use os::unix::raw::pthread_t;
+use sys_common::{AsInner, IntoInner};
+use thread::JoinHandle;
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+#[allow(deprecated)]
+pub type RawPthread = pthread_t;
+
+/// Unix-specific extensions to [`thread::JoinHandle`].
+///
+/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+pub trait JoinHandleExt {
+ /// Extracts the raw pthread_t without taking ownership
+ #[stable(feature = "thread_extensions", since = "1.9.0")]
+ fn as_pthread_t(&self) -> RawPthread;
+
+ /// Consumes the thread, returning the raw pthread_t
+ ///
+ /// This function **transfers ownership** of the underlying pthread_t to
+ /// the caller. Callers are then the unique owners of the pthread_t and
+ /// must either detach or join the pthread_t once it's no longer needed.
+ #[stable(feature = "thread_extensions", since = "1.9.0")]
+ fn into_pthread_t(self) -> RawPthread;
+}
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> JoinHandleExt for JoinHandle<T> {
+ fn as_pthread_t(&self) -> RawPthread {
+ self.as_inner().id() as RawPthread
+ }
+
+ fn into_pthread_t(self) -> RawPthread {
+ self.into_inner().into_id() as RawPthread
+ }
+}