1
1
use std:: fmt;
2
2
use std:: mem:: { self , MaybeUninit } ;
3
- use std:: net:: { SocketAddr , SocketAddrV4 , SocketAddrV6 } ;
3
+ use std:: net:: { Ipv4Addr , Ipv6Addr , SocketAddr , SocketAddrV4 , SocketAddrV6 } ;
4
4
use std:: ptr;
5
5
6
6
#[ cfg( any( unix, target_os = "redox" ) ) ]
7
7
use 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 ,
10
10
} ;
11
11
#[ 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) ]
12
16
use winapi:: shared:: ws2def:: {
13
17
ADDRESS_FAMILY as sa_family_t, AF_INET , AF_INET6 , SOCKADDR as sockaddr,
14
18
SOCKADDR_IN as sockaddr_in, SOCKADDR_STORAGE as sockaddr_storage,
15
19
} ;
16
20
#[ 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} ;
18
22
#[ cfg( windows) ]
19
23
use winapi:: um:: ws2tcpip:: socklen_t;
20
24
@@ -43,17 +47,17 @@ impl fmt::Debug for SockAddr {
43
47
impl SockAddr {
44
48
/// Constructs a `SockAddr` from its raw components.
45
49
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 ( ) ;
47
51
ptr:: copy_nonoverlapping (
48
52
addr as * const _ as * const u8 ,
49
- & mut storage as * mut _ as * mut u8 ,
53
+ storage. as_mut_ptr ( ) as * mut u8 ,
50
54
len as usize ,
51
55
) ;
52
56
53
57
SockAddr {
54
58
// This is safe as we written the address to `storage` above.
55
59
storage : storage. assume_init ( ) ,
56
- len : len ,
60
+ len,
57
61
}
58
62
}
59
63
@@ -120,33 +124,60 @@ impl SockAddr {
120
124
}
121
125
}
122
126
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
-
131
127
/// Returns this address as a `SocketAddrV4` if it is in the `AF_INET`
132
128
/// family.
133
129
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
+ }
135
134
}
136
135
137
136
/// Returns this address as a `SocketAddrV6` if it is in the `AF_INET6`
138
137
/// family.
139
138
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
+ }
141
143
}
142
144
143
145
/// Returns this address as a `SocketAddr` if it is in the `AF_INET`
144
146
/// or `AF_INET6` family, otherwise returns `None`.
145
147
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
+ ) ) )
150
181
} else {
151
182
None
152
183
}
@@ -168,34 +199,90 @@ impl SockAddr {
168
199
}
169
200
}
170
201
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
-
181
202
impl From < SocketAddrV4 > for SockAddr {
182
203
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 ,
188
236
}
189
237
}
190
238
}
191
239
192
240
impl From < SocketAddrV6 > for SockAddr {
193
241
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 ,
199
286
}
200
287
}
201
288
}
0 commit comments