1
- use nix:: sys:: socket:: { AddressFamily , InetAddr , UnixAddr , getsockname} ;
1
+ use nix:: sys:: socket:: { AddressFamily , InetAddr , SockAddr , UnixAddr , getsockname, sockaddr , sockaddr_in6 , sockaddr_storage_to_addr } ;
2
2
use std:: collections:: hash_map:: DefaultHasher ;
3
3
use std:: hash:: { Hash , Hasher } ;
4
+ use std:: mem:: { self , MaybeUninit } ;
4
5
use std:: net:: { self , Ipv6Addr , SocketAddr , SocketAddrV6 } ;
5
6
use std:: os:: unix:: io:: RawFd ;
6
7
use std:: path:: Path ;
7
8
use std:: slice;
8
9
use std:: str:: FromStr ;
9
- use libc:: c_char;
10
+ use libc:: { c_char, sockaddr_storage } ;
10
11
#[ cfg( any( target_os = "linux" , target_os= "android" ) ) ]
11
12
use crate :: * ;
12
13
@@ -33,6 +34,29 @@ pub fn test_inetv4_addr_to_sock_addr() {
33
34
assert_eq ! ( actual, inet) ;
34
35
}
35
36
37
+ #[ test]
38
+ pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr ( ) {
39
+ let actual: net:: SocketAddr = FromStr :: from_str ( "127.0.0.1:3000" ) . unwrap ( ) ;
40
+ let addr = InetAddr :: from_std ( & actual) ;
41
+ let sockaddr = SockAddr :: new_inet ( addr) ;
42
+
43
+ let ( storage, ffi_size) = {
44
+ let mut storage = MaybeUninit :: < sockaddr_storage > :: zeroed ( ) ;
45
+ let storage_ptr = storage. as_mut_ptr ( ) . cast :: < sockaddr > ( ) ;
46
+ let ( ffi_ptr, ffi_size) = sockaddr. as_ffi_pair ( ) ;
47
+ assert_eq ! ( mem:: size_of:: <sockaddr>( ) , ffi_size as usize ) ;
48
+ unsafe {
49
+ storage_ptr. copy_from_nonoverlapping ( ffi_ptr as * const sockaddr , 1 ) ;
50
+ ( storage. assume_init ( ) , ffi_size)
51
+ }
52
+ } ;
53
+
54
+ let from_storage = sockaddr_storage_to_addr ( & storage, ffi_size as usize ) . unwrap ( ) ;
55
+ assert_eq ! ( from_storage, sockaddr) ;
56
+ let from_storage = sockaddr_storage_to_addr ( & storage, mem:: size_of :: < sockaddr_storage > ( ) ) . unwrap ( ) ;
57
+ assert_eq ! ( from_storage, sockaddr) ;
58
+ }
59
+
36
60
#[ test]
37
61
pub fn test_inetv6_addr_to_sock_addr ( ) {
38
62
let port: u16 = 3000 ;
@@ -54,6 +78,33 @@ pub fn test_inetv6_addr_to_sock_addr() {
54
78
55
79
assert_eq ! ( actual, addr. to_std( ) ) ;
56
80
}
81
+ #[ test]
82
+ pub fn test_inetv6_addr_roundtrip_sockaddr_storage_to_addr ( ) {
83
+ let port: u16 = 3000 ;
84
+ let flowinfo: u32 = 1 ;
85
+ let scope_id: u32 = 2 ;
86
+ let ip: Ipv6Addr = "fe80::1" . parse ( ) . unwrap ( ) ;
87
+
88
+ let actual = SocketAddr :: V6 ( SocketAddrV6 :: new ( ip, port, flowinfo, scope_id) ) ;
89
+ let addr = InetAddr :: from_std ( & actual) ;
90
+ let sockaddr = SockAddr :: new_inet ( addr) ;
91
+
92
+ let ( storage, ffi_size) = {
93
+ let mut storage = MaybeUninit :: < sockaddr_storage > :: zeroed ( ) ;
94
+ let storage_ptr = storage. as_mut_ptr ( ) . cast :: < sockaddr_in6 > ( ) ;
95
+ let ( ffi_ptr, ffi_size) = sockaddr. as_ffi_pair ( ) ;
96
+ assert_eq ! ( mem:: size_of:: <sockaddr_in6>( ) , ffi_size as usize ) ;
97
+ unsafe {
98
+ storage_ptr. copy_from_nonoverlapping ( ( ffi_ptr as * const sockaddr ) . cast :: < sockaddr_in6 > ( ) , 1 ) ;
99
+ ( storage. assume_init ( ) , ffi_size)
100
+ }
101
+ } ;
102
+
103
+ let from_storage = sockaddr_storage_to_addr ( & storage, ffi_size as usize ) . unwrap ( ) ;
104
+ assert_eq ! ( from_storage, sockaddr) ;
105
+ let from_storage = sockaddr_storage_to_addr ( & storage, mem:: size_of :: < sockaddr_storage > ( ) ) . unwrap ( ) ;
106
+ assert_eq ! ( from_storage, sockaddr) ;
107
+ }
57
108
58
109
#[ test]
59
110
pub fn test_path_to_sock_addr ( ) {
@@ -1169,7 +1220,6 @@ fn loopback_address(family: AddressFamily) -> Option<nix::ifaddrs::InterfaceAddr
1169
1220
use std:: io;
1170
1221
use std:: io:: Write ;
1171
1222
use nix:: ifaddrs:: getifaddrs;
1172
- use nix:: sys:: socket:: SockAddr ;
1173
1223
use nix:: net:: if_:: * ;
1174
1224
1175
1225
let addrs = match getifaddrs ( ) {
0 commit comments