@@ -1536,6 +1536,17 @@ impl SockaddrLike for SockaddrStorage {
15361536 let mut ss: libc:: sockaddr_storage = mem:: zeroed ( ) ;
15371537 let ssp = & mut ss as * mut libc:: sockaddr_storage as * mut u8 ;
15381538 ptr:: copy ( addr as * const u8 , ssp, len as usize ) ;
1539+ #[ cfg( any(
1540+ target_os = "android" ,
1541+ target_os = "fuchsia" ,
1542+ target_os = "illumos" ,
1543+ target_os = "linux"
1544+ ) ) ]
1545+ if i32:: from ( ss. ss_family ) == libc:: AF_UNIX {
1546+ // Safe because we UnixAddr is strictly smaller than
1547+ // SockaddrStorage, and we just initialized the structure.
1548+ ( * ( & mut ss as * mut libc:: sockaddr_storage as * mut UnixAddr ) ) . sun_len = len as u8 ;
1549+ }
15391550 Some ( Self { ss } )
15401551 }
15411552 } else {
@@ -1597,6 +1608,21 @@ impl SockaddrLike for SockaddrStorage {
15971608 }
15981609 }
15991610 }
1611+
1612+ #[ cfg( any(
1613+ target_os = "android" ,
1614+ target_os = "fuchsia" ,
1615+ target_os = "illumos" ,
1616+ target_os = "linux"
1617+ ) ) ]
1618+ fn len ( & self ) -> libc:: socklen_t {
1619+ match self . as_unix_addr ( ) {
1620+ // The UnixAddr type knows its own length
1621+ Some ( ua) => ua. len ( ) ,
1622+ // For all else, we're just a boring SockaddrStorage
1623+ None => mem:: size_of_val ( self ) as libc:: socklen_t
1624+ }
1625+ }
16001626}
16011627
16021628macro_rules! accessors {
@@ -1634,6 +1660,64 @@ macro_rules! accessors {
16341660}
16351661
16361662impl SockaddrStorage {
1663+ /// Downcast to an immutable `[UnixAddr]` reference.
1664+ pub fn as_unix_addr ( & self ) -> Option < & UnixAddr > {
1665+ cfg_if ! {
1666+ if #[ cfg( any( target_os = "android" ,
1667+ target_os = "fuchsia" ,
1668+ target_os = "illumos" ,
1669+ target_os = "linux"
1670+ ) ) ]
1671+ {
1672+ let p = unsafe { & self . ss as * const libc:: sockaddr_storage } ;
1673+ // Safe because UnixAddr is strictly smaller than
1674+ // sockaddr_storage, and we're fully initialized
1675+ let len = unsafe {
1676+ ( * ( p as * const UnixAddr ) ) . sun_len as usize
1677+ } ;
1678+ } else {
1679+ let len = self . len( ) as usize ;
1680+ }
1681+ }
1682+ // Sanity checks
1683+ if self . family ( ) != Some ( AddressFamily :: Unix ) ||
1684+ len < offset_of ! ( libc:: sockaddr_un, sun_path) ||
1685+ len > mem:: size_of :: < libc:: sockaddr_un > ( ) {
1686+ None
1687+ } else {
1688+ Some ( unsafe { & self . su } )
1689+ }
1690+ }
1691+
1692+ /// Downcast to a mutable `[UnixAddr]` reference.
1693+ pub fn as_unix_addr_mut ( & mut self ) -> Option < & mut UnixAddr > {
1694+ cfg_if ! {
1695+ if #[ cfg( any( target_os = "android" ,
1696+ target_os = "fuchsia" ,
1697+ target_os = "illumos" ,
1698+ target_os = "linux"
1699+ ) ) ]
1700+ {
1701+ let p = unsafe { & self . ss as * const libc:: sockaddr_storage } ;
1702+ // Safe because UnixAddr is strictly smaller than
1703+ // sockaddr_storage, and we're fully initialized
1704+ let len = unsafe {
1705+ ( * ( p as * const UnixAddr ) ) . sun_len as usize
1706+ } ;
1707+ } else {
1708+ let len = self . len( ) as usize ;
1709+ }
1710+ }
1711+ // Sanity checks
1712+ if self . family ( ) != Some ( AddressFamily :: Unix ) ||
1713+ len < offset_of ! ( libc:: sockaddr_un, sun_path) ||
1714+ len > mem:: size_of :: < libc:: sockaddr_un > ( ) {
1715+ None
1716+ } else {
1717+ Some ( unsafe { & mut self . su } )
1718+ }
1719+ }
1720+
16371721 #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
16381722 accessors ! { as_alg_addr, as_alg_addr_mut, AlgAddr ,
16391723 AddressFamily :: Alg , libc:: sockaddr_alg, alg}
@@ -3063,6 +3147,44 @@ mod tests {
30633147 }
30643148 }
30653149
3150+ mod sockaddr_storage {
3151+ use super :: * ;
3152+
3153+ #[ test]
3154+ fn from_sockaddr_un_named ( ) {
3155+ let ua = UnixAddr :: new ( "/var/run/mysock" ) . unwrap ( ) ;
3156+ let ptr = ua. as_ptr ( ) as * const libc:: sockaddr ;
3157+ let ss = unsafe {
3158+ SockaddrStorage :: from_raw ( ptr, Some ( ua. len ( ) ) )
3159+ } . unwrap ( ) ;
3160+ assert_eq ! ( ss. len( ) , ua. len( ) ) ;
3161+ }
3162+
3163+ #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
3164+ #[ test]
3165+ fn from_sockaddr_un_abstract_named ( ) {
3166+ let name = String :: from ( "nix\0 abstract\0 test" ) ;
3167+ let ua = UnixAddr :: new_abstract ( name. as_bytes ( ) ) . unwrap ( ) ;
3168+ let ptr = ua. as_ptr ( ) as * const libc:: sockaddr ;
3169+ let ss = unsafe {
3170+ SockaddrStorage :: from_raw ( ptr, Some ( ua. len ( ) ) )
3171+ } . unwrap ( ) ;
3172+ assert_eq ! ( ss. len( ) , ua. len( ) ) ;
3173+ }
3174+
3175+ #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
3176+ #[ test]
3177+ fn from_sockaddr_un_abstract_unnamed ( ) {
3178+ let empty = String :: new ( ) ;
3179+ let ua = UnixAddr :: new_abstract ( empty. as_bytes ( ) ) . unwrap ( ) ;
3180+ let ptr = ua. as_ptr ( ) as * const libc:: sockaddr ;
3181+ let ss = unsafe {
3182+ SockaddrStorage :: from_raw ( ptr, Some ( ua. len ( ) ) )
3183+ } . unwrap ( ) ;
3184+ assert_eq ! ( ss. len( ) , ua. len( ) ) ;
3185+ }
3186+ }
3187+
30663188 mod unixaddr {
30673189 use super :: * ;
30683190
0 commit comments