summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md6
-rw-r--r--src/sys/socket/addr.rs122
2 files changed, 127 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 917094aa..fba51823 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,9 @@ This project adheres to [Semantic Versioning](https://semver.org/).
## [Unreleased] - ReleaseDate
### Added
-- Add `MntFlags` and `unmount` on all of the BSDs.
+- Added `SockaddrStorage::{as_unix_addr, as_unix_addr_mut}`
+ ([#1871](https://github.com/nix-rust/nix/pull/1871))
+- Added `MntFlags` and `unmount` on all of the BSDs.
([#1849](https://github.com/nix-rust/nix/pull/1849))
- Added a 'Statfs::flags' method.
([#1849](https://github.com/nix-rust/nix/pull/1849))
@@ -44,6 +46,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
### Fixed
+- Fixed using `SockaddrStorage` to store a Unix-domain socket address on Linux.
+ ([#1871](https://github.com/nix-rust/nix/pull/1871))
- Fix microsecond calculation for `TimeSpec`.
([#1801](https://github.com/nix-rust/nix/pull/1801))
- Fix `User::from_name` and `Group::from_name` panicking
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index c7b5f29e..b80d78c1 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -1536,6 +1536,17 @@ impl SockaddrLike for SockaddrStorage {
let mut ss: libc::sockaddr_storage = mem::zeroed();
let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8;
ptr::copy(addr as *const u8, ssp, len as usize);
+ #[cfg(any(
+ target_os = "android",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "linux"
+ ))]
+ if i32::from(ss.ss_family) == libc::AF_UNIX {
+ // Safe because we UnixAddr is strictly smaller than
+ // SockaddrStorage, and we just initialized the structure.
+ (*(&mut ss as *mut libc::sockaddr_storage as *mut UnixAddr)).sun_len = len as u8;
+ }
Some(Self { ss })
}
} else {
@@ -1597,6 +1608,21 @@ impl SockaddrLike for SockaddrStorage {
}
}
}
+
+ #[cfg(any(
+ target_os = "android",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "linux"
+ ))]
+ fn len(&self) -> libc::socklen_t {
+ match self.as_unix_addr() {
+ // The UnixAddr type knows its own length
+ Some(ua) => ua.len(),
+ // For all else, we're just a boring SockaddrStorage
+ None => mem::size_of_val(self) as libc::socklen_t
+ }
+ }
}
macro_rules! accessors {
@@ -1634,6 +1660,64 @@ macro_rules! accessors {
}
impl SockaddrStorage {
+ /// Downcast to an immutable `[UnixAddr]` reference.
+ pub fn as_unix_addr(&self) -> Option<&UnixAddr> {
+ cfg_if! {
+ if #[cfg(any(target_os = "android",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "linux"
+ ))]
+ {
+ let p = unsafe{ &self.ss as *const libc::sockaddr_storage };
+ // Safe because UnixAddr is strictly smaller than
+ // sockaddr_storage, and we're fully initialized
+ let len = unsafe {
+ (*(p as *const UnixAddr )).sun_len as usize
+ };
+ } else {
+ let len = self.len() as usize;
+ }
+ }
+ // Sanity checks
+ if self.family() != Some(AddressFamily::Unix) ||
+ len < offset_of!(libc::sockaddr_un, sun_path) ||
+ len > mem::size_of::<libc::sockaddr_un>() {
+ None
+ } else {
+ Some(unsafe{&self.su})
+ }
+ }
+
+ /// Downcast to a mutable `[UnixAddr]` reference.
+ pub fn as_unix_addr_mut(&mut self) -> Option<&mut UnixAddr> {
+ cfg_if! {
+ if #[cfg(any(target_os = "android",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "linux"
+ ))]
+ {
+ let p = unsafe{ &self.ss as *const libc::sockaddr_storage };
+ // Safe because UnixAddr is strictly smaller than
+ // sockaddr_storage, and we're fully initialized
+ let len = unsafe {
+ (*(p as *const UnixAddr )).sun_len as usize
+ };
+ } else {
+ let len = self.len() as usize;
+ }
+ }
+ // Sanity checks
+ if self.family() != Some(AddressFamily::Unix) ||
+ len < offset_of!(libc::sockaddr_un, sun_path) ||
+ len > mem::size_of::<libc::sockaddr_un>() {
+ None
+ } else {
+ Some(unsafe{&mut self.su})
+ }
+ }
+
#[cfg(any(target_os = "android", target_os = "linux"))]
accessors! {as_alg_addr, as_alg_addr_mut, AlgAddr,
AddressFamily::Alg, libc::sockaddr_alg, alg}
@@ -3063,6 +3147,44 @@ mod tests {
}
}
+ mod sockaddr_storage {
+ use super::*;
+
+ #[test]
+ fn from_sockaddr_un_named() {
+ let ua = UnixAddr::new("/var/run/mysock").unwrap();
+ let ptr = ua.as_ptr() as *const libc::sockaddr;
+ let ss = unsafe {
+ SockaddrStorage::from_raw(ptr, Some(ua.len()))
+ }.unwrap();
+ assert_eq!(ss.len(), ua.len());
+ }
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[test]
+ fn from_sockaddr_un_abstract_named() {
+ let name = String::from("nix\0abstract\0test");
+ let ua = UnixAddr::new_abstract(name.as_bytes()).unwrap();
+ let ptr = ua.as_ptr() as *const libc::sockaddr;
+ let ss = unsafe {
+ SockaddrStorage::from_raw(ptr, Some(ua.len()))
+ }.unwrap();
+ assert_eq!(ss.len(), ua.len());
+ }
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[test]
+ fn from_sockaddr_un_abstract_unnamed() {
+ let empty = String::new();
+ let ua = UnixAddr::new_abstract(empty.as_bytes()).unwrap();
+ let ptr = ua.as_ptr() as *const libc::sockaddr;
+ let ss = unsafe {
+ SockaddrStorage::from_raw(ptr, Some(ua.len()))
+ }.unwrap();
+ assert_eq!(ss.len(), ua.len());
+ }
+ }
+
mod unixaddr {
use super::*;