std\sys\pal\windows/
winsock.rs

1use super::c;
2use crate::ffi::c_int;
3use crate::sync::atomic::Atomic;
4use crate::sync::atomic::Ordering::{AcqRel, Relaxed};
5use crate::{io, mem};
6
7static WSA_STARTED: Atomic<bool> = Atomic::<bool>::new(false);
8
9/// Checks whether the Windows socket interface has been started already, and
10/// if not, starts it.
11#[inline]
12pub fn startup() {
13    if !WSA_STARTED.load(Relaxed) {
14        wsa_startup();
15    }
16}
17
18#[cold]
19fn wsa_startup() {
20    unsafe {
21        let mut data: c::WSADATA = mem::zeroed();
22        let ret = c::WSAStartup(
23            0x202, // version 2.2
24            &mut data,
25        );
26        assert_eq!(ret, 0);
27        if WSA_STARTED.swap(true, AcqRel) {
28            // If another thread raced with us and called WSAStartup first then call
29            // WSACleanup so it's as though WSAStartup was only called once.
30            c::WSACleanup();
31        }
32    }
33}
34
35pub fn cleanup() {
36    // We don't need to call WSACleanup here because exiting the process will cause
37    // the OS to clean everything for us, which is faster than doing it manually.
38    // See #141799.
39}
40
41/// Returns the last error from the Windows socket interface.
42pub fn last_error() -> io::Error {
43    io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() })
44}
45
46#[doc(hidden)]
47pub trait IsMinusOne {
48    fn is_minus_one(&self) -> bool;
49}
50
51macro_rules! impl_is_minus_one {
52    ($($t:ident)*) => ($(impl IsMinusOne for $t {
53        fn is_minus_one(&self) -> bool {
54            *self == -1
55        }
56    })*)
57}
58
59impl_is_minus_one! { i8 i16 i32 i64 isize }
60
61/// Checks if the signed integer is the Windows constant `SOCKET_ERROR` (-1)
62/// and if so, returns the last error from the Windows socket interface. This
63/// function must be called before another call to the socket API is made.
64pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
65    if t.is_minus_one() { Err(last_error()) } else { Ok(t) }
66}
67
68/// A variant of `cvt` for `getaddrinfo` which return 0 for a success.
69pub fn cvt_gai(err: c_int) -> io::Result<()> {
70    if err == 0 { Ok(()) } else { Err(last_error()) }
71}
72
73/// Just to provide the same interface as sys/pal/unix/net.rs
74pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
75where
76    T: IsMinusOne,
77    F: FnMut() -> T,
78{
79    cvt(f())
80}