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