3
3
//!
4
4
//! # Motivation
5
5
//!
6
- //! The std crate provides [SocketAddr] for managing socket addresses. Its `V4` variant
7
- //! encapsulates [ libc::sockaddr_in] and its `V6` variant encapsulates [libc::sockaddr_in6].
8
- //! However there is no easy way to convert `SocketAddr` from/into a `libc::sockaddr` because
9
- //! `SocketAddr` is a rust enum.
6
+ //! The std crate provides [SocketAddr] for managing socket addresses. However there is no easy way
7
+ //! to convert `SocketAddr` from/into a ` libc::sockaddr` because `SocketAddr` has a different
8
+ //! internal layout.
9
+
10
10
//!
11
11
//! This crate provides [OsSocketAddr] which holds a `libc::sockaddr` (containing an IPv4 or IPv6
12
12
//! address) and the conversion functions from/into `SocketAddr`.
95
95
extern crate libc;
96
96
97
97
use std:: convert:: TryInto ;
98
- use std:: net:: SocketAddr ;
98
+ use std:: net:: { Ipv4Addr , Ipv6Addr , SocketAddr , SocketAddrV4 , SocketAddrV6 } ;
99
99
100
100
#[ cfg( target_family = "unix" ) ]
101
- use libc:: { sockaddr, sockaddr_in, sockaddr_in6, socklen_t, AF_INET , AF_INET6 } ;
101
+ use libc:: { sockaddr, sockaddr_in, sockaddr_in6, socklen_t, AF_INET , AF_INET6 , in_addr , in6_addr } ;
102
102
103
103
#[ cfg( target_family = "windows" ) ]
104
104
use winapi:: {
105
105
shared:: {
106
+ inaddr:: in_addr, in6addr:: in6_addr,
106
107
ws2def:: { AF_INET , AF_INET6 , SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in} ,
107
108
ws2ipdef:: SOCKADDR_IN6_LH as sockaddr_in6,
109
+ ws2ipdef:: SOCKADDR_IN6_LH_u ,
108
110
} ,
109
111
um:: ws2tcpip:: socklen_t,
110
112
} ;
@@ -120,7 +122,9 @@ use winapi::{
120
122
/// See [crate] level documentation.
121
123
///
122
124
#[ derive( Copy , Clone ) ]
123
- pub struct OsSocketAddr {
125
+ #[ repr( C ) ]
126
+ pub union OsSocketAddr {
127
+ sa4 : sockaddr_in ,
124
128
sa6 : sockaddr_in6 ,
125
129
}
126
130
@@ -169,7 +173,7 @@ impl OsSocketAddr {
169
173
/// * `AF_INET6` -> the size of [sockaddr_in6]
170
174
/// * *other* -> 0
171
175
pub fn len ( & self ) -> socklen_t {
172
- ( match self . sa6 . sin6_family as i32 {
176
+ ( match unsafe { self . sa6 . sin6_family } as i32 {
173
177
AF_INET => std:: mem:: size_of :: < sockaddr_in > ( ) ,
174
178
AF_INET6 => std:: mem:: size_of :: < sockaddr_in6 > ( ) ,
175
179
_ => 0 ,
@@ -183,12 +187,12 @@ impl OsSocketAddr {
183
187
184
188
/// Get a pointer to the internal buffer
185
189
pub fn as_ptr ( & self ) -> * const sockaddr {
186
- & self . sa6 as * const _ as * const _
190
+ unsafe { & self . sa6 as * const _ as * const _ }
187
191
}
188
192
189
193
/// Get a mutable pointer to the internal buffer
190
194
pub fn as_mut_ptr ( & mut self ) -> * mut sockaddr {
191
- & mut self . sa6 as * mut _ as * mut _
195
+ unsafe { & mut self . sa6 as * mut _ as * mut _ }
192
196
}
193
197
}
194
198
@@ -243,8 +247,29 @@ impl TryInto<SocketAddr> for OsSocketAddr {
243
247
fn try_into ( self ) -> Result < SocketAddr , BadFamilyError > {
244
248
unsafe {
245
249
match self . sa6 . sin6_family as i32 {
246
- AF_INET => Ok ( SocketAddr :: V4 ( * ( self . as_ptr ( ) as * const _ ) ) ) ,
247
- AF_INET6 => Ok ( SocketAddr :: V6 ( * ( self . as_ptr ( ) as * const _ ) ) ) ,
250
+ AF_INET => {
251
+ #[ cfg( not( target_family = "windows" ) ) ]
252
+ let ip = self . sa4 . sin_addr . s_addr ;
253
+ #[ cfg( target_family = "windows" ) ]
254
+ let ip = * self . sa4 . sin_addr . S_un . S_addr ( ) ;
255
+
256
+ Ok ( SocketAddr :: V4 ( SocketAddrV4 :: new (
257
+ Ipv4Addr :: from ( u32:: from_be ( ip) ) ,
258
+ u16:: from_be ( self . sa4 . sin_port ) ,
259
+ ) ) )
260
+ } ,
261
+ AF_INET6 => {
262
+ #[ cfg( not( target_family = "windows" ) ) ]
263
+ let ( ip, scope_id) = ( self . sa6 . sin6_addr . s6_addr , self . sa6 . sin6_scope_id ) ;
264
+ #[ cfg( target_family = "windows" ) ]
265
+ let ( ip, scope_id) = ( * self . sa6 . sin6_addr . u . Byte ( ) , * self . sa6 . u . sin6_scope_id ( ) ) ;
266
+
267
+ Ok ( SocketAddr :: V6 ( SocketAddrV6 :: new (
268
+ Ipv6Addr :: from ( u128:: from_be_bytes ( ip) ) ,
269
+ u16:: from_be ( self . sa6 . sin6_port ) ,
270
+ self . sa6 . sin6_flowinfo ,
271
+ scope_id) ) )
272
+ } ,
248
273
f => Err ( BadFamilyError ( f) ) ,
249
274
}
250
275
}
@@ -266,17 +291,64 @@ impl std::fmt::Display for BadFamilyError {
266
291
267
292
impl From < SocketAddr > for OsSocketAddr {
268
293
fn from ( addr : SocketAddr ) -> Self {
269
- OsSocketAddr {
270
- sa6 : unsafe {
271
- match addr {
272
- SocketAddr :: V4 ( addr) => {
273
- let mut sa6 = std:: mem:: zeroed ( ) ;
274
- * ( & mut sa6 as * mut _ as * mut _ ) = addr;
275
- sa6
276
- }
277
- SocketAddr :: V6 ( addr) => * ( & addr as * const _ as * const _ ) ,
294
+ match addr {
295
+ SocketAddr :: V4 ( addr) => {
296
+ let raw_ip = u32:: to_be ( ( * addr. ip ( ) ) . into ( ) ) ;
297
+ Self { sa4 : sockaddr_in {
298
+ #[ cfg( not( target_os = "macos" ) ) ]
299
+ sin_family : AF_INET as u16 ,
300
+
301
+ #[ cfg( target_os = "macos" ) ]
302
+ sin_len : std:: mem:: size_of :: < sockaddr_in > ( ) as u8 ,
303
+ #[ cfg( target_os = "macos" ) ]
304
+ sin_family : AF_INET as u8 ,
305
+
306
+ #[ cfg( not( target_family = "windows" ) ) ]
307
+ sin_addr : in_addr { s_addr : raw_ip } ,
308
+ #[ cfg( target_family = "windows" ) ]
309
+ sin_addr : unsafe {
310
+ let mut ip : in_addr = std:: mem:: zeroed ( ) ;
311
+ * ip. S_un . S_addr_mut ( ) = raw_ip;
312
+ ip
313
+ } ,
314
+
315
+ sin_port : u16:: to_be ( addr. port ( ) ) ,
316
+ sin_zero : [ 0 ; 8 ] ,
278
317
}
279
- } ,
318
+ } } ,
319
+ SocketAddr :: V6 ( addr) => {
320
+ let raw_ip = u128:: to_be_bytes ( ( * addr. ip ( ) ) . into ( ) ) ;
321
+ Self { sa6 : sockaddr_in6 {
322
+ #[ cfg( not( target_os = "macos" ) ) ]
323
+ sin6_family : AF_INET6 as u16 ,
324
+
325
+ #[ cfg( target_os = "macos" ) ]
326
+ sin6_len : std:: mem:: size_of :: < sockaddr_in6 > ( ) as u8 ,
327
+ #[ cfg( target_os = "macos" ) ]
328
+ sin6_family : AF_INET6 as u8 ,
329
+
330
+ #[ cfg( not( target_family = "windows" ) ) ]
331
+ sin6_addr : in6_addr { s6_addr : raw_ip } ,
332
+ #[ cfg( target_family = "windows" ) ]
333
+ sin6_addr : unsafe {
334
+ let mut ip : in6_addr = std:: mem:: zeroed ( ) ;
335
+ * ip. u . Byte_mut ( ) = raw_ip;
336
+ ip
337
+ } ,
338
+
339
+ #[ cfg( not( target_family = "windows" ) ) ]
340
+ sin6_scope_id : addr. scope_id ( ) ,
341
+ #[ cfg( target_family = "windows" ) ]
342
+ u : unsafe {
343
+ let mut u : SOCKADDR_IN6_LH_u = std:: mem:: zeroed ( ) ;
344
+ * u. sin6_scope_id_mut ( ) = addr. scope_id ( ) ;
345
+ u
346
+ } ,
347
+
348
+ sin6_port : u16:: to_be ( addr. port ( ) ) ,
349
+ sin6_flowinfo : addr. flowinfo ( ) ,
350
+ } }
351
+ }
280
352
}
281
353
}
282
354
}
@@ -304,9 +376,6 @@ mod tests {
304
376
#[ cfg( target_family = "unix" ) ]
305
377
use libc:: { in6_addr, in_addr} ;
306
378
307
- #[ cfg( target_family = "windows" ) ]
308
- use winapi:: shared:: { in6addr:: in6_addr, inaddr:: in_addr} ;
309
-
310
379
fn check_as_mut ( osa : & mut OsSocketAddr ) {
311
380
let ptr = osa as * mut _ as usize ;
312
381
let buf = osa. as_mut ( ) ;
0 commit comments