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