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