Repository: rust-lang/socket2
Pull request #414 (2023-03-20 16:57:19)

Use more types from windows_sys crate


Patch:
diff --git a/.cirrus.yml b/.cirrus.yml
index ba33073..32f3dc0 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -1,5 +1,5 @@
 freebsd_instance:
-  image_family: freebsd-13-0
+  image_family: freebsd-13-1
 
 env:
   RUST_BACKTRACE: full
@@ -7,7 +7,6 @@ env:
 task:
   name: FreeBSD
   setup_script:
-    - pkg install -y curl
     - curl https://sh.rustup.rs -sSf --output rustup.sh
     - sh rustup.sh -y --profile minimal
   cargo_cache:
diff --git a/src/sockaddr.rs b/src/sockaddr.rs
index 5dbecaa..5334227 100644
--- a/src/sockaddr.rs
+++ b/src/sockaddr.rs
@@ -25,16 +25,6 @@ pub struct SockAddr {
 
 #[allow(clippy::len_without_is_empty)]
 impl SockAddr {
-    /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
-    ///
-    /// Returns an error if the path is longer than `SUN_LEN`.
-    pub fn unix<P>(path: P) -> io::Result<SockAddr>
-    where
-        P: AsRef<Path>,
-    {
-        crate::sys::unix_sockaddr(path.as_ref())
-    }
-
     /// Create a `SockAddr` from the underlying storage and its length.
     ///
     /// # Safety
@@ -153,6 +143,26 @@ impl SockAddr {
         })
     }
 
+    /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
+    ///
+    /// Returns an error if the path is longer than `SUN_LEN`.
+    pub fn unix<P>(path: P) -> io::Result<SockAddr>
+    where
+        P: AsRef<Path>,
+    {
+        crate::sys::unix_sockaddr(path.as_ref())
+    }
+
+    /// Set the length of the address.
+    ///
+    /// # Safety
+    ///
+    /// Caller must ensure that the address up to `length` bytes are properly
+    /// initialised.
+    pub unsafe fn set_length(&mut self, length: socklen_t) {
+        self.len = length;
+    }
+
     /// Returns this address's family.
     pub const fn family(&self) -> sa_family_t {
         self.storage.ss_family
@@ -250,6 +260,14 @@ impl SockAddr {
             _ => None,
         }
     }
+
+    /// Returns the initialised storage bytes.
+    fn as_bytes(&self) -> &[u8] {
+        // SAFETY: `self.storage` is a C struct which can always be treated a
+        // slice of bytes. Futhermore we ensure we don't read any unitialised
+        // bytes by using `self.len`.
+        unsafe { std::slice::from_raw_parts(self.as_ptr().cast(), self.len as usize) }
+    }
 }
 
 impl From<SocketAddr> for SockAddr {
@@ -329,11 +347,7 @@ impl fmt::Debug for SockAddr {
 
 impl PartialEq for SockAddr {
     fn eq(&self, other: &Self) -> bool {
-        unsafe {
-            let these_bytes: &[u8] = any_as_u8_slice(&self.storage, self.len as usize);
-            let those_bytes: &[u8] = any_as_u8_slice(&other.storage, other.len as usize);
-            these_bytes == those_bytes
-        }
+        self.as_bytes() == other.as_bytes()
     }
 }
 
@@ -341,17 +355,10 @@ impl Eq for SockAddr {}
 
 impl Hash for SockAddr {
     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
-        unsafe {
-            let these_bytes: &[u8] = any_as_u8_slice(&self.storage, self.len as usize);
-            these_bytes.hash(state);
-        }
+        self.as_bytes().hash(state);
     }
 }
 
-unsafe fn any_as_u8_slice<T: Sized>(p: &T, size: usize) -> &[u8] {
-    ::std::slice::from_raw_parts((p as *const T) as *const u8, size)
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/src/sys/unix.rs b/src/sys/unix.rs
index 811849e..e852ea9 100644
--- a/src/sys/unix.rs
+++ b/src/sys/unix.rs
@@ -741,8 +741,17 @@ impl SockAddr {
         }
     }
 
-    /// Returns this address as a `Path` reference if it is an `AF_UNIX` pathname address, otherwise
-    /// returns `None`.
+    /// Returns this address as Unix `SocketAddr` if it is an `AF_UNIX` pathname
+    /// address, otherwise returns `None`.
+    pub fn as_unix(&self) -> Option<std::os::unix::net::SocketAddr> {
+        let path = self.as_pathname()?;
+        // SAFETY: we can represent this as a valid pathname, then so can the
+        // standard library.
+        Some(std::os::unix::net::SocketAddr::from_pathname(path).unwrap())
+    }
+
+    /// Returns this address as a `Path` reference if it is an `AF_UNIX`
+    /// pathname address, otherwise returns `None`.
     pub fn as_pathname(&self) -> Option<&Path> {
         self.as_sockaddr_un().and_then(|storage| {
             (self.len() > offset_of_path(storage) as u32 && storage.sun_path[0] != 0).then(|| {
diff --git a/src/sys/windows.rs b/src/sys/windows.rs
index 3a517ac..a4d07e2 100644
--- a/src/sys/windows.rs
+++ b/src/sys/windows.rs
@@ -31,7 +31,7 @@ use windows_sys::Win32::System::Threading::INFINITE;
 use crate::{RecvFlags, SockAddr, TcpKeepalive, Type};
 
 #[allow(non_camel_case_types)]
-pub(crate) type c_int = i32;
+pub(crate) type c_int = std::os::raw::c_int;
 
 /// Fake MSG_TRUNC flag for the [`RecvFlags`] struct.
 ///
@@ -61,9 +61,9 @@ pub(crate) use windows_sys::Win32::Networking::WinSock::{
     SOCKADDR_STORAGE as sockaddr_storage,
 };
 #[allow(non_camel_case_types)]
-pub(crate) type sa_family_t = u16;
+pub(crate) type sa_family_t = windows_sys::Win32::Networking::WinSock::sa_family_t;
 #[allow(non_camel_case_types)]
-pub(crate) type socklen_t = i32;
+pub(crate) type socklen_t = windows_sys::Win32::Networking::WinSock::socklen_t;
 // Used in `Socket`.
 #[cfg(feature = "all")]
 pub(crate) use windows_sys::Win32::Networking::WinSock::IP_HDRINCL;
@@ -110,7 +110,7 @@ impl_debug!(
     self::AF_INET,
     self::AF_INET6,
     self::AF_UNIX,
-    self::AF_UNSPEC, // = 0.
+    self::AF_UNSPEC,
 );
 
 /// Windows only API.


Test patch:
diff --git a/tests/socket.rs b/tests/socket.rs
index 33b92f8..2ea8c25 100644
--- a/tests/socket.rs
+++ b/tests/socket.rs
@@ -155,6 +155,8 @@ fn socket_address_unix() {
         assert!(!addr.is_unnamed());
         assert_eq!(addr.as_pathname(), Some(Path::new(string)));
         assert_eq!(addr.as_abstract_namespace(), None);
+        let unix = addr.as_unix().unwrap();
+        assert_eq!(addr.as_pathname(), unix.as_pathname());
     }
 }
 
@@ -172,6 +174,7 @@ fn socket_address_unix_unnamed() {
         assert!(addr.is_unnamed());
         assert_eq!(addr.as_pathname(), None);
         assert_eq!(addr.as_abstract_namespace(), None);
+        assert!(addr.as_unix().is_none());
     }
 }