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 = Atomic::::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: T) -> io::Result { 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(mut f: F) -> io::Result where T: IsMinusOne, F: FnMut() -> T, { cvt(f()) }