@@ -1537,6 +1537,17 @@ impl SockaddrLike for SockaddrStorage {
1537
1537
let mut ss: libc:: sockaddr_storage = mem:: zeroed ( ) ;
1538
1538
let ssp = & mut ss as * mut libc:: sockaddr_storage as * mut u8 ;
1539
1539
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
+ }
1540
1551
Some ( Self { ss } )
1541
1552
}
1542
1553
} else {
@@ -1598,6 +1609,21 @@ impl SockaddrLike for SockaddrStorage {
1598
1609
}
1599
1610
}
1600
1611
}
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
+ }
1601
1627
}
1602
1628
1603
1629
macro_rules! accessors {
@@ -1635,6 +1661,64 @@ macro_rules! accessors {
1635
1661
}
1636
1662
1637
1663
impl 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
+
1638
1722
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
1639
1723
accessors ! { as_alg_addr, as_alg_addr_mut, AlgAddr ,
1640
1724
AddressFamily :: Alg , libc:: sockaddr_alg, alg}
@@ -3064,6 +3148,44 @@ mod tests {
3064
3148
}
3065
3149
}
3066
3150
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
+
3067
3189
mod unixaddr {
3068
3190
use super :: * ;
3069
3191
0 commit comments