]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | #![unstable(issue = "none", feature = "windows_net")] |
54a0048b | 2 | |
532ac7d7 | 3 | use crate::cmp; |
dfeec247 | 4 | use crate::io::{self, IoSlice, IoSliceMut, Read}; |
532ac7d7 | 5 | use crate::mem; |
dfeec247 | 6 | use crate::net::{Shutdown, SocketAddr}; |
94222f64 XL |
7 | use crate::os::windows::io::{ |
8 | AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, | |
9 | }; | |
532ac7d7 | 10 | use crate::ptr; |
923072b8 | 11 | use crate::sync::OnceLock; |
532ac7d7 | 12 | use crate::sys; |
dfeec247 | 13 | use crate::sys::c; |
532ac7d7 | 14 | use crate::sys_common::net; |
cdc7bbd5 | 15 | use crate::sys_common::{AsInner, FromInner, IntoInner}; |
532ac7d7 XL |
16 | use crate::time::Duration; |
17 | ||
94222f64 | 18 | use libc::{c_int, c_long, c_ulong, c_ushort}; |
85aaf69f SL |
19 | |
20 | pub type wrlen_t = i32; | |
21 | ||
92a42be0 | 22 | pub mod netc { |
dfeec247 XL |
23 | pub use crate::sys::c::ADDRESS_FAMILY as sa_family_t; |
24 | pub use crate::sys::c::ADDRINFOA as addrinfo; | |
532ac7d7 XL |
25 | pub use crate::sys::c::SOCKADDR as sockaddr; |
26 | pub use crate::sys::c::SOCKADDR_STORAGE_LH as sockaddr_storage; | |
dfeec247 | 27 | pub use crate::sys::c::*; |
92a42be0 SL |
28 | } |
29 | ||
94222f64 | 30 | pub struct Socket(OwnedSocket); |
85aaf69f | 31 | |
923072b8 | 32 | static WSA_CLEANUP: OnceLock<unsafe extern "system" fn() -> i32> = OnceLock::new(); |
cdc7bbd5 | 33 | |
c34b1796 AL |
34 | /// Checks whether the Windows socket interface has been started already, and |
35 | /// if not, starts it. | |
85aaf69f | 36 | pub fn init() { |
c295e0f8 | 37 | let _ = WSA_CLEANUP.get_or_init(|| unsafe { |
85aaf69f | 38 | let mut data: c::WSADATA = mem::zeroed(); |
dfeec247 XL |
39 | let ret = c::WSAStartup( |
40 | 0x202, // version 2.2 | |
41 | &mut data, | |
42 | ); | |
85aaf69f | 43 | assert_eq!(ret, 0); |
c295e0f8 XL |
44 | |
45 | // Only register `WSACleanup` if `WSAStartup` is actually ever called. | |
46 | // Workaround to prevent linking to `WS2_32.dll` when no network functionality is used. | |
47 | // See issue #85441. | |
48 | c::WSACleanup | |
cdc7bbd5 XL |
49 | }); |
50 | } | |
85aaf69f | 51 | |
cdc7bbd5 | 52 | pub fn cleanup() { |
c295e0f8 XL |
53 | // only perform cleanup if network functionality was actually initialized |
54 | if let Some(cleanup) = WSA_CLEANUP.get() { | |
cdc7bbd5 | 55 | unsafe { |
c295e0f8 | 56 | cleanup(); |
cdc7bbd5 XL |
57 | } |
58 | } | |
85aaf69f SL |
59 | } |
60 | ||
c34b1796 | 61 | /// Returns the last error from the Windows socket interface. |
85aaf69f | 62 | fn last_error() -> io::Error { |
9346a6ac | 63 | io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) |
85aaf69f SL |
64 | } |
65 | ||
3157f602 XL |
66 | #[doc(hidden)] |
67 | pub trait IsMinusOne { | |
68 | fn is_minus_one(&self) -> bool; | |
69 | } | |
70 | ||
71 | macro_rules! impl_is_minus_one { | |
72 | ($($t:ident)*) => ($(impl IsMinusOne for $t { | |
73 | fn is_minus_one(&self) -> bool { | |
74 | *self == -1 | |
75 | } | |
76 | })*) | |
77 | } | |
78 | ||
79 | impl_is_minus_one! { i8 i16 i32 i64 isize } | |
80 | ||
c34b1796 | 81 | /// Checks if the signed integer is the Windows constant `SOCKET_ERROR` (-1) |
54a0048b | 82 | /// and if so, returns the last error from the Windows socket interface. This |
c34b1796 | 83 | /// function must be called before another call to the socket API is made. |
3157f602 | 84 | pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> { |
dfeec247 | 85 | if t.is_minus_one() { Err(last_error()) } else { Ok(t) } |
85aaf69f SL |
86 | } |
87 | ||
54a0048b | 88 | /// A variant of `cvt` for `getaddrinfo` which return 0 for a success. |
85aaf69f | 89 | pub fn cvt_gai(err: c_int) -> io::Result<()> { |
dfeec247 | 90 | if err == 0 { Ok(()) } else { Err(last_error()) } |
85aaf69f SL |
91 | } |
92 | ||
54a0048b | 93 | /// Just to provide the same interface as sys/unix/net.rs |
9346a6ac | 94 | pub fn cvt_r<T, F>(mut f: F) -> io::Result<T> |
dfeec247 XL |
95 | where |
96 | T: IsMinusOne, | |
97 | F: FnMut() -> T, | |
9346a6ac | 98 | { |
85aaf69f SL |
99 | cvt(f()) |
100 | } | |
101 | ||
102 | impl Socket { | |
103 | pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> { | |
136023e0 | 104 | let family = match *addr { |
92a42be0 SL |
105 | SocketAddr::V4(..) => c::AF_INET, |
106 | SocketAddr::V6(..) => c::AF_INET6, | |
85aaf69f | 107 | }; |
54a0048b | 108 | let socket = unsafe { |
136023e0 XL |
109 | c::WSASocketW( |
110 | family, | |
dfeec247 XL |
111 | ty, |
112 | 0, | |
113 | ptr::null_mut(), | |
114 | 0, | |
115 | c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, | |
136023e0 XL |
116 | ) |
117 | }; | |
118 | ||
119 | if socket != c::INVALID_SOCKET { | |
94222f64 | 120 | unsafe { Ok(Self::from_raw_socket(socket)) } |
136023e0 XL |
121 | } else { |
122 | let error = unsafe { c::WSAGetLastError() }; | |
123 | ||
124 | if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL { | |
125 | return Err(io::Error::from_raw_os_error(error)); | |
126 | } | |
127 | ||
128 | let socket = | |
129 | unsafe { c::WSASocketW(family, ty, 0, ptr::null_mut(), 0, c::WSA_FLAG_OVERLAPPED) }; | |
130 | ||
131 | if socket == c::INVALID_SOCKET { | |
132 | return Err(last_error()); | |
c1a9b12d | 133 | } |
136023e0 | 134 | |
94222f64 XL |
135 | unsafe { |
136 | let socket = Self::from_raw_socket(socket); | |
5099ac24 | 137 | socket.0.set_no_inherit()?; |
94222f64 XL |
138 | Ok(socket) |
139 | } | |
136023e0 | 140 | } |
85aaf69f SL |
141 | } |
142 | ||
041b39d2 XL |
143 | pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { |
144 | self.set_nonblocking(true)?; | |
136023e0 | 145 | let result = { |
041b39d2 | 146 | let (addrp, len) = addr.into_inner(); |
94222f64 | 147 | let result = unsafe { c::connect(self.as_raw_socket(), addrp, len) }; |
136023e0 | 148 | cvt(result).map(drop) |
041b39d2 XL |
149 | }; |
150 | self.set_nonblocking(false)?; | |
151 | ||
136023e0 XL |
152 | match result { |
153 | Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => { | |
154 | if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { | |
5099ac24 | 155 | return Err(io::const_io_error!( |
136023e0 | 156 | io::ErrorKind::InvalidInput, |
5099ac24 | 157 | "cannot set a 0 duration timeout", |
136023e0 XL |
158 | )); |
159 | } | |
041b39d2 | 160 | |
136023e0 XL |
161 | let mut timeout = c::timeval { |
162 | tv_sec: timeout.as_secs() as c_long, | |
163 | tv_usec: (timeout.subsec_nanos() / 1000) as c_long, | |
164 | }; | |
041b39d2 | 165 | |
136023e0 XL |
166 | if timeout.tv_sec == 0 && timeout.tv_usec == 0 { |
167 | timeout.tv_usec = 1; | |
168 | } | |
041b39d2 | 169 | |
136023e0 XL |
170 | let fds = { |
171 | let mut fds = unsafe { mem::zeroed::<c::fd_set>() }; | |
172 | fds.fd_count = 1; | |
94222f64 | 173 | fds.fd_array[0] = self.as_raw_socket(); |
136023e0 XL |
174 | fds |
175 | }; | |
176 | ||
177 | let mut writefds = fds; | |
178 | let mut errorfds = fds; | |
179 | ||
180 | let count = { | |
181 | let result = unsafe { | |
182 | c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout) | |
183 | }; | |
184 | cvt(result)? | |
185 | }; | |
186 | ||
187 | match count { | |
5099ac24 | 188 | 0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")), |
136023e0 XL |
189 | _ => { |
190 | if writefds.fd_count != 1 { | |
191 | if let Some(e) = self.take_error()? { | |
192 | return Err(e); | |
193 | } | |
194 | } | |
041b39d2 | 195 | |
136023e0 | 196 | Ok(()) |
041b39d2 XL |
197 | } |
198 | } | |
041b39d2 | 199 | } |
136023e0 | 200 | _ => result, |
041b39d2 XL |
201 | } |
202 | } | |
203 | ||
dfeec247 | 204 | pub fn accept(&self, storage: *mut c::SOCKADDR, len: *mut c_int) -> io::Result<Socket> { |
94222f64 | 205 | let socket = unsafe { c::accept(self.as_raw_socket(), storage, len) }; |
136023e0 XL |
206 | |
207 | match socket { | |
208 | c::INVALID_SOCKET => Err(last_error()), | |
94222f64 | 209 | _ => unsafe { Ok(Self::from_raw_socket(socket)) }, |
136023e0 | 210 | } |
85aaf69f SL |
211 | } |
212 | ||
213 | pub fn duplicate(&self) -> io::Result<Socket> { | |
5099ac24 | 214 | Ok(Self(self.0.try_clone()?)) |
85aaf69f SL |
215 | } |
216 | ||
8bb4bdeb | 217 | fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> { |
85aaf69f SL |
218 | // On unix when a socket is shut down all further reads return 0, so we |
219 | // do the same on windows to map a shut down socket to returning EOF. | |
136023e0 | 220 | let length = cmp::min(buf.len(), i32::MAX as usize) as i32; |
94222f64 XL |
221 | let result = |
222 | unsafe { c::recv(self.as_raw_socket(), buf.as_mut_ptr() as *mut _, length, flags) }; | |
136023e0 XL |
223 | |
224 | match result { | |
225 | c::SOCKET_ERROR => { | |
226 | let error = unsafe { c::WSAGetLastError() }; | |
227 | ||
228 | if error == c::WSAESHUTDOWN { | |
229 | Ok(0) | |
230 | } else { | |
231 | Err(io::Error::from_raw_os_error(error)) | |
232 | } | |
85aaf69f | 233 | } |
136023e0 | 234 | _ => Ok(result as usize), |
85aaf69f SL |
235 | } |
236 | } | |
62682a34 | 237 | |
8bb4bdeb XL |
238 | pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { |
239 | self.recv_with_flags(buf, 0) | |
240 | } | |
241 | ||
48663c56 | 242 | pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
9fa01778 XL |
243 | // On unix when a socket is shut down all further reads return 0, so we |
244 | // do the same on windows to map a shut down socket to returning EOF. | |
136023e0 | 245 | let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; |
9fa01778 XL |
246 | let mut nread = 0; |
247 | let mut flags = 0; | |
136023e0 XL |
248 | let result = unsafe { |
249 | c::WSARecv( | |
94222f64 | 250 | self.as_raw_socket(), |
9fa01778 | 251 | bufs.as_mut_ptr() as *mut c::WSABUF, |
136023e0 | 252 | length, |
9fa01778 XL |
253 | &mut nread, |
254 | &mut flags, | |
255 | ptr::null_mut(), | |
256 | ptr::null_mut(), | |
136023e0 XL |
257 | ) |
258 | }; | |
259 | ||
260 | match result { | |
261 | 0 => Ok(nread as usize), | |
262 | _ => { | |
263 | let error = unsafe { c::WSAGetLastError() }; | |
264 | ||
265 | if error == c::WSAESHUTDOWN { | |
266 | Ok(0) | |
267 | } else { | |
268 | Err(io::Error::from_raw_os_error(error)) | |
269 | } | |
9fa01778 XL |
270 | } |
271 | } | |
272 | } | |
273 | ||
f9f354fc XL |
274 | #[inline] |
275 | pub fn is_read_vectored(&self) -> bool { | |
276 | true | |
277 | } | |
278 | ||
8bb4bdeb XL |
279 | pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { |
280 | self.recv_with_flags(buf, c::MSG_PEEK) | |
281 | } | |
282 | ||
dfeec247 XL |
283 | fn recv_from_with_flags( |
284 | &self, | |
285 | buf: &mut [u8], | |
286 | flags: c_int, | |
287 | ) -> io::Result<(usize, SocketAddr)> { | |
136023e0 | 288 | let mut storage = unsafe { mem::zeroed::<c::SOCKADDR_STORAGE_LH>() }; |
8bb4bdeb | 289 | let mut addrlen = mem::size_of_val(&storage) as c::socklen_t; |
136023e0 | 290 | let length = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; |
8bb4bdeb XL |
291 | |
292 | // On unix when a socket is shut down all further reads return 0, so we | |
293 | // do the same on windows to map a shut down socket to returning EOF. | |
136023e0 XL |
294 | let result = unsafe { |
295 | c::recvfrom( | |
94222f64 | 296 | self.as_raw_socket(), |
136023e0 XL |
297 | buf.as_mut_ptr() as *mut _, |
298 | length, | |
dfeec247 XL |
299 | flags, |
300 | &mut storage as *mut _ as *mut _, | |
301 | &mut addrlen, | |
136023e0 XL |
302 | ) |
303 | }; | |
304 | ||
305 | match result { | |
306 | c::SOCKET_ERROR => { | |
307 | let error = unsafe { c::WSAGetLastError() }; | |
308 | ||
309 | if error == c::WSAESHUTDOWN { | |
8bb4bdeb | 310 | Ok((0, net::sockaddr_to_addr(&storage, addrlen as usize)?)) |
136023e0 XL |
311 | } else { |
312 | Err(io::Error::from_raw_os_error(error)) | |
dfeec247 | 313 | } |
8bb4bdeb | 314 | } |
136023e0 | 315 | _ => Ok((result as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)), |
8bb4bdeb XL |
316 | } |
317 | } | |
318 | ||
319 | pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { | |
320 | self.recv_from_with_flags(buf, 0) | |
321 | } | |
322 | ||
323 | pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { | |
324 | self.recv_from_with_flags(buf, c::MSG_PEEK) | |
325 | } | |
326 | ||
48663c56 | 327 | pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
136023e0 | 328 | let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; |
9fa01778 | 329 | let mut nwritten = 0; |
136023e0 XL |
330 | let result = unsafe { |
331 | c::WSASend( | |
94222f64 | 332 | self.as_raw_socket(), |
136023e0 XL |
333 | bufs.as_ptr() as *const c::WSABUF as *mut _, |
334 | length, | |
9fa01778 XL |
335 | &mut nwritten, |
336 | 0, | |
337 | ptr::null_mut(), | |
338 | ptr::null_mut(), | |
136023e0 XL |
339 | ) |
340 | }; | |
341 | cvt(result).map(|_| nwritten as usize) | |
9fa01778 XL |
342 | } |
343 | ||
f9f354fc XL |
344 | #[inline] |
345 | pub fn is_write_vectored(&self) -> bool { | |
346 | true | |
347 | } | |
348 | ||
dfeec247 | 349 | pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> { |
62682a34 SL |
350 | let timeout = match dur { |
351 | Some(dur) => { | |
352 | let timeout = sys::dur2timeout(dur); | |
353 | if timeout == 0 { | |
5099ac24 | 354 | return Err(io::const_io_error!( |
dfeec247 | 355 | io::ErrorKind::InvalidInput, |
5099ac24 | 356 | "cannot set a 0 duration timeout", |
dfeec247 | 357 | )); |
62682a34 SL |
358 | } |
359 | timeout | |
360 | } | |
dfeec247 | 361 | None => 0, |
62682a34 | 362 | }; |
92a42be0 | 363 | net::setsockopt(self, c::SOL_SOCKET, kind, timeout) |
62682a34 SL |
364 | } |
365 | ||
92a42be0 | 366 | pub fn timeout(&self, kind: c_int) -> io::Result<Option<Duration>> { |
54a0048b | 367 | let raw: c::DWORD = net::getsockopt(self, c::SOL_SOCKET, kind)?; |
62682a34 SL |
368 | if raw == 0 { |
369 | Ok(None) | |
370 | } else { | |
371 | let secs = raw / 1000; | |
372 | let nsec = (raw % 1000) * 1000000; | |
373 | Ok(Some(Duration::new(secs as u64, nsec as u32))) | |
374 | } | |
375 | } | |
c1a9b12d | 376 | |
92a42be0 SL |
377 | pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { |
378 | let how = match how { | |
379 | Shutdown::Write => c::SD_SEND, | |
380 | Shutdown::Read => c::SD_RECEIVE, | |
381 | Shutdown::Both => c::SD_BOTH, | |
382 | }; | |
94222f64 | 383 | let result = unsafe { c::shutdown(self.as_raw_socket(), how) }; |
136023e0 | 384 | cvt(result).map(drop) |
92a42be0 | 385 | } |
54a0048b SL |
386 | |
387 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
388 | let mut nonblocking = nonblocking as c_ulong; | |
94222f64 XL |
389 | let result = |
390 | unsafe { c::ioctlsocket(self.as_raw_socket(), c::FIONBIO as c_int, &mut nonblocking) }; | |
136023e0 | 391 | cvt(result).map(drop) |
54a0048b SL |
392 | } |
393 | ||
94222f64 XL |
394 | pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> { |
395 | let linger = c::linger { | |
396 | l_onoff: linger.is_some() as c_ushort, | |
397 | l_linger: linger.unwrap_or_default().as_secs() as c_ushort, | |
398 | }; | |
399 | ||
400 | net::setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger) | |
401 | } | |
402 | ||
403 | pub fn linger(&self) -> io::Result<Option<Duration>> { | |
404 | let val: c::linger = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; | |
405 | ||
406 | Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) | |
407 | } | |
408 | ||
54a0048b | 409 | pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { |
5e7ed085 | 410 | net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL) |
54a0048b SL |
411 | } |
412 | ||
413 | pub fn nodelay(&self) -> io::Result<bool> { | |
5e7ed085 | 414 | let raw: c::BOOL = net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?; |
54a0048b SL |
415 | Ok(raw != 0) |
416 | } | |
417 | ||
418 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { | |
419 | let raw: c_int = net::getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?; | |
dfeec247 | 420 | if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } |
54a0048b | 421 | } |
94222f64 XL |
422 | |
423 | // This is used by sys_common code to abstract over Windows and Unix. | |
424 | pub fn as_raw(&self) -> RawSocket { | |
425 | self.as_inner().as_raw_socket() | |
426 | } | |
54a0048b SL |
427 | } |
428 | ||
dfeec247 | 429 | #[unstable(reason = "not public", issue = "none", feature = "fd_read")] |
54a0048b SL |
430 | impl<'a> Read for &'a Socket { |
431 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
432 | (**self).read(buf) | |
433 | } | |
85aaf69f SL |
434 | } |
435 | ||
94222f64 XL |
436 | impl AsInner<OwnedSocket> for Socket { |
437 | fn as_inner(&self) -> &OwnedSocket { | |
438 | &self.0 | |
85aaf69f SL |
439 | } |
440 | } | |
441 | ||
94222f64 XL |
442 | impl FromInner<OwnedSocket> for Socket { |
443 | fn from_inner(sock: OwnedSocket) -> Socket { | |
444 | Socket(sock) | |
dfeec247 | 445 | } |
85aaf69f | 446 | } |
c34b1796 | 447 | |
94222f64 XL |
448 | impl IntoInner<OwnedSocket> for Socket { |
449 | fn into_inner(self) -> OwnedSocket { | |
450 | self.0 | |
451 | } | |
452 | } | |
453 | ||
454 | impl AsSocket for Socket { | |
455 | fn as_socket(&self) -> BorrowedSocket<'_> { | |
456 | self.0.as_socket() | |
457 | } | |
458 | } | |
459 | ||
460 | impl AsRawSocket for Socket { | |
461 | fn as_raw_socket(&self) -> RawSocket { | |
462 | self.0.as_raw_socket() | |
463 | } | |
464 | } | |
465 | ||
466 | impl IntoRawSocket for Socket { | |
467 | fn into_raw_socket(self) -> RawSocket { | |
468 | self.0.into_raw_socket() | |
dfeec247 | 469 | } |
c34b1796 | 470 | } |
c1a9b12d | 471 | |
94222f64 XL |
472 | impl FromRawSocket for Socket { |
473 | unsafe fn from_raw_socket(raw_socket: RawSocket) -> Self { | |
474 | Self(FromRawSocket::from_raw_socket(raw_socket)) | |
c1a9b12d SL |
475 | } |
476 | } |