11use std:: fmt;
22use std:: mem:: { self , MaybeUninit } ;
3- use std:: net:: { SocketAddr , SocketAddrV4 , SocketAddrV6 } ;
3+ use std:: net:: { Ipv4Addr , Ipv6Addr , SocketAddr , SocketAddrV4 , SocketAddrV6 } ;
44use std:: ptr;
55
66#[ cfg( any( unix, target_os = "redox" ) ) ]
77use libc:: {
8- sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t , AF_INET ,
9- AF_INET6 ,
8+ in6_addr , in_addr , sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage,
9+ socklen_t , AF_INET , AF_INET6 ,
1010} ;
1111#[ cfg( windows) ]
12+ use winapi:: shared:: in6addr:: { in6_addr_u, IN6_ADDR as in6_addr} ;
13+ #[ cfg( windows) ]
14+ use winapi:: shared:: inaddr:: { in_addr_S_un, IN_ADDR as in_addr} ;
15+ #[ cfg( windows) ]
1216use winapi:: shared:: ws2def:: {
1317 ADDRESS_FAMILY as sa_family_t, AF_INET , AF_INET6 , SOCKADDR as sockaddr,
1418 SOCKADDR_IN as sockaddr_in, SOCKADDR_STORAGE as sockaddr_storage,
1519} ;
1620#[ cfg( windows) ]
17- use winapi:: shared:: ws2ipdef:: SOCKADDR_IN6_LH as sockaddr_in6;
21+ use winapi:: shared:: ws2ipdef:: { SOCKADDR_IN6_LH_u , SOCKADDR_IN6_LH as sockaddr_in6} ;
1822#[ cfg( windows) ]
1923use winapi:: um:: ws2tcpip:: socklen_t;
2024
@@ -43,17 +47,17 @@ impl fmt::Debug for SockAddr {
4347impl SockAddr {
4448 /// Constructs a `SockAddr` from its raw components.
4549 pub unsafe fn from_raw_parts ( addr : * const sockaddr , len : socklen_t ) -> SockAddr {
46- let mut storage = MaybeUninit :: < sockaddr_storage > :: uninit ( ) ;
50+ let mut storage = MaybeUninit :: < sockaddr_storage > :: zeroed ( ) ;
4751 ptr:: copy_nonoverlapping (
4852 addr as * const _ as * const u8 ,
49- & mut storage as * mut _ as * mut u8 ,
53+ storage. as_mut_ptr ( ) as * mut u8 ,
5054 len as usize ,
5155 ) ;
5256
5357 SockAddr {
5458 // This is safe as we written the address to `storage` above.
5559 storage : storage. assume_init ( ) ,
56- len : len ,
60+ len,
5761 }
5862 }
5963
@@ -120,33 +124,60 @@ impl SockAddr {
120124 }
121125 }
122126
123- unsafe fn as_ < T > ( & self , family : sa_family_t ) -> Option < T > {
124- if self . storage . ss_family != family {
125- return None ;
126- }
127-
128- Some ( mem:: transmute_copy ( & self . storage ) )
129- }
130-
131127 /// Returns this address as a `SocketAddrV4` if it is in the `AF_INET`
132128 /// family.
133129 pub fn as_inet ( & self ) -> Option < SocketAddrV4 > {
134- unsafe { self . as_ ( AF_INET as sa_family_t ) }
130+ match self . as_std ( ) {
131+ Some ( SocketAddr :: V4 ( addr) ) => Some ( addr) ,
132+ _ => None ,
133+ }
135134 }
136135
137136 /// Returns this address as a `SocketAddrV6` if it is in the `AF_INET6`
138137 /// family.
139138 pub fn as_inet6 ( & self ) -> Option < SocketAddrV6 > {
140- unsafe { self . as_ ( AF_INET6 as sa_family_t ) }
139+ match self . as_std ( ) {
140+ Some ( SocketAddr :: V6 ( addr) ) => Some ( addr) ,
141+ _ => None ,
142+ }
141143 }
142144
143145 /// Returns this address as a `SocketAddr` if it is in the `AF_INET`
144146 /// or `AF_INET6` family, otherwise returns `None`.
145147 pub fn as_std ( & self ) -> Option < SocketAddr > {
146- if let Some ( addr) = self . as_inet ( ) {
147- Some ( SocketAddr :: V4 ( addr) )
148- } else if let Some ( addr) = self . as_inet6 ( ) {
149- Some ( SocketAddr :: V6 ( addr) )
148+ if self . storage . ss_family == AF_INET as sa_family_t {
149+ // Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in.
150+ let addr = unsafe { & * ( & self . storage as * const _ as * const sockaddr_in ) } ;
151+
152+ #[ cfg( unix) ]
153+ let ip = Ipv4Addr :: from ( addr. sin_addr . s_addr . to_ne_bytes ( ) ) ;
154+ #[ cfg( windows) ]
155+ let ip = {
156+ let ip_bytes = unsafe { addr. sin_addr . S_un . S_un_b ( ) } ;
157+ Ipv4Addr :: from ( [ ip_bytes. s_b1 , ip_bytes. s_b2 , ip_bytes. s_b3 , ip_bytes. s_b4 ] )
158+ } ;
159+ let port = u16:: from_be ( addr. sin_port ) ;
160+ Some ( SocketAddr :: V4 ( SocketAddrV4 :: new ( ip, port) ) )
161+ } else if self . storage . ss_family == AF_INET6 as sa_family_t {
162+ // Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6.
163+ let addr = unsafe { & * ( & self . storage as * const _ as * const sockaddr_in6 ) } ;
164+
165+ #[ cfg( unix) ]
166+ let ip = Ipv6Addr :: from ( addr. sin6_addr . s6_addr ) ;
167+ #[ cfg( windows) ]
168+ let ip = Ipv6Addr :: from ( * unsafe { addr. sin6_addr . u . Byte ( ) } ) ;
169+ let port = u16:: from_be ( addr. sin6_port ) ;
170+ Some ( SocketAddr :: V6 ( SocketAddrV6 :: new (
171+ ip,
172+ port,
173+ addr. sin6_flowinfo ,
174+ #[ cfg( unix) ]
175+ addr. sin6_scope_id ,
176+ #[ cfg( windows) ]
177+ unsafe {
178+ * addr. u . sin6_scope_id ( )
179+ } ,
180+ ) ) )
150181 } else {
151182 None
152183 }
@@ -168,34 +199,90 @@ impl SockAddr {
168199 }
169200}
170201
171- // SocketAddrV4 and SocketAddrV6 are just wrappers around sockaddr_in and sockaddr_in6
172-
173- // check to make sure that the sizes at least match up
174- fn _size_checks ( v4 : SocketAddrV4 , v6 : SocketAddrV6 ) {
175- unsafe {
176- mem:: transmute :: < SocketAddrV4 , sockaddr_in > ( v4) ;
177- mem:: transmute :: < SocketAddrV6 , sockaddr_in6 > ( v6) ;
178- }
179- }
180-
181202impl From < SocketAddrV4 > for SockAddr {
182203 fn from ( addr : SocketAddrV4 ) -> SockAddr {
183- unsafe {
184- SockAddr :: from_raw_parts (
185- & addr as * const _ as * const _ ,
186- mem:: size_of :: < SocketAddrV4 > ( ) as socklen_t ,
187- )
204+ #[ cfg( unix) ]
205+ let sin_addr = in_addr {
206+ s_addr : u32:: from_ne_bytes ( addr. ip ( ) . octets ( ) ) ,
207+ } ;
208+ #[ cfg( windows) ]
209+ let sin_addr = unsafe {
210+ let mut s_un = mem:: zeroed :: < in_addr_S_un > ( ) ;
211+ * s_un. S_addr_mut ( ) = u32:: from_ne_bytes ( addr. ip ( ) . octets ( ) ) ;
212+ in_addr { S_un : s_un }
213+ } ;
214+
215+ let sockaddr_in = sockaddr_in {
216+ sin_family : AF_INET as sa_family_t ,
217+ sin_port : addr. port ( ) . to_be ( ) ,
218+ sin_addr,
219+ sin_zero : [ 0 ; 8 ] ,
220+ #[ cfg( any(
221+ target_os = "dragonfly" ,
222+ target_os = "freebsd" ,
223+ target_os = "ios" ,
224+ target_os = "macos" ,
225+ target_os = "netbsd" ,
226+ target_os = "openbsd"
227+ ) ) ]
228+ sin_len : 0 ,
229+ } ;
230+ let mut storage = MaybeUninit :: < sockaddr_storage > :: zeroed ( ) ;
231+ // Safety: A `sockaddr_in` is memory compatible with a `sockaddr_storage`
232+ unsafe { ( storage. as_mut_ptr ( ) as * mut sockaddr_in ) . write ( sockaddr_in) } ;
233+ SockAddr {
234+ storage : unsafe { storage. assume_init ( ) } ,
235+ len : mem:: size_of :: < sockaddr_in > ( ) as socklen_t ,
188236 }
189237 }
190238}
191239
192240impl From < SocketAddrV6 > for SockAddr {
193241 fn from ( addr : SocketAddrV6 ) -> SockAddr {
194- unsafe {
195- SockAddr :: from_raw_parts (
196- & addr as * const _ as * const _ ,
197- mem:: size_of :: < SocketAddrV6 > ( ) as socklen_t ,
198- )
242+ #[ cfg( unix) ]
243+ let sin6_addr = in6_addr {
244+ s6_addr : addr. ip ( ) . octets ( ) ,
245+ } ;
246+ #[ cfg( windows) ]
247+ let sin6_addr = unsafe {
248+ let mut u = mem:: zeroed :: < in6_addr_u > ( ) ;
249+ * u. Byte_mut ( ) = addr. ip ( ) . octets ( ) ;
250+ in6_addr { u }
251+ } ;
252+ #[ cfg( windows) ]
253+ let u = unsafe {
254+ let mut u = mem:: zeroed :: < SOCKADDR_IN6_LH_u > ( ) ;
255+ * u. sin6_scope_id_mut ( ) = addr. scope_id ( ) ;
256+ u
257+ } ;
258+
259+ let sockaddr_in6 = sockaddr_in6 {
260+ sin6_family : AF_INET6 as sa_family_t ,
261+ sin6_port : addr. port ( ) . to_be ( ) ,
262+ sin6_addr,
263+ sin6_flowinfo : addr. flowinfo ( ) ,
264+ #[ cfg( unix) ]
265+ sin6_scope_id : addr. scope_id ( ) ,
266+ #[ cfg( windows) ]
267+ u,
268+ #[ cfg( any(
269+ target_os = "dragonfly" ,
270+ target_os = "freebsd" ,
271+ target_os = "ios" ,
272+ target_os = "macos" ,
273+ target_os = "netbsd" ,
274+ target_os = "openbsd"
275+ ) ) ]
276+ sin6_len : 0 ,
277+ #[ cfg( any( target_os = "solaris" , target_os = "illumos" ) ) ]
278+ __sin6_src_id : 0 ,
279+ } ;
280+ let mut storage = MaybeUninit :: < sockaddr_storage > :: zeroed ( ) ;
281+ // Safety: A `sockaddr_in6` is memory compatible with a `sockaddr_storage`
282+ unsafe { ( storage. as_mut_ptr ( ) as * mut sockaddr_in6 ) . write ( sockaddr_in6) } ;
283+ SockAddr {
284+ storage : unsafe { storage. assume_init ( ) } ,
285+ len : mem:: size_of :: < sockaddr_in6 > ( ) as socklen_t ,
199286 }
200287 }
201288}
0 commit comments