1 use std::io;
2 use std::mem;
3 use std::net::SocketAddr;
4 use std::sync::Once;
5 
6 use windows_sys::Win32::Networking::WinSock::{
7     closesocket, ioctlsocket, socket, AF_INET, AF_INET6, FIONBIO, IN6_ADDR, IN6_ADDR_0,
8     INVALID_SOCKET, IN_ADDR, IN_ADDR_0, SOCKADDR, SOCKADDR_IN, SOCKADDR_IN6, SOCKADDR_IN6_0,
9     SOCKET,
10 };
11 
12 /// Initialise the network stack for Windows.
init()13 fn init() {
14     static INIT: Once = Once::new();
15     INIT.call_once(|| {
16         // Let standard library call `WSAStartup` for us, we can't do it
17         // ourselves because otherwise using any type in `std::net` would panic
18         // when it tries to call `WSAStartup` a second time.
19         drop(std::net::UdpSocket::bind("127.0.0.1:0"));
20     });
21 }
22 
23 /// Create a new non-blocking socket.
new_ip_socket(addr: SocketAddr, socket_type: i32) -> io::Result<SOCKET>24 pub(crate) fn new_ip_socket(addr: SocketAddr, socket_type: i32) -> io::Result<SOCKET> {
25     let domain = match addr {
26         SocketAddr::V4(..) => AF_INET,
27         SocketAddr::V6(..) => AF_INET6,
28     };
29 
30     new_socket(domain.into(), socket_type)
31 }
32 
new_socket(domain: u32, socket_type: i32) -> io::Result<SOCKET>33 pub(crate) fn new_socket(domain: u32, socket_type: i32) -> io::Result<SOCKET> {
34     init();
35 
36     let socket = syscall!(
37         socket(domain as i32, socket_type, 0),
38         PartialEq::eq,
39         INVALID_SOCKET
40     )?;
41 
42     if let Err(err) = syscall!(ioctlsocket(socket, FIONBIO, &mut 1), PartialEq::ne, 0) {
43         let _ = unsafe { closesocket(socket) };
44         return Err(err);
45     }
46 
47     Ok(socket as SOCKET)
48 }
49 
50 /// A type with the same memory layout as `SOCKADDR`. Used in converting Rust level
51 /// SocketAddr* types into their system representation. The benefit of this specific
52 /// type over using `SOCKADDR_STORAGE` is that this type is exactly as large as it
53 /// needs to be and not a lot larger. And it can be initialized cleaner from Rust.
54 #[repr(C)]
55 pub(crate) union SocketAddrCRepr {
56     v4: SOCKADDR_IN,
57     v6: SOCKADDR_IN6,
58 }
59 
60 impl SocketAddrCRepr {
as_ptr(&self) -> *const SOCKADDR61     pub(crate) fn as_ptr(&self) -> *const SOCKADDR {
62         self as *const _ as *const SOCKADDR
63     }
64 }
65 
socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, i32)66 pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, i32) {
67     match addr {
68         SocketAddr::V4(ref addr) => {
69             // `s_addr` is stored as BE on all machine and the array is in BE order.
70             // So the native endian conversion method is used so that it's never swapped.
71             let sin_addr = unsafe {
72                 let mut s_un = mem::zeroed::<IN_ADDR_0>();
73                 s_un.S_addr = u32::from_ne_bytes(addr.ip().octets());
74                 IN_ADDR { S_un: s_un }
75             };
76 
77             let sockaddr_in = SOCKADDR_IN {
78                 sin_family: AF_INET as u16, // 1
79                 sin_port: addr.port().to_be(),
80                 sin_addr,
81                 sin_zero: [0; 8],
82             };
83 
84             let sockaddr = SocketAddrCRepr { v4: sockaddr_in };
85             (sockaddr, mem::size_of::<SOCKADDR_IN>() as i32)
86         }
87         SocketAddr::V6(ref addr) => {
88             let sin6_addr = unsafe {
89                 let mut u = mem::zeroed::<IN6_ADDR_0>();
90                 u.Byte = addr.ip().octets();
91                 IN6_ADDR { u }
92             };
93             let u = unsafe {
94                 let mut u = mem::zeroed::<SOCKADDR_IN6_0>();
95                 u.sin6_scope_id = addr.scope_id();
96                 u
97             };
98 
99             let sockaddr_in6 = SOCKADDR_IN6 {
100                 sin6_family: AF_INET6 as u16, // 23
101                 sin6_port: addr.port().to_be(),
102                 sin6_addr,
103                 sin6_flowinfo: addr.flowinfo(),
104                 Anonymous: u,
105             };
106 
107             let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 };
108             (sockaddr, mem::size_of::<SOCKADDR_IN6>() as i32)
109         }
110     }
111 }
112