-
Notifications
You must be signed in to change notification settings - Fork 747
/
Copy pathmod.rs
159 lines (145 loc) · 4.7 KB
/
mod.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use std::io;
use std::mem::size_of_val;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::pin::Pin;
use std::sync::{Arc, Mutex, Once};
use winapi::ctypes::c_int;
use winapi::shared::ws2def::SOCKADDR;
use winapi::um::winsock2::{
ioctlsocket, socket, FIONBIO, INVALID_SOCKET, PF_INET, PF_INET6, SOCKET,
};
/// Helper macro to execute a system call that returns an `io::Result`.
//
// Macro must be defined before any modules that uses them.
macro_rules! syscall {
($fn: ident ( $($arg: expr),* $(,)* ), $err_test: path, $err_value: expr) => {{
let res = unsafe { $fn($($arg, )*) };
if $err_test(&res, &$err_value) {
Err(io::Error::last_os_error())
} else {
Ok(res)
}
}};
}
/// Helper macro to execute an I/O operation and register interests if the
/// operation would block.
macro_rules! try_io {
($self: ident, $method: ident $(, $args: expr)*) => {{
let result = (&$self.inner).$method($($args),*);
if let Err(ref e) = result {
if e.kind() == io::ErrorKind::WouldBlock {
$self.io_blocked_reregister()?;
}
}
result
}};
($self: ident.$method: ident ( $($arg: expr),* $(,)* ), $reregister_check: expr) => {{
let result = (&$self.inner).$method($($arg),*);
let should_reregister = match &result {
// See if we need reregister interest to emulate edge-triggers.
Ok(ok) => $reregister_check(ok),
Err(err) if err.kind() == io::ErrorKind::WouldBlock => true,
Err(_) => false,
};
if should_reregister {
$self.io_blocked_reregister()?;
}
result
}};
}
mod afd;
pub mod event;
mod io_status_block;
mod selector;
mod tcp;
mod udp;
mod waker;
pub use event::{Event, Events};
pub use selector::{Selector, SelectorInner, SockState};
pub use tcp::{TcpListener, TcpStream};
pub use udp::UdpSocket;
pub use waker::Waker;
pub trait SocketState {
// The `SockState` struct needs to be pinned in memory because it contains
// `OVERLAPPED` and `AFD_POLL_INFO` fields which are modified in the
// background by the windows kernel, therefore we need to ensure they are
// never moved to a different memory address.
fn get_sock_state(&self) -> Option<Pin<Arc<Mutex<SockState>>>>;
fn set_sock_state(&self, sock_state: Option<Pin<Arc<Mutex<SockState>>>>);
}
use crate::{Interests, Token};
struct InternalState {
selector: Arc<SelectorInner>,
token: Token,
interests: Interests,
sock_state: Option<Pin<Arc<Mutex<SockState>>>>,
}
impl InternalState {
fn new(selector: Arc<SelectorInner>, token: Token, interests: Interests) -> InternalState {
InternalState {
selector,
token,
interests,
sock_state: None,
}
}
}
impl Drop for InternalState {
fn drop(&mut self) {
if let Some(sock_state) = self.sock_state.as_ref() {
let mut sock_state = sock_state.lock().unwrap();
sock_state.mark_delete();
}
}
}
/// Initialise the network stack for Windows.
fn init() {
static INIT: Once = Once::new();
INIT.call_once(|| {
// Let standard library call `WSAStartup` for us, we can't do it
// ourselves because otherwise using any type in `std::net` would panic
// when it tries to call `WSAStartup` a second time.
drop(std::net::UdpSocket::bind("127.0.0.1:0"));
});
}
/// Create a new non-blocking socket.
fn new_socket(addr: SocketAddr, socket_type: c_int) -> io::Result<SOCKET> {
let domain = match addr {
SocketAddr::V4(..) => PF_INET,
SocketAddr::V6(..) => PF_INET6,
};
syscall!(
socket(domain, socket_type, 0),
PartialEq::eq,
INVALID_SOCKET
)
.and_then(|socket| {
syscall!(ioctlsocket(socket, FIONBIO, &mut 1), PartialEq::ne, 0).map(|_| socket as SOCKET)
})
}
fn socket_addr(addr: &SocketAddr) -> (*const SOCKADDR, c_int) {
match addr {
SocketAddr::V4(ref addr) => (
addr as *const _ as *const SOCKADDR,
size_of_val(addr) as c_int,
),
SocketAddr::V6(ref addr) => (
addr as *const _ as *const SOCKADDR,
size_of_val(addr) as c_int,
),
}
}
fn inaddr_any(other: SocketAddr) -> SocketAddr {
match other {
SocketAddr::V4(..) => {
let any = Ipv4Addr::new(0, 0, 0, 0);
let addr = SocketAddrV4::new(any, 0);
SocketAddr::V4(addr)
}
SocketAddr::V6(..) => {
let any = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
let addr = SocketAddrV6::new(any, 0, 0, 0);
SocketAddr::V6(addr)
}
}
}