| use super::c; | |
| use crate::ffi::c_int; | |
| use crate::sync::atomic::Atomic; | |
| use crate::sync::atomic::Ordering::{AcqRel, Relaxed}; | |
| use crate::{io, mem}; | |
| static WSA_STARTED: Atomic<bool> = Atomic::<bool>::new(false); | |
| /// Checks whether the Windows socket interface has been started already, and | |
| /// if not, starts it. | |
| #[inline] | |
| pub fn startup() { | |
| if !WSA_STARTED.load(Relaxed) { | |
| wsa_startup(); | |
| } | |
| } | |
| #[cold] | |
| fn wsa_startup() { | |
| unsafe { | |
| let mut data: c::WSADATA = mem::zeroed(); | |
| let ret = c::WSAStartup( | |
| 0x202, // version 2.2 | |
| &mut data, | |
| ); | |
| assert_eq!(ret, 0); | |
| if WSA_STARTED.swap(true, AcqRel) { | |
| // If another thread raced with us and called WSAStartup first then call | |
| // WSACleanup so it's as though WSAStartup was only called once. | |
| c::WSACleanup(); | |
| } | |
| } | |
| } | |
| pub fn cleanup() { | |
| // We don't need to call WSACleanup here because exiting the process will cause | |
| // the OS to clean everything for us, which is faster than doing it manually. | |
| // See #141799. | |
| } | |
| /// Returns the last error from the Windows socket interface. | |
| pub fn last_error() -> io::Error { | |
| io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) | |
| } | |
| #[doc(hidden)] | |
| pub trait IsMinusOne { | |
| fn is_minus_one(&self) -> bool; | |
| } | |
| macro_rules! impl_is_minus_one { | |
| ($($t:ident)*) => ($(impl IsMinusOne for $t { | |
| fn is_minus_one(&self) -> bool { | |
| *self == -1 | |
| } | |
| })*) | |
| } | |
| impl_is_minus_one! { i8 i16 i32 i64 isize } | |
| /// Checks if the signed integer is the Windows constant `SOCKET_ERROR` (-1) | |
| /// and if so, returns the last error from the Windows socket interface. This | |
| /// function must be called before another call to the socket API is made. | |
| pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> { | |
| if t.is_minus_one() { Err(last_error()) } else { Ok(t) } | |
| } | |
| /// A variant of `cvt` for `getaddrinfo` which return 0 for a success. | |
| pub fn cvt_gai(err: c_int) -> io::Result<()> { | |
| if err == 0 { Ok(()) } else { Err(last_error()) } | |
| } | |
| /// Just to provide the same interface as sys/pal/unix/net.rs | |
| pub fn cvt_r<T, F>(mut f: F) -> io::Result<T> | |
| where | |
| T: IsMinusOne, | |
| F: FnMut() -> T, | |
| { | |
| cvt(f()) | |
| } |