summaryrefslogtreecommitdiffstats
path: root/library/std/src/os/unix
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/os/unix')
-rw-r--r--library/std/src/os/unix/ffi/mod.rs42
-rw-r--r--library/std/src/os/unix/ffi/os_str.rs70
-rw-r--r--library/std/src/os/unix/fs.rs1022
-rw-r--r--library/std/src/os/unix/io/fd.rs8
-rw-r--r--library/std/src/os/unix/io/fd/tests.rs11
-rw-r--r--library/std/src/os/unix/io/mod.rs86
-rw-r--r--library/std/src/os/unix/io/raw.rs6
-rw-r--r--library/std/src/os/unix/mod.rs126
-rw-r--r--library/std/src/os/unix/net/addr.rs350
-rw-r--r--library/std/src/os/unix/net/ancillary.rs674
-rw-r--r--library/std/src/os/unix/net/datagram.rs987
-rw-r--r--library/std/src/os/unix/net/listener.rs385
-rw-r--r--library/std/src/os/unix/net/mod.rs26
-rw-r--r--library/std/src/os/unix/net/stream.rs711
-rw-r--r--library/std/src/os/unix/net/tests.rs753
-rw-r--r--library/std/src/os/unix/process.rs466
-rw-r--r--library/std/src/os/unix/raw.rs33
-rw-r--r--library/std/src/os/unix/thread.rs41
-rw-r--r--library/std/src/os/unix/ucred.rs136
-rw-r--r--library/std/src/os/unix/ucred/tests.rs39
20 files changed, 5972 insertions, 0 deletions
diff --git a/library/std/src/os/unix/ffi/mod.rs b/library/std/src/os/unix/ffi/mod.rs
new file mode 100644
index 000000000..5b49f5076
--- /dev/null
+++ b/library/std/src/os/unix/ffi/mod.rs
@@ -0,0 +1,42 @@
+//! Unix-specific extensions to primitives in the [`std::ffi`] module.
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::unix::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::unix::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! [`std::ffi`]: crate::ffi
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+mod os_str;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::os_str::{OsStrExt, OsStringExt};
diff --git a/library/std/src/os/unix/ffi/os_str.rs b/library/std/src/os/unix/ffi/os_str.rs
new file mode 100644
index 000000000..650f712bc
--- /dev/null
+++ b/library/std/src/os/unix/ffi/os_str.rs
@@ -0,0 +1,70 @@
+use crate::ffi::{OsStr, OsString};
+use crate::mem;
+use crate::sealed::Sealed;
+use crate::sys::os_str::Buf;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+// Note: this file is currently reused in other `std::os::{platform}::ffi` modules to reduce duplication.
+// Keep this in mind when applying changes to this file that only apply to `unix`.
+
+/// Platform-specific extensions to [`OsString`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStringExt: Sealed {
+ /// Creates an [`OsString`] from a byte vector.
+ ///
+ /// See the module documentation for an example.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn from_vec(vec: Vec<u8>) -> Self;
+
+ /// Yields the underlying byte vector of this [`OsString`].
+ ///
+ /// See the module documentation for an example.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn into_vec(self) -> Vec<u8>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStringExt for OsString {
+ #[inline]
+ fn from_vec(vec: Vec<u8>) -> OsString {
+ FromInner::from_inner(Buf { inner: vec })
+ }
+ #[inline]
+ fn into_vec(self) -> Vec<u8> {
+ self.into_inner().inner
+ }
+}
+
+/// Platform-specific extensions to [`OsStr`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStrExt: Sealed {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ /// Creates an [`OsStr`] from a byte slice.
+ ///
+ /// See the module documentation for an example.
+ fn from_bytes(slice: &[u8]) -> &Self;
+
+ /// Gets the underlying byte view of the [`OsStr`] slice.
+ ///
+ /// See the module documentation for an example.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_bytes(&self) -> &[u8];
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStrExt for OsStr {
+ #[inline]
+ fn from_bytes(slice: &[u8]) -> &OsStr {
+ unsafe { mem::transmute(slice) }
+ }
+ #[inline]
+ fn as_bytes(&self) -> &[u8] {
+ &self.as_inner().inner
+ }
+}
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
new file mode 100644
index 000000000..3fc6cc44c
--- /dev/null
+++ b/library/std/src/os/unix/fs.rs
@@ -0,0 +1,1022 @@
+//! Unix-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use super::platform::fs::MetadataExt as _;
+use crate::fs::{self, OpenOptions, Permissions};
+use crate::io;
+use crate::os::unix::io::{AsFd, AsRawFd};
+use crate::path::Path;
+use crate::sys;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner};
+// Used for `File::read` on intra-doc links
+use crate::ffi::OsStr;
+use crate::sealed::Sealed;
+#[allow(unused_imports)]
+use io::{Read, Write};
+
+/// Unix-specific extensions to [`fs::File`].
+#[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`]: fs::File::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 {num_bytes_read} bytes: {buf:?}");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "file_offset", since = "1.15.0")]
+ fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+ /// Reads the exact number of byte required to fill `buf` from the given offset.
+ ///
+ /// 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.
+ ///
+ /// Similar to [`io::Read::read_exact`] but uses [`read_at`] instead of `read`.
+ ///
+ /// [`read_at`]: FileExt::read_at
+ ///
+ /// # Errors
+ ///
+ /// If this function encounters an error of the kind
+ /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
+ /// will continue.
+ ///
+ /// If this function encounters an "end of file" before completely filling
+ /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
+ /// The contents of `buf` are unspecified in this case.
+ ///
+ /// If any other read error is encountered then this function immediately
+ /// returns. The contents of `buf` are unspecified in this case.
+ ///
+ /// If this function returns an error, it is unspecified how many bytes it
+ /// has read, but it will never read more than would be necessary to
+ /// completely fill the buffer.
+ ///
+ /// # 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 exactly 8 bytes from the offset 10.
+ /// file.read_exact_at(&mut buf, 10)?;
+ /// println!("read {} bytes: {:?}", buf.len(), buf);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+ fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
+ while !buf.is_empty() {
+ match self.read_at(buf, offset) {
+ Ok(0) => break,
+ Ok(n) => {
+ let tmp = buf;
+ buf = &mut tmp[n..];
+ offset += n as u64;
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+ if !buf.is_empty() {
+ Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer",))
+ } else {
+ Ok(())
+ }
+ }
+
+ /// 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`]: fs::File::write
+ ///
+ /// # 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>;
+
+ /// Attempts to write an entire buffer starting from a given offset.
+ ///
+ /// 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.
+ ///
+ /// This method will continuously call [`write_at`] until there is no more data
+ /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
+ /// returned. This method will not return until the entire buffer has been
+ /// successfully written or such an error occurs. The first error that is
+ /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
+ /// returned.
+ ///
+ /// # Errors
+ ///
+ /// This function will return the first error of
+ /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
+ ///
+ /// [`write_at`]: FileExt::write_at
+ ///
+ /// # 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_all_at(b"sushi", 10)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+ fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
+ while !buf.is_empty() {
+ match self.write_at(buf, offset) {
+ Ok(0) => {
+ return Err(io::const_io_error!(
+ io::ErrorKind::WriteZero,
+ "failed to write whole buffer",
+ ));
+ }
+ Ok(n) => {
+ buf = &buf[n..];
+ offset += n as u64
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+ Ok(())
+ }
+}
+
+#[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`].
+#[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: {:o}", 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`].
+#[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 an `OpenOptions::open` 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 system's `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(rustc_private)]
+ /// 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`].
+#[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 last access time of the file, in seconds since Unix Epoch.
+ ///
+ /// # 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 last access time of the file, in nanoseconds since [`atime`].
+ ///
+ /// [`atime`]: MetadataExt::atime
+ ///
+ /// # 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 last modification time of the file, in seconds since Unix Epoch.
+ ///
+ /// # 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 last modification time of the file, in nanoseconds since [`mtime`].
+ ///
+ /// [`mtime`]: MetadataExt::mtime
+ ///
+ /// # 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 last status change time of the file, in seconds since Unix Epoch.
+ ///
+ /// # 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 last status change time of the file, in nanoseconds since [`ctime`].
+ ///
+ /// [`ctime`]: MetadataExt::ctime
+ ///
+ /// # 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 block size 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 block_size = 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;
+ #[cfg(target_os = "vxworks")]
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn attrib(&self) -> u8;
+}
+
+#[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()
+ }
+ #[cfg(target_os = "vxworks")]
+ fn attrib(&self) -> u8 {
+ self.st_attrib()
+ }
+}
+
+/// Unix-specific extensions for [`fs::FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+pub trait FileTypeExt {
+ /// Returns `true` if 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 `true` if 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 `true` if 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 `true` if 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`].
+#[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()
+ }
+}
+
+/// Sealed Unix-specific extension methods for [`fs::DirEntry`].
+#[unstable(feature = "dir_entry_ext2", issue = "85573")]
+pub trait DirEntryExt2: Sealed {
+ /// Returns a reference to the underlying `OsStr` of this entry's filename.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(dir_entry_ext2)]
+ /// use std::os::unix::fs::DirEntryExt2;
+ /// use std::{fs, io};
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?;
+ /// entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));
+ ///
+ /// for p in entries {
+ /// println!("{p:?}");
+ /// }
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ fn file_name_ref(&self) -> &OsStr;
+}
+
+/// Allows extension traits within `std`.
+#[unstable(feature = "sealed", issue = "none")]
+impl Sealed for fs::DirEntry {}
+
+#[unstable(feature = "dir_entry_ext2", issue = "85573")]
+impl DirEntryExt2 for fs::DirEntry {
+ fn file_name_ref(&self) -> &OsStr {
+ self.as_inner().file_name_os_str()
+ }
+}
+
+/// Creates a new symbolic link on the filesystem.
+///
+/// The `link` path will be a symbolic link pointing to the `original` path.
+///
+/// # 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>>(original: P, link: Q) -> io::Result<()> {
+ sys::fs::symlink(original.as_ref(), link.as_ref())
+}
+
+/// Unix-specific extensions to [`fs::DirBuilder`].
+#[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
+ }
+}
+
+/// Change the owner and group of the specified path.
+///
+/// Specifying either the uid or gid as `None` will leave it unchanged.
+///
+/// Changing the owner typically requires privileges, such as root or a specific capability.
+/// Changing the group typically requires either being the owner and a member of the group, or
+/// having privileges.
+///
+/// If called on a symbolic link, this will change the owner and group of the link target. To
+/// change the owner and group of the link itself, see [`lchown`].
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chown)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::chown("/sandbox", Some(0), Some(0))?;
+/// Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_chown", issue = "88989")]
+pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
+ sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
+}
+
+/// Change the owner and group of the file referenced by the specified open file descriptor.
+///
+/// For semantics and required privileges, see [`chown`].
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chown)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// let f = std::fs::File::open("/file")?;
+/// fs::fchown(&f, Some(0), Some(0))?;
+/// Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_chown", issue = "88989")]
+pub fn fchown<F: AsFd>(fd: F, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
+ sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
+}
+
+/// Change the owner and group of the specified path, without dereferencing symbolic links.
+///
+/// Identical to [`chown`], except that if called on a symbolic link, this will change the owner
+/// and group of the link itself rather than the owner and group of the link target.
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chown)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::lchown("/symlink", Some(0), Some(0))?;
+/// Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_chown", issue = "88989")]
+pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::Result<()> {
+ sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX))
+}
+
+/// Change the root directory of the current process to the specified path.
+///
+/// This typically requires privileges, such as root or a specific capability.
+///
+/// This does not change the current working directory; you should call
+/// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::chroot("/sandbox")?;
+/// std::env::set_current_dir("/")?;
+/// // continue working in sandbox
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "unix_chroot", since = "1.56.0")]
+#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
+pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
+ sys::fs::chroot(dir.as_ref())
+}
diff --git a/library/std/src/os/unix/io/fd.rs b/library/std/src/os/unix/io/fd.rs
new file mode 100644
index 000000000..d4cb69645
--- /dev/null
+++ b/library/std/src/os/unix/io/fd.rs
@@ -0,0 +1,8 @@
+//! Owned and borrowed file descriptors.
+
+// Tests for this module
+#[cfg(test)]
+mod tests;
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub use crate::os::fd::owned::*;
diff --git a/library/std/src/os/unix/io/fd/tests.rs b/library/std/src/os/unix/io/fd/tests.rs
new file mode 100644
index 000000000..84d2a7a1a
--- /dev/null
+++ b/library/std/src/os/unix/io/fd/tests.rs
@@ -0,0 +1,11 @@
+use crate::mem::size_of;
+use crate::os::unix::io::RawFd;
+
+#[test]
+fn test_raw_fd_layout() {
+ // `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start`
+ // and `rustc_layout_scalar_valid_range_end`, with values that depend on
+ // the bit width of `RawFd`. If this ever changes, those values will need
+ // to be updated.
+ assert_eq!(size_of::<RawFd>(), 4);
+}
diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs
new file mode 100644
index 000000000..3ab5606f8
--- /dev/null
+++ b/library/std/src/os/unix/io/mod.rs
@@ -0,0 +1,86 @@
+//! Unix-specific extensions to general I/O primitives.
+//!
+//! Just like raw pointers, raw file descriptors point to resources with
+//! dynamic lifetimes, and they can dangle if they outlive their resources
+//! or be forged if they're created from invalid values.
+//!
+//! This module provides three types for representing file descriptors,
+//! with different ownership properties: raw, borrowed, and owned, which are
+//! analogous to types used for representing pointers:
+//!
+//! | Type | Analogous to |
+//! | ------------------ | ------------ |
+//! | [`RawFd`] | `*const _` |
+//! | [`BorrowedFd<'a>`] | `&'a _` |
+//! | [`OwnedFd`] | `Box<_>` |
+//!
+//! Like raw pointers, `RawFd` values are primitive values. And in new code,
+//! they should be considered unsafe to do I/O on (analogous to dereferencing
+//! them). Rust did not always provide this guidance, so existing code in the
+//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Once the
+//! `io_safety` feature is stable, libraries will be encouraged to migrate,
+//! either by adding `unsafe` to APIs that dereference `RawFd` values, or by
+//! using to `BorrowedFd` or `OwnedFd` instead.
+//!
+//! Like references, `BorrowedFd` values are tied to a lifetime, to ensure
+//! that they don't outlive the resource they point to. These are safe to
+//! use. `BorrowedFd` values may be used in APIs which provide safe access to
+//! any system call except for:
+//!
+//! - `close`, because that would end the dynamic lifetime of the resource
+//! without ending the lifetime of the file descriptor.
+//!
+//! - `dup2`/`dup3`, in the second argument, because this argument is
+//! closed and assigned a new resource, which may break the assumptions
+//! other code using that file descriptor.
+//!
+//! `BorrowedFd` values may be used in APIs which provide safe access to `dup`
+//! system calls, so types implementing `AsFd` or `From<OwnedFd>` should not
+//! assume they always have exclusive access to the underlying file
+//! description.
+//!
+//! `BorrowedFd` values may also be used with `mmap`, since `mmap` uses the
+//! provided file descriptor in a manner similar to `dup` and does not require
+//! the `BorrowedFd` passed to it to live for the lifetime of the resulting
+//! mapping. That said, `mmap` is unsafe for other reasons: it operates on raw
+//! pointers, and it can have undefined behavior if the underlying storage is
+//! mutated. Mutations may come from other processes, or from the same process
+//! if the API provides `BorrowedFd` access, since as mentioned earlier,
+//! `BorrowedFd` values may be used in APIs which provide safe access to any
+//! system call. Consequently, code using `mmap` and presenting a safe API must
+//! take full responsibility for ensuring that safe Rust code cannot evoke
+//! undefined behavior through it.
+//!
+//! Like boxes, `OwnedFd` values conceptually own the resource they point to,
+//! and free (close) it when they are dropped.
+//!
+//! ## `/proc/self/mem` and similar OS features
+//!
+//! Some platforms have special files, such as `/proc/self/mem`, which
+//! provide read and write access to the process's memory. Such reads
+//! and writes happen outside the control of the Rust compiler, so they do not
+//! uphold Rust's memory safety guarantees.
+//!
+//! This does not mean that all APIs that might allow `/proc/self/mem`
+//! to be opened and read from or written must be `unsafe`. Rust's safety guarantees
+//! only cover what the program itself can do, and not what entities outside
+//! the program can do to it. `/proc/self/mem` is considered to be such an
+//! external entity, along with debugging interfaces, and people with physical access to
+//! the hardware. This is true even in cases where the program is controlling
+//! the external entity.
+//!
+//! If you desire to comprehensively prevent programs from reaching out and
+//! causing external entities to reach back in and violate memory safety, it's
+//! necessary to use *sandboxing*, which is outside the scope of `std`.
+//!
+//! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+mod fd;
+mod raw;
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+pub use fd::*;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use raw::*;
diff --git a/library/std/src/os/unix/io/raw.rs b/library/std/src/os/unix/io/raw.rs
new file mode 100644
index 000000000..a4d2ba797
--- /dev/null
+++ b/library/std/src/os/unix/io/raw.rs
@@ -0,0 +1,6 @@
+//! Unix-specific extensions to general I/O primitives.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::os::fd::raw::*;
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
new file mode 100644
index 000000000..411cc0925
--- /dev/null
+++ b/library/std/src/os/unix/mod.rs
@@ -0,0 +1,126 @@
+//! Platform-specific extensions to `std` for Unix platforms.
+//!
+//! Provides access to platform-level information on Unix platforms, and
+//! exposes Unix-specific functions that would otherwise be inappropriate as
+//! part of the core `std` library.
+//!
+//! It exposes more ways to deal with platform-specific strings ([`OsStr`],
+//! [`OsString`]), allows to set permissions more granularly, extract low-level
+//! file descriptors from files and sockets, and has platform-specific helpers
+//! for spawning processes.
+//!
+//! # Examples
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::unix::prelude::*;
+//!
+//! fn main() -> std::io::Result<()> {
+//! let f = File::create("foo.txt")?;
+//! let fd = f.as_raw_fd();
+//!
+//! // use fd with native unix bindings
+//!
+//! Ok(())
+//! }
+//! ```
+//!
+//! [`OsStr`]: crate::ffi::OsStr
+//! [`OsString`]: crate::ffi::OsString
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(unix))]
+
+// Use linux as the default platform when documenting on other platforms like Windows
+#[cfg(doc)]
+use crate::os::linux as platform;
+
+#[cfg(not(doc))]
+mod platform {
+ #[cfg(target_os = "android")]
+ pub use crate::os::android::*;
+ #[cfg(target_os = "dragonfly")]
+ pub use crate::os::dragonfly::*;
+ #[cfg(target_os = "emscripten")]
+ pub use crate::os::emscripten::*;
+ #[cfg(target_os = "espidf")]
+ pub use crate::os::espidf::*;
+ #[cfg(target_os = "freebsd")]
+ pub use crate::os::freebsd::*;
+ #[cfg(target_os = "fuchsia")]
+ pub use crate::os::fuchsia::*;
+ #[cfg(target_os = "haiku")]
+ pub use crate::os::haiku::*;
+ #[cfg(target_os = "horizon")]
+ pub use crate::os::horizon::*;
+ #[cfg(target_os = "illumos")]
+ pub use crate::os::illumos::*;
+ #[cfg(target_os = "ios")]
+ pub use crate::os::ios::*;
+ #[cfg(target_os = "l4re")]
+ pub use crate::os::l4re::*;
+ #[cfg(target_os = "linux")]
+ pub use crate::os::linux::*;
+ #[cfg(target_os = "macos")]
+ pub use crate::os::macos::*;
+ #[cfg(target_os = "netbsd")]
+ pub use crate::os::netbsd::*;
+ #[cfg(target_os = "openbsd")]
+ pub use crate::os::openbsd::*;
+ #[cfg(target_os = "redox")]
+ pub use crate::os::redox::*;
+ #[cfg(target_os = "solaris")]
+ pub use crate::os::solaris::*;
+ #[cfg(target_os = "vxworks")]
+ pub use crate::os::vxworks::*;
+}
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod net;
+pub mod process;
+pub mod raw;
+pub mod thread;
+
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "watchos",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+))]
+pub mod ucred;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[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::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::fs::{FileTypeExt, MetadataExt, OpenOptionsExt, PermissionsExt};
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+ #[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::thread::JoinHandleExt;
+}
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
new file mode 100644
index 000000000..9aeae4b2c
--- /dev/null
+++ b/library/std/src/os/unix/net/addr.rs
@@ -0,0 +1,350 @@
+use crate::ffi::OsStr;
+use crate::os::unix::ffi::OsStrExt;
+use crate::path::Path;
+use crate::sys::cvt;
+use crate::{ascii, fmt, io, mem, ptr};
+
+// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
+#[cfg(not(unix))]
+#[allow(non_camel_case_types)]
+mod libc {
+ pub use libc::c_int;
+ pub type socklen_t = u32;
+ pub struct sockaddr;
+ #[derive(Clone)]
+ pub struct sockaddr_un;
+}
+
+fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
+ // Work with an actual instance of the type since using a null pointer is UB
+ let base = (addr as *const libc::sockaddr_un).addr();
+ let path = (&addr.sun_path as *const libc::c_char).addr();
+ path - base
+}
+
+pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
+ // SAFETY: All zeros is a valid representation for `sockaddr_un`.
+ let mut addr: libc::sockaddr_un = unsafe { 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::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "paths must not contain interior null bytes",
+ ));
+ }
+
+ if bytes.len() >= addr.sun_path.len() {
+ return Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "path must be shorter than SUN_LEN",
+ ));
+ }
+ // SAFETY: `bytes` and `addr.sun_path` are not overlapping and
+ // both point to valid memory.
+ // NOTE: We zeroed the memory above, so the path is already null
+ // terminated.
+ unsafe {
+ ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len())
+ };
+
+ let mut len = sun_path_offset(&addr) + 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]),
+}
+
+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, "\"")
+ }
+}
+
+/// 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 {
+ pub(super) addr: libc::sockaddr_un,
+ pub(super) len: libc::socklen_t,
+}
+
+impl SocketAddr {
+ pub(super) 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)
+ }
+ }
+
+ pub(super) 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(&addr) 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::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "file descriptor did not correspond to a Unix socket",
+ ));
+ }
+
+ Ok(SocketAddr { addr, len })
+ }
+
+ /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if the path is longer than `SUN_LEN` or if it contains
+ /// NULL bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::SocketAddr;
+ /// use std::path::Path;
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// let address = SocketAddr::from_pathname("/path/to/socket")?;
+ /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
+ /// # Ok(())
+ /// # }
+ /// ```
+ ///
+ /// Creating a `SocketAddr` with a NULL byte results in an error.
+ ///
+ /// ```
+ /// use std::os::unix::net::SocketAddr;
+ ///
+ /// assert!(SocketAddr::from_pathname("/path/with/\0/bytes").is_err());
+ /// ```
+ #[stable(feature = "unix_socket_creation", since = "1.61.0")]
+ pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr>
+ where
+ P: AsRef<Path>,
+ {
+ sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len })
+ }
+
+ /// Returns `true` if the address is unnamed.
+ ///
+ /// # Examples
+ ///
+ /// A named address:
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixListener::bind("/tmp/sock")?;
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.is_unnamed(), false);
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// An unnamed address:
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixDatagram::unbound()?;
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.is_unnamed(), true);
+ /// Ok(())
+ /// }
+ /// ```
+ #[must_use]
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn is_unnamed(&self) -> bool {
+ matches!(self.address(), AddressKind::Unnamed)
+ }
+
+ /// 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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixListener::bind("/tmp/sock")?;
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// Without a pathname:
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixDatagram::unbound()?;
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.as_pathname(), None);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ #[must_use]
+ pub fn as_pathname(&self) -> Option<&Path> {
+ if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None }
+ }
+
+ /// Returns the contents of this address if it is an abstract namespace
+ /// without the leading null byte.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixListener, SocketAddr};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let namespace = b"hidden";
+ /// let namespace_addr = SocketAddr::from_abstract_namespace(&namespace[..])?;
+ /// let socket = UnixListener::bind_addr(&namespace_addr)?;
+ /// let local_addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(local_addr.as_abstract_namespace(), Some(&namespace[..]));
+ /// Ok(())
+ /// }
+ /// ```
+ #[doc(cfg(any(target_os = "android", target_os = "linux")))]
+ #[cfg(any(doc, target_os = "android", target_os = "linux",))]
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
+ if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None }
+ }
+
+ fn address(&self) -> AddressKind<'_> {
+ let len = self.len as usize - sun_path_offset(&self.addr);
+ 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())
+ }
+ }
+
+ /// Creates an abstract domain socket address from a namespace
+ ///
+ /// An abstract address does not create a file unlike traditional path-based
+ /// Unix sockets. The advantage of this is that the address will disappear when
+ /// the socket bound to it is closed, so no filesystem clean up is required.
+ ///
+ /// The leading null byte for the abstract namespace is automatically added.
+ ///
+ /// This is a Linux-specific extension. See more at [`unix(7)`].
+ ///
+ /// [`unix(7)`]: https://man7.org/linux/man-pages/man7/unix.7.html
+ ///
+ /// # Errors
+ ///
+ /// This will return an error if the given namespace is too long
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixListener, SocketAddr};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let addr = SocketAddr::from_abstract_namespace(b"hidden")?;
+ /// let listener = match UnixListener::bind_addr(&addr) {
+ /// Ok(sock) => sock,
+ /// Err(err) => {
+ /// println!("Couldn't bind: {err:?}");
+ /// return Err(err);
+ /// }
+ /// };
+ /// Ok(())
+ /// }
+ /// ```
+ #[doc(cfg(any(target_os = "android", target_os = "linux")))]
+ #[cfg(any(doc, target_os = "android", target_os = "linux",))]
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn from_abstract_namespace(namespace: &[u8]) -> io::Result<SocketAddr> {
+ unsafe {
+ let mut addr: libc::sockaddr_un = mem::zeroed();
+ addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
+
+ if namespace.len() + 1 > addr.sun_path.len() {
+ return Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "namespace must be shorter than SUN_LEN",
+ ));
+ }
+
+ crate::ptr::copy_nonoverlapping(
+ namespace.as_ptr(),
+ addr.sun_path.as_mut_ptr().offset(1) as *mut u8,
+ namespace.len(),
+ );
+ let len = (sun_path_offset(&addr) + 1 + namespace.len()) as libc::socklen_t;
+ SocketAddr::from_parts(addr, len)
+ }
+ }
+}
+
+#[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, "{path:?} (pathname)"),
+ }
+ }
+}
diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs
new file mode 100644
index 000000000..7cc901a79
--- /dev/null
+++ b/library/std/src/os/unix/net/ancillary.rs
@@ -0,0 +1,674 @@
+// FIXME: This is currently disabled on *BSD.
+
+use super::{sockaddr_un, SocketAddr};
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::marker::PhantomData;
+use crate::mem::{size_of, zeroed};
+use crate::os::unix::io::RawFd;
+use crate::path::Path;
+use crate::ptr::{eq, read_unaligned};
+use crate::slice::from_raw_parts;
+use crate::sys::net::Socket;
+
+// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
+#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android"), not(target_os = "netbsd")))]
+#[allow(non_camel_case_types)]
+mod libc {
+ pub use libc::c_int;
+ pub struct ucred;
+ pub struct cmsghdr;
+ pub type pid_t = i32;
+ pub type gid_t = u32;
+ pub type uid_t = u32;
+}
+
+pub(super) fn recv_vectored_with_ancillary_from(
+ socket: &Socket,
+ bufs: &mut [IoSliceMut<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
+ unsafe {
+ let mut msg_name: libc::sockaddr_un = zeroed();
+ let mut msg: libc::msghdr = zeroed();
+ msg.msg_name = &mut msg_name as *mut _ as *mut _;
+ msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
+ msg.msg_iov = bufs.as_mut_ptr().cast();
+ msg.msg_iovlen = bufs.len() as _;
+ msg.msg_controllen = ancillary.buffer.len() as _;
+ // macos requires that the control pointer is null when the len is 0.
+ if msg.msg_controllen > 0 {
+ msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
+ }
+
+ let count = socket.recv_msg(&mut msg)?;
+
+ ancillary.length = msg.msg_controllen as usize;
+ ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
+
+ let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
+ let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
+
+ Ok((count, truncated, addr))
+ }
+}
+
+pub(super) fn send_vectored_with_ancillary_to(
+ socket: &Socket,
+ path: Option<&Path>,
+ bufs: &[IoSlice<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+) -> io::Result<usize> {
+ unsafe {
+ let (mut msg_name, msg_namelen) =
+ if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
+
+ let mut msg: libc::msghdr = zeroed();
+ msg.msg_name = &mut msg_name as *mut _ as *mut _;
+ msg.msg_namelen = msg_namelen;
+ msg.msg_iov = bufs.as_ptr() as *mut _;
+ msg.msg_iovlen = bufs.len() as _;
+ msg.msg_controllen = ancillary.length as _;
+ // macos requires that the control pointer is null when the len is 0.
+ if msg.msg_controllen > 0 {
+ msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
+ }
+
+ ancillary.truncated = false;
+
+ socket.send_msg(&mut msg)
+ }
+}
+
+fn add_to_ancillary_data<T>(
+ buffer: &mut [u8],
+ length: &mut usize,
+ source: &[T],
+ cmsg_level: libc::c_int,
+ cmsg_type: libc::c_int,
+) -> bool {
+ let source_len = if let Some(source_len) = source.len().checked_mul(size_of::<T>()) {
+ if let Ok(source_len) = u32::try_from(source_len) {
+ source_len
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ };
+
+ unsafe {
+ let additional_space = libc::CMSG_SPACE(source_len) as usize;
+
+ let new_length = if let Some(new_length) = additional_space.checked_add(*length) {
+ new_length
+ } else {
+ return false;
+ };
+
+ if new_length > buffer.len() {
+ return false;
+ }
+
+ buffer[*length..new_length].fill(0);
+
+ *length = new_length;
+
+ let mut msg: libc::msghdr = zeroed();
+ msg.msg_control = buffer.as_mut_ptr().cast();
+ msg.msg_controllen = *length as _;
+
+ let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
+ let mut previous_cmsg = cmsg;
+ while !cmsg.is_null() {
+ previous_cmsg = cmsg;
+ cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
+
+ // Most operating systems, but not Linux or emscripten, return the previous pointer
+ // when its length is zero. Therefore, check if the previous pointer is the same as
+ // the current one.
+ if eq(cmsg, previous_cmsg) {
+ break;
+ }
+ }
+
+ if previous_cmsg.is_null() {
+ return false;
+ }
+
+ (*previous_cmsg).cmsg_level = cmsg_level;
+ (*previous_cmsg).cmsg_type = cmsg_type;
+ (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as _;
+
+ let data = libc::CMSG_DATA(previous_cmsg).cast();
+
+ libc::memcpy(data, source.as_ptr().cast(), source_len as usize);
+ }
+ true
+}
+
+struct AncillaryDataIter<'a, T> {
+ data: &'a [u8],
+ phantom: PhantomData<T>,
+}
+
+impl<'a, T> AncillaryDataIter<'a, T> {
+ /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message.
+ ///
+ /// # Safety
+ ///
+ /// `data` must contain a valid control message.
+ unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
+ AncillaryDataIter { data, phantom: PhantomData }
+ }
+}
+
+impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ if size_of::<T>() <= self.data.len() {
+ unsafe {
+ let unit = read_unaligned(self.data.as_ptr().cast());
+ self.data = &self.data[size_of::<T>()..];
+ Some(unit)
+ }
+ } else {
+ None
+ }
+ }
+}
+
+#[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+#[derive(Clone)]
+pub struct SocketCred(());
+
+/// Unix credential.
+#[cfg(any(target_os = "android", target_os = "linux",))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+#[derive(Clone)]
+pub struct SocketCred(libc::ucred);
+
+#[cfg(target_os = "netbsd")]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+#[derive(Clone)]
+pub struct SocketCred(libc::sockcred);
+
+#[doc(cfg(any(target_os = "android", target_os = "linux")))]
+#[cfg(any(target_os = "android", target_os = "linux"))]
+impl SocketCred {
+ /// Create a Unix credential struct.
+ ///
+ /// PID, UID and GID is set to 0.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ #[must_use]
+ pub fn new() -> SocketCred {
+ SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 })
+ }
+
+ /// Set the PID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_pid(&mut self, pid: libc::pid_t) {
+ self.0.pid = pid;
+ }
+
+ /// Get the current PID.
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn get_pid(&self) -> libc::pid_t {
+ self.0.pid
+ }
+
+ /// Set the UID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_uid(&mut self, uid: libc::uid_t) {
+ self.0.uid = uid;
+ }
+
+ /// Get the current UID.
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn get_uid(&self) -> libc::uid_t {
+ self.0.uid
+ }
+
+ /// Set the GID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_gid(&mut self, gid: libc::gid_t) {
+ self.0.gid = gid;
+ }
+
+ /// Get the current GID.
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn get_gid(&self) -> libc::gid_t {
+ self.0.gid
+ }
+}
+
+#[cfg(target_os = "netbsd")]
+impl SocketCred {
+ /// Create a Unix credential struct.
+ ///
+ /// PID, UID and GID is set to 0.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn new() -> SocketCred {
+ SocketCred(libc::sockcred {
+ sc_pid: 0,
+ sc_uid: 0,
+ sc_euid: 0,
+ sc_gid: 0,
+ sc_egid: 0,
+ sc_ngroups: 0,
+ sc_groups: [0u32; 1],
+ })
+ }
+
+ /// Set the PID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_pid(&mut self, pid: libc::pid_t) {
+ self.0.sc_pid = pid;
+ }
+
+ /// Get the current PID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn get_pid(&self) -> libc::pid_t {
+ self.0.sc_pid
+ }
+
+ /// Set the UID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_uid(&mut self, uid: libc::uid_t) {
+ self.0.sc_uid = uid;
+ }
+
+ /// Get the current UID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn get_uid(&self) -> libc::uid_t {
+ self.0.sc_uid
+ }
+
+ /// Set the GID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_gid(&mut self, gid: libc::gid_t) {
+ self.0.sc_gid = gid;
+ }
+
+ /// Get the current GID.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn get_gid(&self) -> libc::gid_t {
+ self.0.sc_gid
+ }
+}
+
+/// This control message contains file descriptors.
+///
+/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
+
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+impl<'a> Iterator for ScmRights<'a> {
+ type Item = RawFd;
+
+ fn next(&mut self) -> Option<RawFd> {
+ self.0.next()
+ }
+}
+
+#[cfg(all(doc, not(target_os = "android"), not(target_os = "linux"), not(target_os = "netbsd")))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
+
+/// This control message contains unix credentials.
+///
+/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`.
+#[cfg(any(target_os = "android", target_os = "linux",))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
+
+#[cfg(target_os = "netbsd")]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred>);
+
+#[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+impl<'a> Iterator for ScmCredentials<'a> {
+ type Item = SocketCred;
+
+ fn next(&mut self) -> Option<SocketCred> {
+ Some(SocketCred(self.0.next()?))
+ }
+}
+
+/// The error type which is returned from parsing the type a control message.
+#[non_exhaustive]
+#[derive(Debug)]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub enum AncillaryError {
+ Unknown { cmsg_level: i32, cmsg_type: i32 },
+}
+
+/// This enum represent one control message of variable type.
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub enum AncillaryData<'a> {
+ ScmRights(ScmRights<'a>),
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ ScmCredentials(ScmCredentials<'a>),
+}
+
+impl<'a> AncillaryData<'a> {
+ /// Create an `AncillaryData::ScmRights` variant.
+ ///
+ /// # Safety
+ ///
+ /// `data` must contain a valid control message and the control message must be type of
+ /// `SOL_SOCKET` and level of `SCM_RIGHTS`.
+ unsafe fn as_rights(data: &'a [u8]) -> Self {
+ let ancillary_data_iter = AncillaryDataIter::new(data);
+ let scm_rights = ScmRights(ancillary_data_iter);
+ AncillaryData::ScmRights(scm_rights)
+ }
+
+ /// Create an `AncillaryData::ScmCredentials` variant.
+ ///
+ /// # Safety
+ ///
+ /// `data` must contain a valid control message and the control message must be type of
+ /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDS`.
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ unsafe fn as_credentials(data: &'a [u8]) -> Self {
+ let ancillary_data_iter = AncillaryDataIter::new(data);
+ let scm_credentials = ScmCredentials(ancillary_data_iter);
+ AncillaryData::ScmCredentials(scm_credentials)
+ }
+
+ fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
+ unsafe {
+ let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
+ let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero;
+ let data = libc::CMSG_DATA(cmsg).cast();
+ let data = from_raw_parts(data, data_len);
+
+ match (*cmsg).cmsg_level {
+ libc::SOL_SOCKET => match (*cmsg).cmsg_type {
+ libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
+ #[cfg(any(target_os = "android", target_os = "linux",))]
+ libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
+ #[cfg(target_os = "netbsd")]
+ libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)),
+ cmsg_type => {
+ Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type })
+ }
+ },
+ cmsg_level => {
+ Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type })
+ }
+ }
+ }
+ }
+}
+
+/// This struct is used to iterate through the control messages.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct Messages<'a> {
+ buffer: &'a [u8],
+ current: Option<&'a libc::cmsghdr>,
+}
+
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+impl<'a> Iterator for Messages<'a> {
+ type Item = Result<AncillaryData<'a>, AncillaryError>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ unsafe {
+ let mut msg: libc::msghdr = zeroed();
+ msg.msg_control = self.buffer.as_ptr() as *mut _;
+ msg.msg_controllen = self.buffer.len() as _;
+
+ let cmsg = if let Some(current) = self.current {
+ libc::CMSG_NXTHDR(&msg, current)
+ } else {
+ libc::CMSG_FIRSTHDR(&msg)
+ };
+
+ let cmsg = cmsg.as_ref()?;
+
+ // Most operating systems, but not Linux or emscripten, return the previous pointer
+ // when its length is zero. Therefore, check if the previous pointer is the same as
+ // the current one.
+ if let Some(current) = self.current {
+ if eq(current, cmsg) {
+ return None;
+ }
+ }
+
+ self.current = Some(cmsg);
+ let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg);
+ Some(ancillary_result)
+ }
+ }
+}
+
+/// A Unix socket Ancillary data struct.
+///
+/// # Example
+/// ```no_run
+/// #![feature(unix_socket_ancillary_data)]
+/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
+/// use std::io::IoSliceMut;
+///
+/// fn main() -> std::io::Result<()> {
+/// let sock = UnixStream::connect("/tmp/sock")?;
+///
+/// let mut fds = [0; 8];
+/// let mut ancillary_buffer = [0; 128];
+/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+///
+/// let mut buf = [1; 8];
+/// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+/// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+///
+/// for ancillary_result in ancillary.messages() {
+/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+/// for fd in scm_rights {
+/// println!("receive file descriptor: {fd}");
+/// }
+/// }
+/// }
+/// Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+#[derive(Debug)]
+pub struct SocketAncillary<'a> {
+ buffer: &'a mut [u8],
+ length: usize,
+ truncated: bool,
+}
+
+impl<'a> SocketAncillary<'a> {
+ /// Create an ancillary data with the given buffer.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// # #![allow(unused_mut)]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::SocketAncillary;
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// ```
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn new(buffer: &'a mut [u8]) -> Self {
+ SocketAncillary { buffer, length: 0, truncated: false }
+ }
+
+ /// Returns the capacity of the buffer.
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn capacity(&self) -> usize {
+ self.buffer.len()
+ }
+
+ /// Returns `true` if the ancillary data is empty.
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn is_empty(&self) -> bool {
+ self.length == 0
+ }
+
+ /// Returns the number of used bytes.
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn len(&self) -> usize {
+ self.length
+ }
+
+ /// Returns the iterator of the control messages.
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn messages(&self) -> Messages<'_> {
+ Messages { buffer: &self.buffer[..self.length], current: None }
+ }
+
+ /// Is `true` if during a recv operation the ancillary was truncated.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixStream, SocketAncillary};
+ /// use std::io::IoSliceMut;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixStream::connect("/tmp/sock")?;
+ ///
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ ///
+ /// let mut buf = [1; 8];
+ /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+ /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+ ///
+ /// println!("Is truncated: {}", ancillary.truncated());
+ /// Ok(())
+ /// }
+ /// ```
+ #[must_use]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn truncated(&self) -> bool {
+ self.truncated
+ }
+
+ /// Add file descriptors to the ancillary data.
+ ///
+ /// The function returns `true` if there was enough space in the buffer.
+ /// If there was not enough space then no file descriptors was appended.
+ /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
+ /// and type `SCM_RIGHTS`.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixStream, SocketAncillary};
+ /// use std::os::unix::io::AsRawFd;
+ /// use std::io::IoSlice;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixStream::connect("/tmp/sock")?;
+ ///
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// ancillary.add_fds(&[sock.as_raw_fd()][..]);
+ ///
+ /// let buf = [1; 8];
+ /// let mut bufs = &mut [IoSlice::new(&buf[..])][..];
+ /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
+ self.truncated = false;
+ add_to_ancillary_data(
+ &mut self.buffer,
+ &mut self.length,
+ fds,
+ libc::SOL_SOCKET,
+ libc::SCM_RIGHTS,
+ )
+ }
+
+ /// Add credentials to the ancillary data.
+ ///
+ /// The function returns `true` if there was enough space in the buffer.
+ /// If there was not enough space then no credentials was appended.
+ /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
+ /// and type `SCM_CREDENTIALS` or `SCM_CREDS`.
+ ///
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
+ self.truncated = false;
+ add_to_ancillary_data(
+ &mut self.buffer,
+ &mut self.length,
+ creds,
+ libc::SOL_SOCKET,
+ #[cfg(not(target_os = "netbsd"))]
+ libc::SCM_CREDENTIALS,
+ #[cfg(target_os = "netbsd")]
+ libc::SCM_CREDS,
+ )
+ }
+
+ /// Clears the ancillary data, removing all values.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
+ /// use std::io::IoSliceMut;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixStream::connect("/tmp/sock")?;
+ ///
+ /// let mut fds1 = [0; 8];
+ /// let mut fds2 = [0; 8];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ ///
+ /// let mut buf = [1; 8];
+ /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+ ///
+ /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+ /// for ancillary_result in ancillary.messages() {
+ /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+ /// for fd in scm_rights {
+ /// println!("receive file descriptor: {fd}");
+ /// }
+ /// }
+ /// }
+ ///
+ /// ancillary.clear();
+ ///
+ /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+ /// for ancillary_result in ancillary.messages() {
+ /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+ /// for fd in scm_rights {
+ /// println!("receive file descriptor: {fd}");
+ /// }
+ /// }
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn clear(&mut self) {
+ self.length = 0;
+ self.truncated = false;
+ }
+}
diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
new file mode 100644
index 000000000..8008acfd1
--- /dev/null
+++ b/library/std/src/os/unix/net/datagram.rs
@@ -0,0 +1,987 @@
+#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
+use super::{sockaddr_un, SocketAddr};
+#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+use crate::io::{IoSlice, IoSliceMut};
+use crate::net::Shutdown;
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::path::Path;
+use crate::sys::cvt;
+use crate::sys::net::Socket;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::Duration;
+use crate::{fmt, io};
+
+#[cfg(any(
+ target_os = "linux",
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd",
+ target_os = "haiku"
+))]
+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"
+)))]
+const MSG_NOSIGNAL: libc::c_int = 0x0;
+
+/// A Unix datagram socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixDatagram;
+///
+/// fn main() -> std::io::Result<()> {
+/// let socket = UnixDatagram::bind("/path/to/my/socket")?;
+/// socket.send_to(b"hello world", "/path/to/other/socket")?;
+/// let mut buf = [0; 100];
+/// let (count, address) = socket.recv_from(&mut buf)?;
+/// println!("socket {:?} sent {:?}", address, &buf[..count]);
+/// Ok(())
+/// }
+/// ```
+#[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> {
+ unsafe {
+ let socket = UnixDatagram::unbound()?;
+ let (addr, len) = sockaddr_un(path.as_ref())?;
+
+ cvt(libc::bind(socket.as_raw_fd(), &addr as *const _ as *const _, len as _))?;
+
+ Ok(socket)
+ }
+ }
+
+ /// Creates a Unix datagram socket bound to an address.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixDatagram};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock1 = UnixDatagram::bind("path/to/socket")?;
+ /// let addr = sock1.local_addr()?;
+ ///
+ /// let sock2 = match UnixDatagram::bind_addr(&addr) {
+ /// Ok(sock) => sock,
+ /// Err(err) => {
+ /// println!("Couldn't bind: {err:?}");
+ /// return Err(err);
+ /// }
+ /// };
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixDatagram> {
+ unsafe {
+ let socket = UnixDatagram::unbound()?;
+ cvt(libc::bind(
+ socket.as_raw_fd(),
+ &socket_addr.addr as *const _ as *const _,
+ socket_addr.len as _,
+ ))?;
+ Ok(socket)
+ }
+ }
+
+ /// 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))
+ }
+
+ /// Creates 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 path 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`]: UnixDatagram::send
+ /// [`recv`]: UnixDatagram::recv
+ /// [`recv_from`]: UnixDatagram::recv_from
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// match sock.connect("/path/to/the/socket") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {e:?}");
+ /// return Err(e)
+ /// }
+ /// };
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+ unsafe {
+ let (addr, len) = sockaddr_un(path.as_ref())?;
+
+ cvt(libc::connect(self.as_raw_fd(), &addr as *const _ as *const _, len))?;
+ }
+ Ok(())
+ }
+
+ /// Connects the socket to an address.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixDatagram};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let bound = UnixDatagram::bind("/path/to/socket")?;
+ /// let addr = bound.local_addr()?;
+ ///
+ /// let sock = UnixDatagram::unbound()?;
+ /// match sock.connect_addr(&addr) {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {e:?}");
+ /// return Err(e)
+ /// }
+ /// };
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn connect_addr(&self, socket_addr: &SocketAddr) -> io::Result<()> {
+ unsafe {
+ cvt(libc::connect(
+ self.as_raw_fd(),
+ &socket_addr.addr as *const _ as *const _,
+ socket_addr.len,
+ ))?;
+ }
+ Ok(())
+ }
+
+ /// 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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::bind("/path/to/the/socket")?;
+ /// let sock_copy = sock.try_clone().expect("try_clone failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::bind("/path/to/the/socket")?;
+ /// let addr = sock.local_addr().expect("Couldn't get local address");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) })
+ }
+
+ /// Returns the address of this socket's peer.
+ ///
+ /// The [`connect`] method will connect the socket to a peer.
+ ///
+ /// [`connect`]: UnixDatagram::connect
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.connect("/path/to/the/socket")?;
+ ///
+ /// let addr = sock.peer_addr().expect("Couldn't get peer address");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getpeername(self.as_raw_fd(), addr, len) })
+ }
+
+ fn recv_from_flags(
+ &self,
+ buf: &mut [u8],
+ flags: libc::c_int,
+ ) -> io::Result<(usize, SocketAddr)> {
+ let mut count = 0;
+ let addr = SocketAddr::new(|addr, len| unsafe {
+ count = libc::recvfrom(
+ self.as_raw_fd(),
+ buf.as_mut_ptr() as *mut _,
+ buf.len(),
+ flags,
+ 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 and the address from
+ /// whence the data came.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// let mut buf = vec![0; 10];
+ /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?;
+ /// println!("received {size} bytes from {sender:?}");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_flags(buf, 0)
+ }
+
+ /// Receives data from the socket.
+ ///
+ /// On success, returns the number of bytes read.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::bind("/path/to/the/socket")?;
+ /// let mut buf = vec![0; 10];
+ /// sock.recv(buf.as_mut_slice()).expect("recv function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ /// Receives data and ancillary data from socket.
+ ///
+ /// On success, returns the number of bytes read, if the data was truncated and the address from whence the msg came.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
+ /// use std::io::IoSliceMut;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// let mut buf1 = [1; 8];
+ /// let mut buf2 = [2; 16];
+ /// let mut buf3 = [3; 8];
+ /// let mut bufs = &mut [
+ /// IoSliceMut::new(&mut buf1),
+ /// IoSliceMut::new(&mut buf2),
+ /// IoSliceMut::new(&mut buf3),
+ /// ][..];
+ /// let mut fds = [0; 8];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?;
+ /// println!("received {size}");
+ /// for ancillary_result in ancillary.messages() {
+ /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+ /// for fd in scm_rights {
+ /// println!("receive file descriptor: {fd}");
+ /// }
+ /// }
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn recv_vectored_with_ancillary_from(
+ &self,
+ bufs: &mut [IoSliceMut<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+ ) -> io::Result<(usize, bool, SocketAddr)> {
+ let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
+ let addr = addr?;
+
+ Ok((count, truncated, addr))
+ }
+
+ /// Receives data and ancillary data from socket.
+ ///
+ /// On success, returns the number of bytes read and if the data was truncated.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
+ /// use std::io::IoSliceMut;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// let mut buf1 = [1; 8];
+ /// let mut buf2 = [2; 16];
+ /// let mut buf3 = [3; 8];
+ /// let mut bufs = &mut [
+ /// IoSliceMut::new(&mut buf1),
+ /// IoSliceMut::new(&mut buf2),
+ /// IoSliceMut::new(&mut buf3),
+ /// ][..];
+ /// let mut fds = [0; 8];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+ /// println!("received {size}");
+ /// for ancillary_result in ancillary.messages() {
+ /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+ /// for fd in scm_rights {
+ /// println!("receive file descriptor: {fd}");
+ /// }
+ /// }
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn recv_vectored_with_ancillary(
+ &self,
+ bufs: &mut [IoSliceMut<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+ ) -> io::Result<(usize, bool)> {
+ let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
+ addr?;
+
+ Ok((count, truncated))
+ }
+
+ /// 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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
+ unsafe {
+ let (addr, len) = sockaddr_un(path.as_ref())?;
+
+ let count = cvt(libc::sendto(
+ self.as_raw_fd(),
+ buf.as_ptr() as *const _,
+ buf.len(),
+ MSG_NOSIGNAL,
+ &addr as *const _ as *const _,
+ len,
+ ))?;
+ Ok(count as usize)
+ }
+ }
+
+ /// Sends data on the socket to the specified [SocketAddr].
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// [SocketAddr]: crate::os::unix::net::SocketAddr
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixDatagram};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let bound = UnixDatagram::bind("/path/to/socket")?;
+ /// let addr = bound.local_addr()?;
+ ///
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.send_to_addr(b"bacon egg and cheese", &addr).expect("send_to_addr function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn send_to_addr(&self, buf: &[u8], socket_addr: &SocketAddr) -> io::Result<usize> {
+ unsafe {
+ let count = cvt(libc::sendto(
+ self.as_raw_fd(),
+ buf.as_ptr() as *const _,
+ buf.len(),
+ MSG_NOSIGNAL,
+ &socket_addr.addr as *const _ as *const _,
+ socket_addr.len,
+ ))?;
+ Ok(count as usize)
+ }
+ }
+
+ /// 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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.connect("/some/sock").expect("Couldn't connect");
+ /// sock.send(b"omelette au fromage").expect("send_to function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ /// Sends data and ancillary data on the socket to the specified address.
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
+ /// use std::io::IoSlice;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// let buf1 = [1; 8];
+ /// let buf2 = [2; 16];
+ /// let buf3 = [3; 8];
+ /// let bufs = &[
+ /// IoSlice::new(&buf1),
+ /// IoSlice::new(&buf2),
+ /// IoSlice::new(&buf3),
+ /// ][..];
+ /// let fds = [0, 1, 2];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// ancillary.add_fds(&fds[..]);
+ /// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock")
+ /// .expect("send_vectored_with_ancillary_to function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn send_vectored_with_ancillary_to<P: AsRef<Path>>(
+ &self,
+ bufs: &[IoSlice<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+ path: P,
+ ) -> io::Result<usize> {
+ send_vectored_with_ancillary_to(&self.0, Some(path.as_ref()), bufs, ancillary)
+ }
+
+ /// Sends data and ancillary data on the socket.
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
+ /// use std::io::IoSlice;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// let buf1 = [1; 8];
+ /// let buf2 = [2; 16];
+ /// let buf3 = [3; 8];
+ /// let bufs = &[
+ /// IoSlice::new(&buf1),
+ /// IoSlice::new(&buf2),
+ /// IoSlice::new(&buf3),
+ /// ][..];
+ /// let fds = [0, 1, 2];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// ancillary.add_fds(&fds[..]);
+ /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)
+ /// .expect("send_vectored_with_ancillary function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn send_vectored_with_ancillary(
+ &self,
+ bufs: &[IoSlice<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+ ) -> io::Result<usize> {
+ send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
+ }
+
+ /// 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.
+ ///
+ /// [`recv`]: UnixDatagram::recv
+ /// [`recv_from`]: UnixDatagram::recv_from
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.set_read_timeout(Some(Duration::new(1, 0)))
+ /// .expect("set_read_timeout function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// 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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixDatagram::unbound()?;
+ /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+ /// Ok(())
+ /// }
+ /// ```
+ #[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.
+ ///
+ /// [`send`]: UnixDatagram::send
+ /// [`send_to`]: UnixDatagram::send_to
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.set_write_timeout(Some(Duration::new(1, 0)))
+ /// .expect("set_write_timeout function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// 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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixDatagram::unbound()?;
+ /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+ /// Ok(())
+ /// }
+ /// ```
+ #[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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.set_read_timeout(Some(Duration::new(1, 0)))
+ /// .expect("set_read_timeout function failed");
+ /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0)));
+ /// Ok(())
+ /// }
+ /// ```
+ #[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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.set_write_timeout(Some(Duration::new(1, 0)))
+ /// .expect("set_write_timeout function failed");
+ /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0)));
+ /// Ok(())
+ /// }
+ /// ```
+ #[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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.set_nonblocking(true).expect("set_nonblocking function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+
+ /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`].
+ ///
+ /// Set the socket option `SO_PASSCRED`.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.set_passcred(true).expect("set_passcred function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
+ self.0.set_passcred(passcred)
+ }
+
+ /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`].
+ /// This value can be change by [`set_passcred`].
+ ///
+ /// Get the socket option `SO_PASSCRED`.
+ ///
+ /// [`set_passcred`]: UnixDatagram::set_passcred
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn passcred(&self) -> io::Result<bool> {
+ self.0.passcred()
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// if let Ok(Some(err)) = sock.take_error() {
+ /// println!("Got error: {err:?}");
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[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`]).
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixDatagram;
+ /// use std::net::Shutdown;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let sock = UnixDatagram::unbound()?;
+ /// sock.shutdown(Shutdown::Both).expect("shutdown function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.0.shutdown(how)
+ }
+
+ /// Receives data on the socket from the remote address to which it is
+ /// connected, without removing that data from the queue. On success,
+ /// returns the number of bytes peeked.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recv` system call.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_peek)]
+ ///
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixDatagram::bind("/tmp/sock")?;
+ /// let mut buf = [0; 10];
+ /// let len = socket.peek(&mut buf).expect("peek failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_peek", issue = "76923")]
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.peek(buf)
+ }
+
+ /// Receives a single datagram message on the socket, without removing it from the
+ /// queue. On success, returns the number of bytes read and the origin.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call.
+ ///
+ /// Do not use this function to implement busy waiting, instead use `libc::poll` to
+ /// synchronize IO events on one or more sockets.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_peek)]
+ ///
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixDatagram::bind("/tmp/sock")?;
+ /// let mut buf = [0; 10];
+ /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_peek", issue = "76923")]
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_flags(buf, libc::MSG_PEEK)
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixDatagram {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_inner().as_raw_fd()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixDatagram {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
+ UnixDatagram(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))))
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixDatagram {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_inner().into_inner().into_raw_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for UnixDatagram {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.0.as_inner().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<UnixDatagram> for OwnedFd {
+ #[inline]
+ fn from(unix_datagram: UnixDatagram) -> OwnedFd {
+ unsafe { OwnedFd::from_raw_fd(unix_datagram.into_raw_fd()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedFd> for UnixDatagram {
+ #[inline]
+ fn from(owned: OwnedFd) -> Self {
+ unsafe { Self::from_raw_fd(owned.into_raw_fd()) }
+ }
+}
diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
new file mode 100644
index 000000000..7c0d53950
--- /dev/null
+++ b/library/std/src/os/unix/net/listener.rs
@@ -0,0 +1,385 @@
+use super::{sockaddr_un, SocketAddr, UnixStream};
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::path::Path;
+use crate::sys::cvt;
+use crate::sys::net::Socket;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::{fmt, io, mem};
+
+/// 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) {
+/// // ...
+/// }
+///
+/// fn main() -> std::io::Result<()> {
+/// let listener = UnixListener::bind("/path/to/the/socket")?;
+///
+/// // 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;
+/// }
+/// }
+/// }
+/// Ok(())
+/// }
+/// ```
+#[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> {
+ unsafe {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ let (addr, len) = sockaddr_un(path.as_ref())?;
+
+ cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?;
+ cvt(libc::listen(inner.as_inner().as_raw_fd(), 128))?;
+
+ Ok(UnixListener(inner))
+ }
+ }
+
+ /// Creates a new `UnixListener` bound to the specified [`socket address`].
+ ///
+ /// [`socket address`]: crate::os::unix::net::SocketAddr
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixListener};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener1 = UnixListener::bind("path/to/socket")?;
+ /// let addr = listener1.local_addr()?;
+ ///
+ /// let listener2 = match UnixListener::bind_addr(&addr) {
+ /// Ok(sock) => sock,
+ /// Err(err) => {
+ /// println!("Couldn't bind: {err:?}");
+ /// return Err(err);
+ /// }
+ /// };
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixListener> {
+ unsafe {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ cvt(libc::bind(
+ inner.as_raw_fd(),
+ &socket_addr.addr as *const _ as *const _,
+ socket_addr.len as _,
+ ))?;
+ cvt(libc::listen(inner.as_raw_fd(), 128))?;
+ Ok(UnixListener(inner))
+ }
+ }
+
+ /// 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`]: crate::os::unix::net::UnixStream
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/path/to/the/socket")?;
+ ///
+ /// match listener.accept() {
+ /// Ok((socket, addr)) => println!("Got a client: {addr:?}"),
+ /// Err(e) => println!("accept function failed: {e:?}"),
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/path/to/the/socket")?;
+ /// let listener_copy = listener.try_clone().expect("try_clone failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/path/to/the/socket")?;
+ /// let addr = listener.local_addr().expect("Couldn't get local address");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) })
+ }
+
+ /// Moves the socket into or out of nonblocking mode.
+ ///
+ /// This will result in the `accept` operation becoming nonblocking,
+ /// i.e., immediately returning from their calls. If the IO operation is
+ /// successful, `Ok` is returned and no further action is required. If the
+ /// IO operation could not be completed and needs to be retried, an error
+ /// with kind [`io::ErrorKind::WouldBlock`] is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/path/to/the/socket")?;
+ /// listener.set_nonblocking(true).expect("Couldn't set non blocking");
+ /// Ok(())
+ /// }
+ /// ```
+ #[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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/tmp/sock")?;
+ ///
+ /// if let Ok(Some(err)) = listener.take_error() {
+ /// println!("Got error: {err:?}");
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// # Platform specific
+ /// On Redox this always returns `None`.
+ #[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.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::thread;
+ /// use std::os::unix::net::{UnixStream, UnixListener};
+ ///
+ /// fn handle_client(stream: UnixStream) {
+ /// // ...
+ /// }
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/path/to/the/socket")?;
+ ///
+ /// for stream in listener.incoming() {
+ /// match stream {
+ /// Ok(stream) => {
+ /// thread::spawn(|| handle_client(stream));
+ /// }
+ /// Err(err) => {
+ /// break;
+ /// }
+ /// }
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn incoming(&self) -> Incoming<'_> {
+ Incoming { listener: self }
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixListener {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_inner().as_raw_fd()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixListener {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
+ UnixListener(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))))
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixListener {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_inner().into_inner().into_raw_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for UnixListener {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.0.as_inner().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedFd> for UnixListener {
+ #[inline]
+ fn from(fd: OwnedFd) -> UnixListener {
+ UnixListener(Socket::from_inner(FromInner::from_inner(fd)))
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<UnixListener> for OwnedFd {
+ #[inline]
+ fn from(listener: UnixListener) -> OwnedFd {
+ listener.0.into_inner().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`].
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+/// // ...
+/// }
+///
+/// fn main() -> std::io::Result<()> {
+/// let listener = UnixListener::bind("/path/to/the/socket")?;
+///
+/// for stream in listener.incoming() {
+/// match stream {
+/// Ok(stream) => {
+/// thread::spawn(|| handle_client(stream));
+/// }
+/// Err(err) => {
+/// break;
+/// }
+/// }
+/// }
+/// Ok(())
+/// }
+/// ```
+#[derive(Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[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, None)
+ }
+}
diff --git a/library/std/src/os/unix/net/mod.rs b/library/std/src/os/unix/net/mod.rs
new file mode 100644
index 000000000..6da3e350b
--- /dev/null
+++ b/library/std/src/os/unix/net/mod.rs
@@ -0,0 +1,26 @@
+//! Unix-specific networking functionality.
+
+#![allow(irrefutable_let_patterns)]
+#![stable(feature = "unix_socket", since = "1.10.0")]
+
+mod addr;
+#[doc(cfg(any(target_os = "android", target_os = "linux")))]
+#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+mod ancillary;
+mod datagram;
+mod listener;
+mod stream;
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub use self::addr::*;
+#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub use self::ancillary::*;
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub use self::datagram::*;
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub use self::listener::*;
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub use self::stream::*;
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
new file mode 100644
index 000000000..cc3a88587
--- /dev/null
+++ b/library/std/src/os/unix/net/stream.rs
@@ -0,0 +1,711 @@
+#[cfg(any(doc, target_os = "android", target_os = "linux"))]
+use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
+use super::{sockaddr_un, SocketAddr};
+use crate::fmt;
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::net::Shutdown;
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "watchos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+))]
+use crate::os::unix::ucred;
+use crate::path::Path;
+use crate::sys::cvt;
+use crate::sys::net::Socket;
+use crate::sys_common::{AsInner, FromInner};
+use crate::time::Duration;
+
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "watchos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+))]
+pub use ucred::UCred;
+
+/// A Unix stream socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixStream;
+/// use std::io::prelude::*;
+///
+/// fn main() -> std::io::Result<()> {
+/// let mut stream = UnixStream::connect("/path/to/my/socket")?;
+/// stream.write_all(b"hello world")?;
+/// let mut response = String::new();
+/// stream.read_to_string(&mut response)?;
+/// println!("{response}");
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixStream(pub(super) 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> {
+ unsafe {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ let (addr, len) = sockaddr_un(path.as_ref())?;
+
+ cvt(libc::connect(inner.as_raw_fd(), &addr as *const _ as *const _, len))?;
+ Ok(UnixStream(inner))
+ }
+ }
+
+ /// Connects to the socket specified by [`address`].
+ ///
+ /// [`address`]: crate::os::unix::net::SocketAddr
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_abstract)]
+ /// use std::os::unix::net::{UnixListener, UnixStream};
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let listener = UnixListener::bind("/path/to/the/socket")?;
+ /// let addr = listener.local_addr()?;
+ ///
+ /// let sock = match UnixStream::connect_addr(&addr) {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {e:?}");
+ /// return Err(e)
+ /// }
+ /// };
+ /// Ok(())
+ /// }
+ /// ````
+ #[unstable(feature = "unix_socket_abstract", issue = "85410")]
+ pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result<UnixStream> {
+ unsafe {
+ let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ cvt(libc::connect(
+ inner.as_raw_fd(),
+ &socket_addr.addr as *const _ as *const _,
+ socket_addr.len,
+ ))?;
+ Ok(UnixStream(inner))
+ }
+ }
+
+ /// 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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let sock_copy = socket.try_clone().expect("Couldn't clone socket");
+ /// Ok(())
+ /// }
+ /// ```
+ #[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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) })
+ }
+
+ /// Returns the socket address of the remote half of this connection.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let addr = socket.peer_addr().expect("Couldn't get peer address");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ SocketAddr::new(|addr, len| unsafe { libc::getpeername(self.as_raw_fd(), addr, len) })
+ }
+
+ /// Gets the peer credentials for this Unix domain socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(peer_credentials_unix_socket)]
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials");
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "watchos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ pub fn peer_cred(&self) -> io::Result<UCred> {
+ ucred::peer_cred(self)
+ }
+
+ /// 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.
+ ///
+ /// [`read`]: io::Read::read
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// 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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+ /// Ok(())
+ /// }
+ /// ```
+ #[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.
+ ///
+ /// [`read`]: io::Read::read
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.set_write_timeout(Some(Duration::new(1, 0)))
+ /// .expect("Couldn't set write timeout");
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// 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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UdpSocket::bind("127.0.0.1:34254")?;
+ /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+ /// Ok(())
+ /// }
+ /// ```
+ #[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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+ /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0)));
+ /// Ok(())
+ /// }
+ /// ```
+ #[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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.set_write_timeout(Some(Duration::new(1, 0)))
+ /// .expect("Couldn't set write timeout");
+ /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0)));
+ /// Ok(())
+ /// }
+ /// ```
+ #[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;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.set_nonblocking(true).expect("Couldn't set nonblocking");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+
+ /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`].
+ ///
+ /// Set the socket option `SO_PASSCRED`.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.set_passcred(true).expect("Couldn't set passcred");
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
+ self.0.set_passcred(passcred)
+ }
+
+ /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`].
+ /// This value can be change by [`set_passcred`].
+ ///
+ /// Get the socket option `SO_PASSCRED`.
+ ///
+ /// [`set_passcred`]: UnixStream::set_passcred
+ #[cfg(any(doc, target_os = "android", target_os = "linux", target_os = "netbsd",))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn passcred(&self) -> io::Result<bool> {
+ self.0.passcred()
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// if let Ok(Some(err)) = socket.take_error() {
+ /// println!("Got error: {err:?}");
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// # Platform specific
+ /// On Redox this always returns `None`.
+ #[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`]).
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::net::Shutdown;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// socket.shutdown(Shutdown::Both).expect("shutdown function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket", since = "1.10.0")]
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ self.0.shutdown(how)
+ }
+
+ /// Receives data on the socket from the remote address to which it is
+ /// connected, without removing that data from the queue. On success,
+ /// returns the number of bytes peeked.
+ ///
+ /// Successive calls return the same data. This is accomplished by passing
+ /// `MSG_PEEK` as a flag to the underlying `recv` system call.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(unix_socket_peek)]
+ ///
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let mut buf = [0; 10];
+ /// let len = socket.peek(&mut buf).expect("peek failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "unix_socket_peek", issue = "76923")]
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.peek(buf)
+ }
+
+ /// Receives data and ancillary data from socket.
+ ///
+ /// On success, returns the number of bytes read.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
+ /// use std::io::IoSliceMut;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let mut buf1 = [1; 8];
+ /// let mut buf2 = [2; 16];
+ /// let mut buf3 = [3; 8];
+ /// let mut bufs = &mut [
+ /// IoSliceMut::new(&mut buf1),
+ /// IoSliceMut::new(&mut buf2),
+ /// IoSliceMut::new(&mut buf3),
+ /// ][..];
+ /// let mut fds = [0; 8];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+ /// println!("received {size}");
+ /// for ancillary_result in ancillary.messages() {
+ /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+ /// for fd in scm_rights {
+ /// println!("receive file descriptor: {fd}");
+ /// }
+ /// }
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn recv_vectored_with_ancillary(
+ &self,
+ bufs: &mut [IoSliceMut<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+ ) -> io::Result<usize> {
+ let (count, _, _) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
+
+ Ok(count)
+ }
+
+ /// Sends data and ancillary data on the socket.
+ ///
+ /// On success, returns the number of bytes written.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+ #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+ /// #![feature(unix_socket_ancillary_data)]
+ /// use std::os::unix::net::{UnixStream, SocketAncillary};
+ /// use std::io::IoSlice;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let buf1 = [1; 8];
+ /// let buf2 = [2; 16];
+ /// let buf3 = [3; 8];
+ /// let bufs = &[
+ /// IoSlice::new(&buf1),
+ /// IoSlice::new(&buf2),
+ /// IoSlice::new(&buf3),
+ /// ][..];
+ /// let fds = [0, 1, 2];
+ /// let mut ancillary_buffer = [0; 128];
+ /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+ /// ancillary.add_fds(&fds[..]);
+ /// socket.send_vectored_with_ancillary(bufs, &mut ancillary)
+ /// .expect("send_vectored_with_ancillary function failed");
+ /// Ok(())
+ /// }
+ /// ```
+ #[cfg(any(doc, target_os = "android", target_os = "linux"))]
+ #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+ pub fn send_vectored_with_ancillary(
+ &self,
+ bufs: &[IoSlice<'_>],
+ ancillary: &mut SocketAncillary<'_>,
+ ) -> io::Result<usize> {
+ send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
+ }
+}
+
+#[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)
+ }
+
+ fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ io::Read::read_vectored(&mut &*self, bufs)
+ }
+
+ #[inline]
+ fn is_read_vectored(&self) -> bool {
+ io::Read::is_read_vectored(&&*self)
+ }
+}
+
+#[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)
+ }
+
+ fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ self.0.read_vectored(bufs)
+ }
+
+ #[inline]
+ fn is_read_vectored(&self) -> bool {
+ self.0.is_read_vectored()
+ }
+}
+
+#[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 write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ io::Write::write_vectored(&mut &*self, bufs)
+ }
+
+ #[inline]
+ fn is_write_vectored(&self) -> bool {
+ io::Write::is_write_vectored(&&*self)
+ }
+
+ 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 write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ self.0.write_vectored(bufs)
+ }
+
+ #[inline]
+ fn is_write_vectored(&self) -> bool {
+ self.0.is_write_vectored()
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixStream {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_raw_fd()
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixStream {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
+ UnixStream(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))))
+ }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixStream {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_raw_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for UnixStream {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.0.as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<UnixStream> for OwnedFd {
+ #[inline]
+ fn from(unix_stream: UnixStream) -> OwnedFd {
+ unsafe { OwnedFd::from_raw_fd(unix_stream.into_raw_fd()) }
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedFd> for UnixStream {
+ #[inline]
+ fn from(owned: OwnedFd) -> Self {
+ unsafe { Self::from_raw_fd(owned.into_raw_fd()) }
+ }
+}
diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs
new file mode 100644
index 000000000..e4499f9b6
--- /dev/null
+++ b/library/std/src/os/unix/net/tests.rs
@@ -0,0 +1,753 @@
+use super::*;
+use crate::io::prelude::*;
+use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
+#[cfg(any(target_os = "android", target_os = "linux"))]
+use crate::os::unix::io::AsRawFd;
+use crate::sys_common::io::test::tmpdir;
+use crate::thread;
+use crate::time::Duration;
+
+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 vectored() {
+ let (mut s1, mut s2) = or_panic!(UnixStream::pair());
+
+ let len = or_panic!(s1.write_vectored(&[
+ IoSlice::new(b"hello"),
+ IoSlice::new(b" "),
+ IoSlice::new(b"world!")
+ ],));
+ assert_eq!(len, 12);
+
+ let mut buf1 = [0; 6];
+ let mut buf2 = [0; 7];
+ let len =
+ or_panic!(s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],));
+ assert_eq!(len, 12);
+ assert_eq!(&buf1, b"hello ");
+ assert_eq!(&buf2, b"world!\0");
+}
+
+#[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_exact(&mut buf).err().expect("expected error").kind();
+ assert!(
+ kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+ "unexpected_error: {:?}",
+ kind
+ );
+}
+
+#[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_exact(&mut buf).err().expect("expected error").kind();
+ assert!(
+ kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+ "unexpected_error: {:?}",
+ kind
+ );
+}
+
+// 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_unix_datagram_connect_to_recv_addr() {
+ 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";
+ let sock1_addr = or_panic!(sock1.local_addr());
+ or_panic!(sock2.send_to_addr(msg, &sock1_addr));
+ let mut buf = [0; 11];
+ let (_, addr) = or_panic!(sock1.recv_from(&mut buf));
+
+ let new_msg = b"hello back";
+ let mut new_buf = [0; 10];
+ or_panic!(sock2.connect_addr(&addr));
+ or_panic!(sock2.send(new_msg)); // set by connect_addr
+ let usize = or_panic!(sock2.recv(&mut new_buf));
+ assert_eq!(usize, 10);
+ assert_eq!(new_msg, &new_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_connect() {
+ assert!(UnixStream::connect("\0asdf").is_err());
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_abstract_stream_connect() {
+ let msg1 = b"hello";
+ let msg2 = b"world";
+
+ let socket_addr = or_panic!(SocketAddr::from_abstract_namespace(b"namespace"));
+ let listener = or_panic!(UnixListener::bind_addr(&socket_addr));
+
+ 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_addr(&socket_addr));
+
+ let peer = or_panic!(stream.peer_addr());
+ assert_eq!(peer.as_abstract_namespace().unwrap(), b"namespace");
+
+ 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();
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_abstract_stream_iter() {
+ let addr = or_panic!(SocketAddr::from_abstract_namespace(b"hidden"));
+ let listener = or_panic!(UnixListener::bind_addr(&addr));
+
+ 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_addr(&addr));
+ or_panic!(stream.write_all(&[0]));
+ }
+
+ thread.join().unwrap();
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_abstract_datagram_bind_send_to_addr() {
+ let addr1 = or_panic!(SocketAddr::from_abstract_namespace(b"ns1"));
+ let sock1 = or_panic!(UnixDatagram::bind_addr(&addr1));
+
+ let local = or_panic!(sock1.local_addr());
+ assert_eq!(local.as_abstract_namespace().unwrap(), b"ns1");
+
+ let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns2"));
+ let sock2 = or_panic!(UnixDatagram::bind_addr(&addr2));
+
+ let msg = b"hello world";
+ or_panic!(sock1.send_to_addr(msg, &addr2));
+ let mut buf = [0; 11];
+ let (len, addr) = or_panic!(sock2.recv_from(&mut buf));
+ assert_eq!(msg, &buf[..]);
+ assert_eq!(len, 11);
+ assert_eq!(addr.as_abstract_namespace().unwrap(), b"ns1");
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_abstract_datagram_connect_addr() {
+ let addr1 = or_panic!(SocketAddr::from_abstract_namespace(b"ns3"));
+ let bsock1 = or_panic!(UnixDatagram::bind_addr(&addr1));
+
+ let sock = or_panic!(UnixDatagram::unbound());
+ or_panic!(sock.connect_addr(&addr1));
+
+ let msg = b"hello world";
+ or_panic!(sock.send(msg));
+ let mut buf = [0; 11];
+ let (len, addr) = or_panic!(bsock1.recv_from(&mut buf));
+ assert_eq!(len, 11);
+ assert_eq!(addr.is_unnamed(), true);
+ assert_eq!(msg, &buf[..]);
+
+ let addr2 = or_panic!(SocketAddr::from_abstract_namespace(b"ns4"));
+ let bsock2 = or_panic!(UnixDatagram::bind_addr(&addr2));
+
+ or_panic!(sock.connect_addr(&addr2));
+ or_panic!(sock.send(msg));
+ or_panic!(bsock2.recv_from(&mut buf));
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_abstract_namespace_too_long() {
+ match SocketAddr::from_abstract_namespace(
+ b"abcdefghijklmnopqrstuvwxyzabcdefghijklmn\
+ opqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi\
+ jklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
+ ) {
+ Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+ Err(e) => panic!("unexpected error {e}"),
+ Ok(_) => panic!("unexpected success"),
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_abstract_namespace_no_pathname_and_not_unnamed() {
+ let namespace = b"local";
+ let addr = or_panic!(SocketAddr::from_abstract_namespace(&namespace[..]));
+ assert_eq!(addr.as_pathname(), None);
+ assert_eq!(addr.as_abstract_namespace(), Some(&namespace[..]));
+ assert_eq!(addr.is_unnamed(), false);
+}
+
+#[test]
+fn test_unix_stream_peek() {
+ let (txdone, rxdone) = crate::sync::mpsc::channel();
+
+ let dir = tmpdir();
+ let path = dir.path().join("sock");
+
+ let listener = or_panic!(UnixListener::bind(&path));
+ let thread = thread::spawn(move || {
+ let mut stream = or_panic!(listener.accept()).0;
+ or_panic!(stream.write_all(&[1, 3, 3, 7]));
+ or_panic!(rxdone.recv());
+ });
+
+ let mut stream = or_panic!(UnixStream::connect(&path));
+ let mut buf = [0; 10];
+ for _ in 0..2 {
+ assert_eq!(or_panic!(stream.peek(&mut buf)), 4);
+ }
+ assert_eq!(or_panic!(stream.read(&mut buf)), 4);
+
+ or_panic!(stream.set_nonblocking(true));
+ match stream.peek(&mut buf) {
+ Ok(_) => panic!("expected error"),
+ Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
+ Err(e) => panic!("unexpected error: {e}"),
+ }
+
+ or_panic!(txdone.send(()));
+ thread.join().unwrap();
+}
+
+#[test]
+fn test_unix_datagram_peek() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock");
+
+ 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));
+ for _ in 0..2 {
+ let mut buf = [0; 11];
+ let size = or_panic!(sock1.peek(&mut buf));
+ assert_eq!(size, 11);
+ assert_eq!(msg, &buf[..]);
+ }
+
+ let mut buf = [0; 11];
+ let size = or_panic!(sock1.recv(&mut buf));
+ assert_eq!(size, 11);
+ assert_eq!(msg, &buf[..]);
+}
+
+#[test]
+fn test_unix_datagram_peek_from() {
+ let dir = tmpdir();
+ let path1 = dir.path().join("sock");
+
+ 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));
+ for _ in 0..2 {
+ let mut buf = [0; 11];
+ let (size, _) = or_panic!(sock1.peek_from(&mut buf));
+ assert_eq!(size, 11);
+ assert_eq!(msg, &buf[..]);
+ }
+
+ let mut buf = [0; 11];
+ let size = or_panic!(sock1.recv(&mut buf));
+ assert_eq!(size, 11);
+ assert_eq!(msg, &buf[..]);
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_send_vectored_fds_unix_stream() {
+ let (s1, s2) = or_panic!(UnixStream::pair());
+
+ let buf1 = [1; 8];
+ let bufs_send = &[IoSlice::new(&buf1[..])][..];
+
+ let mut ancillary1_buffer = [0; 128];
+ let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
+ assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..]));
+
+ let usize = or_panic!(s1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1));
+ assert_eq!(usize, 8);
+
+ let mut buf2 = [0; 8];
+ let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
+
+ let mut ancillary2_buffer = [0; 128];
+ let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
+
+ let usize = or_panic!(s2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2));
+ assert_eq!(usize, 8);
+ assert_eq!(buf1, buf2);
+
+ let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
+ assert_eq!(ancillary_data_vec.len(), 1);
+ if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() {
+ let fd_vec = Vec::from_iter(scm_rights);
+ assert_eq!(fd_vec.len(), 1);
+ unsafe {
+ libc::close(fd_vec[0]);
+ }
+ } else {
+ unreachable!("must be ScmRights");
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "linux",))]
+#[test]
+fn test_send_vectored_with_ancillary_to_unix_datagram() {
+ fn getpid() -> libc::pid_t {
+ unsafe { libc::getpid() }
+ }
+
+ fn getuid() -> libc::uid_t {
+ unsafe { libc::getuid() }
+ }
+
+ fn getgid() -> libc::gid_t {
+ unsafe { libc::getgid() }
+ }
+
+ 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));
+
+ or_panic!(bsock2.set_passcred(true));
+
+ let buf1 = [1; 8];
+ let bufs_send = &[IoSlice::new(&buf1[..])][..];
+
+ let mut ancillary1_buffer = [0; 128];
+ let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
+ let mut cred1 = SocketCred::new();
+ cred1.set_pid(getpid());
+ cred1.set_uid(getuid());
+ cred1.set_gid(getgid());
+ assert!(ancillary1.add_creds(&[cred1.clone()][..]));
+
+ let usize =
+ or_panic!(bsock1.send_vectored_with_ancillary_to(&bufs_send, &mut ancillary1, &path2));
+ assert_eq!(usize, 8);
+
+ let mut buf2 = [0; 8];
+ let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
+
+ let mut ancillary2_buffer = [0; 128];
+ let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
+
+ let (usize, truncated, _addr) =
+ or_panic!(bsock2.recv_vectored_with_ancillary_from(&mut bufs_recv, &mut ancillary2));
+ assert_eq!(ancillary2.truncated(), false);
+ assert_eq!(usize, 8);
+ assert_eq!(truncated, false);
+ assert_eq!(buf1, buf2);
+
+ let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
+ assert_eq!(ancillary_data_vec.len(), 1);
+ if let AncillaryData::ScmCredentials(scm_credentials) =
+ ancillary_data_vec.pop().unwrap().unwrap()
+ {
+ let cred_vec = Vec::from_iter(scm_credentials);
+ assert_eq!(cred_vec.len(), 1);
+ assert_eq!(cred1.get_pid(), cred_vec[0].get_pid());
+ assert_eq!(cred1.get_uid(), cred_vec[0].get_uid());
+ assert_eq!(cred1.get_gid(), cred_vec[0].get_gid());
+ } else {
+ unreachable!("must be ScmCredentials");
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[test]
+fn test_send_vectored_with_ancillary_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 buf1 = [1; 8];
+ let bufs_send = &[IoSlice::new(&buf1[..])][..];
+
+ let mut ancillary1_buffer = [0; 128];
+ let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
+ assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..]));
+
+ or_panic!(bsock1.connect(&path2));
+ let usize = or_panic!(bsock1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1));
+ assert_eq!(usize, 8);
+
+ let mut buf2 = [0; 8];
+ let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
+
+ let mut ancillary2_buffer = [0; 128];
+ let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
+
+ let (usize, truncated) =
+ or_panic!(bsock2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2));
+ assert_eq!(usize, 8);
+ assert_eq!(truncated, false);
+ assert_eq!(buf1, buf2);
+
+ let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
+ assert_eq!(ancillary_data_vec.len(), 1);
+ if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() {
+ let fd_vec = Vec::from_iter(scm_rights);
+ assert_eq!(fd_vec.len(), 1);
+ unsafe {
+ libc::close(fd_vec[0]);
+ }
+ } else {
+ unreachable!("must be ScmRights");
+ }
+}
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
new file mode 100644
index 000000000..09b2bfe39
--- /dev/null
+++ b/library/std/src/os/unix/process.rs
@@ -0,0 +1,466 @@
+//! Unix-specific extensions to primitives in the [`std::process`] module.
+//!
+//! [`std::process`]: crate::process
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::ffi::OsStr;
+use crate::io;
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::process;
+use crate::sealed::Sealed;
+use crate::sys;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+
+#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))]
+type UserId = u32;
+#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))]
+type GroupId = u32;
+
+#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))]
+type UserId = u16;
+#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))]
+type GroupId = u16;
+
+/// Unix-specific extensions to the [`process::Command`] builder.
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait CommandExt: Sealed {
+ /// 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: UserId) -> &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: GroupId) -> &mut process::Command;
+
+ /// Sets the supplementary group IDs for the calling process. Translates to
+ /// a `setgroups` call in the child process.
+ #[unstable(feature = "setgroups", issue = "90747")]
+ fn groups(&mut self, groups: &[GroupId]) -> &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 and Safety
+ ///
+ /// 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`, accessing environment variables through [`std::env`]
+ /// or acquiring a mutex are not guaranteed to work (due to
+ /// other threads perhaps still running when the `fork` was run).
+ ///
+ /// For further details refer to the [POSIX fork() specification]
+ /// and the equivalent documentation for any targeted
+ /// platform, especially the requirements around *async-signal-safety*.
+ ///
+ /// This also means that all resources such as file descriptors and
+ /// memory-mapped regions got duplicated. It is your responsibility to make
+ /// sure that the closure does not violate library invariants by making
+ /// invalid use of these duplicates.
+ ///
+ /// Panicking in the closure is safe only if all the format arguments for the
+ /// panic message can be safely formatted; this is because although
+ /// `Command` calls [`std::panic::always_abort`](crate::panic::always_abort)
+ /// before calling the pre_exec hook, panic will still try to format the
+ /// panic message.
+ ///
+ /// When this closure is run, aspects such as the stdio file descriptors and
+ /// working directory have successfully been changed, so output to these
+ /// locations might not appear where intended.
+ ///
+ /// [POSIX fork() specification]:
+ /// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html
+ /// [`std::env`]: mod@crate::env
+ #[stable(feature = "process_pre_exec", since = "1.34.0")]
+ unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
+ where
+ F: FnMut() -> io::Result<()> + Send + Sync + 'static;
+
+ /// Schedules a closure to be run just before the `exec` function is
+ /// invoked.
+ ///
+ /// This method is stable and usable, but it should be unsafe. To fix
+ /// that, it got deprecated in favor of the unsafe [`pre_exec`].
+ ///
+ /// [`pre_exec`]: CommandExt::pre_exec
+ #[stable(feature = "process_exec", since = "1.15.0")]
+ #[deprecated(since = "1.37.0", note = "should be unsafe, use `pre_exec` instead")]
+ fn before_exec<F>(&mut self, f: F) -> &mut process::Command
+ where
+ F: FnMut() -> io::Result<()> + Send + Sync + 'static,
+ {
+ unsafe { self.pre_exec(f) }
+ }
+
+ /// 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.
+ ///
+ /// # 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;
+
+ /// Set executable argument
+ ///
+ /// Set the first process argument, `argv[0]`, to something other than the
+ /// default executable path.
+ #[stable(feature = "process_set_argv0", since = "1.45.0")]
+ fn arg0<S>(&mut self, arg: S) -> &mut process::Command
+ where
+ S: AsRef<OsStr>;
+
+ /// Sets the process group ID (PGID) of the child process. Equivalent to a
+ /// `setpgid` call in the child process, but may be more efficient.
+ ///
+ /// Process groups determine which processes receive signals.
+ ///
+ /// # Examples
+ ///
+ /// Pressing Ctrl-C in a terminal will send SIGINT to all processes in
+ /// the current foreground process group. By spawning the `sleep`
+ /// subprocess in a new process group, it will not receive SIGINT from the
+ /// terminal.
+ ///
+ /// The parent process could install a signal handler and manage the
+ /// subprocess on its own terms.
+ ///
+ /// A process group ID of 0 will use the process ID as the PGID.
+ ///
+ /// ```no_run
+ /// use std::process::Command;
+ /// use std::os::unix::process::CommandExt;
+ ///
+ /// Command::new("sleep")
+ /// .arg("10")
+ /// .process_group(0)
+ /// .spawn()?
+ /// .wait()?;
+ /// #
+ /// # Ok::<_, Box<dyn std::error::Error>>(())
+ /// ```
+ #[stable(feature = "process_set_process_group", since = "1.64.0")]
+ fn process_group(&mut self, pgroup: i32) -> &mut process::Command;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl CommandExt for process::Command {
+ fn uid(&mut self, id: UserId) -> &mut process::Command {
+ self.as_inner_mut().uid(id);
+ self
+ }
+
+ fn gid(&mut self, id: GroupId) -> &mut process::Command {
+ self.as_inner_mut().gid(id);
+ self
+ }
+
+ fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command {
+ self.as_inner_mut().groups(groups);
+ self
+ }
+
+ unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
+ where
+ F: FnMut() -> io::Result<()> + Send + Sync + 'static,
+ {
+ self.as_inner_mut().pre_exec(Box::new(f));
+ self
+ }
+
+ fn exec(&mut self) -> io::Error {
+ // NOTE: This may *not* be safe to call after `libc::fork`, because it
+ // may allocate. That may be worth fixing at some point in the future.
+ self.as_inner_mut().exec(sys::process::Stdio::Inherit)
+ }
+
+ fn arg0<S>(&mut self, arg: S) -> &mut process::Command
+ where
+ S: AsRef<OsStr>,
+ {
+ self.as_inner_mut().set_arg_0(arg.as_ref());
+ self
+ }
+
+ fn process_group(&mut self, pgroup: i32) -> &mut process::Command {
+ self.as_inner_mut().pgroup(pgroup);
+ self
+ }
+}
+
+/// Unix-specific extensions to [`process::ExitStatus`] and
+/// [`ExitStatusError`](process::ExitStatusError).
+///
+/// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as
+/// passed to the `_exit` system call or returned by
+/// [`ExitStatus::code()`](crate::process::ExitStatus::code). It represents **any wait status**
+/// as returned by one of the `wait` family of system
+/// calls.
+///
+/// A Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but can also
+/// represent other kinds of process event.
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait ExitStatusExt: Sealed {
+ /// Creates a new `ExitStatus` or `ExitStatusError` from the raw underlying integer status
+ /// value from `wait`
+ ///
+ /// The value should be a **wait status, not an exit status**.
+ ///
+ /// # Panics
+ ///
+ /// Panics on an attempt to make an `ExitStatusError` from a wait status of `0`.
+ ///
+ /// Making an `ExitStatus` always succeeds and never panics.
+ #[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.
+ ///
+ /// In other words, if `WIFSIGNALED`, this returns `WTERMSIG`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn signal(&self) -> Option<i32>;
+
+ /// If the process was terminated by a signal, says whether it dumped core.
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
+ fn core_dumped(&self) -> bool;
+
+ /// If the process was stopped by a signal, returns that signal.
+ ///
+ /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`. This is only possible if the status came from
+ /// a `wait` system call which was passed `WUNTRACED`, and was then converted into an `ExitStatus`.
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
+ fn stopped_signal(&self) -> Option<i32>;
+
+ /// Whether the process was continued from a stopped status.
+ ///
+ /// Ie, `WIFCONTINUED`. This is only possible if the status came from a `wait` system call
+ /// which was passed `WCONTINUED`, and was then converted into an `ExitStatus`.
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
+ fn continued(&self) -> bool;
+
+ /// Returns the underlying raw `wait` status.
+ ///
+ /// The returned integer is a **wait status, not an exit status**.
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
+ fn into_raw(self) -> 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()
+ }
+
+ fn core_dumped(&self) -> bool {
+ self.as_inner().core_dumped()
+ }
+
+ fn stopped_signal(&self) -> Option<i32> {
+ self.as_inner().stopped_signal()
+ }
+
+ fn continued(&self) -> bool {
+ self.as_inner().continued()
+ }
+
+ fn into_raw(self) -> i32 {
+ self.as_inner().into_raw().into()
+ }
+}
+
+#[unstable(feature = "exit_status_error", issue = "84908")]
+impl ExitStatusExt for process::ExitStatusError {
+ fn from_raw(raw: i32) -> Self {
+ process::ExitStatus::from_raw(raw)
+ .exit_ok()
+ .expect_err("<ExitStatusError as ExitStatusExt>::from_raw(0) but zero is not an error")
+ }
+
+ fn signal(&self) -> Option<i32> {
+ self.into_status().signal()
+ }
+
+ fn core_dumped(&self) -> bool {
+ self.into_status().core_dumped()
+ }
+
+ fn stopped_signal(&self) -> Option<i32> {
+ self.into_status().stopped_signal()
+ }
+
+ fn continued(&self) -> bool {
+ self.into_status().continued()
+ }
+
+ fn into_raw(self) -> i32 {
+ self.into_status().into_raw()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawFd for process::Stdio {
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
+ let fd = sys::fd::FileDesc::from_raw_fd(fd);
+ let io = sys::process::Stdio::Fd(fd);
+ process::Stdio::from_inner(io)
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedFd> for process::Stdio {
+ #[inline]
+ fn from(fd: OwnedFd) -> process::Stdio {
+ let fd = sys::fd::FileDesc::from_inner(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 {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_raw_fd()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdout {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_raw_fd()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStderr {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_raw_fd()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdin {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_inner().into_raw_fd()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdout {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_inner().into_raw_fd()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStderr {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_inner().into_raw_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for crate::process::ChildStdin {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.as_inner().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStdin> for OwnedFd {
+ #[inline]
+ fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd {
+ child_stdin.into_inner().into_inner().into_inner()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for crate::process::ChildStdout {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.as_inner().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStdout> for OwnedFd {
+ #[inline]
+ fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd {
+ child_stdout.into_inner().into_inner().into_inner()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for crate::process::ChildStderr {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.as_inner().as_fd()
+ }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStderr> for OwnedFd {
+ #[inline]
+ fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd {
+ child_stderr.into_inner().into_inner().into_inner()
+ }
+}
+
+/// Returns the OS-assigned process identifier associated with this process's parent.
+#[must_use]
+#[stable(feature = "unix_ppid", since = "1.27.0")]
+pub fn parent_id() -> u32 {
+ crate::sys::os::getppid()
+}
diff --git a/library/std/src/os/unix/raw.rs b/library/std/src/os/unix/raw.rs
new file mode 100644
index 000000000..fe761627b
--- /dev/null
+++ b/library/std/src/os/unix/raw.rs
@@ -0,0 +1,33 @@
+//! Unix-specific primitives available on all unix platforms.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(non_camel_case_types)]
+pub type uid_t = u32;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(non_camel_case_types)]
+pub type gid_t = u32;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(non_camel_case_types)]
+pub type pid_t = i32;
+
+#[doc(inline)]
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub use super::platform::raw::pthread_t;
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use super::platform::raw::{blkcnt_t, time_t};
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use super::platform::raw::{blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t};
diff --git a/library/std/src/os/unix/thread.rs b/library/std/src/os/unix/thread.rs
new file mode 100644
index 000000000..03dcc3a4f
--- /dev/null
+++ b/library/std/src/os/unix/thread.rs
@@ -0,0 +1,41 @@
+//! Unix-specific extensions to primitives in the [`std::thread`] module.
+//!
+//! [`std::thread`]: crate::thread
+
+#![stable(feature = "thread_extensions", since = "1.9.0")]
+
+#[allow(deprecated)]
+use crate::os::unix::raw::pthread_t;
+use crate::sys_common::{AsInner, IntoInner};
+use crate::thread::JoinHandle;
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+#[allow(deprecated)]
+pub type RawPthread = pthread_t;
+
+/// Unix-specific extensions to [`JoinHandle`].
+#[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
+ }
+}
diff --git a/library/std/src/os/unix/ucred.rs b/library/std/src/os/unix/ucred.rs
new file mode 100644
index 000000000..ae4faf27b
--- /dev/null
+++ b/library/std/src/os/unix/ucred.rs
@@ -0,0 +1,136 @@
+//! Unix peer credentials.
+
+// NOTE: Code in this file is heavily based on work done in PR 13 from the tokio-uds repository on
+// GitHub.
+//
+// For reference, the link is here: https://github.com/tokio-rs/tokio-uds/pull/13
+// Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work.
+
+use libc::{gid_t, pid_t, uid_t};
+
+/// Credentials for a UNIX process for credentials passing.
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub struct UCred {
+ /// The UID part of the peer credential. This is the effective UID of the process at the domain
+ /// socket's endpoint.
+ pub uid: uid_t,
+ /// The GID part of the peer credential. This is the effective GID of the process at the domain
+ /// socket's endpoint.
+ pub gid: gid_t,
+ /// The PID part of the peer credential. This field is optional because the PID part of the
+ /// peer credentials is not supported on every platform. On platforms where the mechanism to
+ /// discover the PID exists, this field will be populated to the PID of the process at the
+ /// domain socket's endpoint. Otherwise, it will be set to None.
+ pub pid: Option<pid_t>,
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use self::impl_linux::peer_cred;
+
+#[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd"
+))]
+pub use self::impl_bsd::peer_cred;
+
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+pub use self::impl_mac::peer_cred;
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub mod impl_linux {
+ use super::UCred;
+ use crate::os::unix::io::AsRawFd;
+ use crate::os::unix::net::UnixStream;
+ use crate::{io, mem};
+ use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED};
+
+ pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+ let ucred_size = mem::size_of::<ucred>();
+
+ // Trivial sanity checks.
+ assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
+ assert!(ucred_size <= u32::MAX as usize);
+
+ let mut ucred_size = ucred_size as socklen_t;
+ let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 };
+
+ unsafe {
+ let ret = getsockopt(
+ socket.as_raw_fd(),
+ SOL_SOCKET,
+ SO_PEERCRED,
+ &mut ucred as *mut ucred as *mut c_void,
+ &mut ucred_size,
+ );
+
+ if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
+ Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) })
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+ }
+}
+
+#[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd"
+))]
+pub mod impl_bsd {
+ use super::UCred;
+ use crate::io;
+ use crate::os::unix::io::AsRawFd;
+ use crate::os::unix::net::UnixStream;
+
+ pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+ let mut cred = UCred { uid: 1, gid: 1, pid: None };
+ unsafe {
+ let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
+
+ if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) }
+ }
+ }
+}
+
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
+pub mod impl_mac {
+ use super::UCred;
+ use crate::os::unix::io::AsRawFd;
+ use crate::os::unix::net::UnixStream;
+ use crate::{io, mem};
+ use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, LOCAL_PEERPID, SOL_LOCAL};
+
+ pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+ let mut cred = UCred { uid: 1, gid: 1, pid: None };
+ unsafe {
+ let ret = getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
+
+ if ret != 0 {
+ return Err(io::Error::last_os_error());
+ }
+
+ let mut pid: pid_t = 1;
+ let mut pid_size = mem::size_of::<pid_t>() as socklen_t;
+
+ let ret = getsockopt(
+ socket.as_raw_fd(),
+ SOL_LOCAL,
+ LOCAL_PEERPID,
+ &mut pid as *mut pid_t as *mut c_void,
+ &mut pid_size,
+ );
+
+ if ret == 0 && pid_size as usize == mem::size_of::<pid_t>() {
+ cred.pid = Some(pid);
+ Ok(cred)
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+ }
+}
diff --git a/library/std/src/os/unix/ucred/tests.rs b/library/std/src/os/unix/ucred/tests.rs
new file mode 100644
index 000000000..e63a2fc24
--- /dev/null
+++ b/library/std/src/os/unix/ucred/tests.rs
@@ -0,0 +1,39 @@
+use crate::os::unix::net::UnixStream;
+use libc::{getegid, geteuid, getpid};
+
+#[test]
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "watchos",
+ target_os = "openbsd"
+))]
+fn test_socket_pair() {
+ // Create two connected sockets and get their peer credentials. They should be equal.
+ let (sock_a, sock_b) = UnixStream::pair().unwrap();
+ let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap());
+ assert_eq!(cred_a, cred_b);
+
+ // Check that the UID and GIDs match up.
+ let uid = unsafe { geteuid() };
+ let gid = unsafe { getegid() };
+ assert_eq!(cred_a.uid, uid);
+ assert_eq!(cred_a.gid, gid);
+}
+
+#[test]
+#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos", target_os = "watchos"))]
+fn test_socket_pair_pids(arg: Type) -> RetType {
+ // Create two connected sockets and get their peer credentials.
+ let (sock_a, sock_b) = UnixStream::pair().unwrap();
+ let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap());
+
+ // On supported platforms (see the cfg above), the credentials should always include the PID.
+ let pid = unsafe { getpid() };
+ assert_eq!(cred_a.pid, Some(pid));
+ assert_eq!(cred_b.pid, Some(pid));
+}