author | alfadur |
Tue, 09 Apr 2019 21:08:35 +0300 | |
changeset 14779 | f43ab2bd76ae |
parent 14697 | f64e21f164a5 |
child 14780 | 65861ba8b4e8 |
permissions | -rw-r--r-- |
13119 | 1 |
extern crate slab; |
2 |
||
13414 | 3 |
use std::{ |
13415 | 4 |
collections::HashSet, |
14457 | 5 |
io, |
6 |
io::{Error, ErrorKind, Read, Write}, |
|
7 |
mem::{replace, swap}, |
|
8 |
net::{IpAddr, Ipv4Addr, SocketAddr}, |
|
13414 | 9 |
}; |
10 |
||
14457 | 11 |
use log::*; |
13414 | 12 |
use mio::{ |
14457 | 13 |
net::{TcpListener, TcpStream}, |
14 |
Poll, PollOpt, Ready, Token, |
|
13414 | 15 |
}; |
16 |
use netbuf; |
|
13119 | 17 |
use slab::Slab; |
18 |
||
14779
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
19 |
use super::{core::FileServerIO, core::HWServer, coretypes::ClientId, handlers}; |
13666 | 20 |
use crate::{ |
14457 | 21 |
protocol::{messages::*, ProtocolDecoder}, |
13666 | 22 |
utils, |
13414 | 23 |
}; |
14779
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
24 |
|
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
25 |
#[cfg(feature = "official-server")] |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
26 |
use super::io::{IOThread, RequestId}; |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
27 |
|
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
28 |
use crate::server::handlers::{IoResult, IoTask}; |
13799 | 29 |
#[cfg(feature = "tls-connections")] |
30 |
use openssl::{ |
|
14457 | 31 |
error::ErrorStack, |
13799 | 32 |
ssl::{ |
14457 | 33 |
HandshakeError, MidHandshakeSslStream, Ssl, SslContext, SslContextBuilder, SslFiletype, |
34 |
SslMethod, SslOptions, SslStream, SslStreamBuilder, SslVerifyMode, |
|
13799 | 35 |
}, |
36 |
}; |
|
13414 | 37 |
|
38 |
const MAX_BYTES_PER_READ: usize = 2048; |
|
13119 | 39 |
|
13415 | 40 |
#[derive(Hash, Eq, PartialEq, Copy, Clone)] |
13414 | 41 |
pub enum NetworkClientState { |
42 |
Idle, |
|
43 |
NeedsWrite, |
|
44 |
NeedsRead, |
|
45 |
Closed, |
|
46 |
} |
|
47 |
||
48 |
type NetworkResult<T> = io::Result<(T, NetworkClientState)>; |
|
13119 | 49 |
|
13799 | 50 |
#[cfg(not(feature = "tls-connections"))] |
51 |
pub enum ClientSocket { |
|
14457 | 52 |
Plain(TcpStream), |
13799 | 53 |
} |
54 |
||
55 |
#[cfg(feature = "tls-connections")] |
|
56 |
pub enum ClientSocket { |
|
57 |
SslHandshake(Option<MidHandshakeSslStream<TcpStream>>), |
|
14457 | 58 |
SslStream(SslStream<TcpStream>), |
13799 | 59 |
} |
60 |
||
61 |
impl ClientSocket { |
|
62 |
fn inner(&self) -> &TcpStream { |
|
63 |
#[cfg(not(feature = "tls-connections"))] |
|
64 |
match self { |
|
65 |
ClientSocket::Plain(stream) => stream, |
|
66 |
} |
|
67 |
||
68 |
#[cfg(feature = "tls-connections")] |
|
69 |
match self { |
|
70 |
ClientSocket::SslHandshake(Some(builder)) => builder.get_ref(), |
|
71 |
ClientSocket::SslHandshake(None) => unreachable!(), |
|
14457 | 72 |
ClientSocket::SslStream(ssl_stream) => ssl_stream.get_ref(), |
13799 | 73 |
} |
74 |
} |
|
75 |
} |
|
76 |
||
13119 | 77 |
pub struct NetworkClient { |
78 |
id: ClientId, |
|
13799 | 79 |
socket: ClientSocket, |
13119 | 80 |
peer_addr: SocketAddr, |
81 |
decoder: ProtocolDecoder, |
|
14457 | 82 |
buf_out: netbuf::Buf, |
13119 | 83 |
} |
84 |
||
85 |
impl NetworkClient { |
|
13799 | 86 |
pub fn new(id: ClientId, socket: ClientSocket, peer_addr: SocketAddr) -> NetworkClient { |
13119 | 87 |
NetworkClient { |
14457 | 88 |
id, |
89 |
socket, |
|
90 |
peer_addr, |
|
13119 | 91 |
decoder: ProtocolDecoder::new(), |
14457 | 92 |
buf_out: netbuf::Buf::new(), |
13119 | 93 |
} |
94 |
} |
|
95 |
||
13802 | 96 |
#[cfg(feature = "tls-connections")] |
14457 | 97 |
fn handshake_impl( |
98 |
&mut self, |
|
99 |
handshake: MidHandshakeSslStream<TcpStream>, |
|
100 |
) -> io::Result<NetworkClientState> { |
|
13802 | 101 |
match handshake.handshake() { |
102 |
Ok(stream) => { |
|
103 |
self.socket = ClientSocket::SslStream(stream); |
|
14457 | 104 |
debug!( |
105 |
"TLS handshake with {} ({}) completed", |
|
106 |
self.id, self.peer_addr |
|
107 |
); |
|
13802 | 108 |
Ok(NetworkClientState::Idle) |
109 |
} |
|
110 |
Err(HandshakeError::WouldBlock(new_handshake)) => { |
|
111 |
self.socket = ClientSocket::SslHandshake(Some(new_handshake)); |
|
112 |
Ok(NetworkClientState::Idle) |
|
113 |
} |
|
13803 | 114 |
Err(HandshakeError::Failure(new_handshake)) => { |
115 |
self.socket = ClientSocket::SslHandshake(Some(new_handshake)); |
|
13802 | 116 |
debug!("TLS handshake with {} ({}) failed", self.id, self.peer_addr); |
117 |
Err(Error::new(ErrorKind::Other, "Connection failure")) |
|
118 |
} |
|
14457 | 119 |
Err(HandshakeError::SetupFailure(_)) => unreachable!(), |
13802 | 120 |
} |
121 |
} |
|
122 |
||
14457 | 123 |
fn read_impl<R: Read>( |
124 |
decoder: &mut ProtocolDecoder, |
|
125 |
source: &mut R, |
|
126 |
id: ClientId, |
|
127 |
addr: &SocketAddr, |
|
128 |
) -> NetworkResult<Vec<HWProtocolMessage>> { |
|
13414 | 129 |
let mut bytes_read = 0; |
130 |
let result = loop { |
|
13799 | 131 |
match decoder.read_from(source) { |
13414 | 132 |
Ok(bytes) => { |
13799 | 133 |
debug!("Client {}: read {} bytes", id, bytes); |
13414 | 134 |
bytes_read += bytes; |
135 |
if bytes == 0 { |
|
136 |
let result = if bytes_read == 0 { |
|
13799 | 137 |
info!("EOF for client {} ({})", id, addr); |
13414 | 138 |
(Vec::new(), NetworkClientState::Closed) |
139 |
} else { |
|
13799 | 140 |
(decoder.extract_messages(), NetworkClientState::NeedsRead) |
13414 | 141 |
}; |
142 |
break Ok(result); |
|
14457 | 143 |
} else if bytes_read >= MAX_BYTES_PER_READ { |
144 |
break Ok((decoder.extract_messages(), NetworkClientState::NeedsRead)); |
|
13414 | 145 |
} |
146 |
} |
|
147 |
Err(ref error) if error.kind() == ErrorKind::WouldBlock => { |
|
14457 | 148 |
let messages = if bytes_read == 0 { |
13414 | 149 |
Vec::new() |
150 |
} else { |
|
13799 | 151 |
decoder.extract_messages() |
13414 | 152 |
}; |
153 |
break Ok((messages, NetworkClientState::Idle)); |
|
154 |
} |
|
14457 | 155 |
Err(error) => break Err(error), |
13414 | 156 |
} |
157 |
}; |
|
13799 | 158 |
decoder.sweep(); |
13414 | 159 |
result |
160 |
} |
|
161 |
||
13799 | 162 |
pub fn read(&mut self) -> NetworkResult<Vec<HWProtocolMessage>> { |
163 |
#[cfg(not(feature = "tls-connections"))] |
|
164 |
match self.socket { |
|
14457 | 165 |
ClientSocket::Plain(ref mut stream) => { |
166 |
NetworkClient::read_impl(&mut self.decoder, stream, self.id, &self.peer_addr) |
|
167 |
} |
|
13799 | 168 |
} |
169 |
||
170 |
#[cfg(feature = "tls-connections")] |
|
171 |
match self.socket { |
|
172 |
ClientSocket::SslHandshake(ref mut handshake_opt) => { |
|
13802 | 173 |
let handshake = std::mem::replace(handshake_opt, None).unwrap(); |
174 |
Ok((Vec::new(), self.handshake_impl(handshake)?)) |
|
14457 | 175 |
} |
176 |
ClientSocket::SslStream(ref mut stream) => { |
|
13799 | 177 |
NetworkClient::read_impl(&mut self.decoder, stream, self.id, &self.peer_addr) |
14457 | 178 |
} |
13799 | 179 |
} |
180 |
} |
|
181 |
||
182 |
fn write_impl<W: Write>(buf_out: &mut netbuf::Buf, destination: &mut W) -> NetworkResult<()> { |
|
13414 | 183 |
let result = loop { |
13799 | 184 |
match buf_out.write_to(destination) { |
14457 | 185 |
Ok(bytes) if buf_out.is_empty() || bytes == 0 => { |
14671
455865ccd36c
Server action refactoring part 2 of N
alfadur <mail@none>
parents:
14457
diff
changeset
|
186 |
break Ok(((), NetworkClientState::Idle)); |
14457 | 187 |
} |
13415 | 188 |
Ok(_) => (), |
14457 | 189 |
Err(ref error) |
190 |
if error.kind() == ErrorKind::Interrupted |
|
191 |
|| error.kind() == ErrorKind::WouldBlock => |
|
192 |
{ |
|
13414 | 193 |
break Ok(((), NetworkClientState::NeedsWrite)); |
14457 | 194 |
} |
195 |
Err(error) => break Err(error), |
|
13414 | 196 |
} |
197 |
}; |
|
13799 | 198 |
result |
199 |
} |
|
200 |
||
201 |
pub fn write(&mut self) -> NetworkResult<()> { |
|
202 |
let result = { |
|
203 |
#[cfg(not(feature = "tls-connections"))] |
|
204 |
match self.socket { |
|
14457 | 205 |
ClientSocket::Plain(ref mut stream) => { |
13799 | 206 |
NetworkClient::write_impl(&mut self.buf_out, stream) |
14457 | 207 |
} |
13799 | 208 |
} |
209 |
||
14457 | 210 |
#[cfg(feature = "tls-connections")] |
211 |
{ |
|
13799 | 212 |
match self.socket { |
13802 | 213 |
ClientSocket::SslHandshake(ref mut handshake_opt) => { |
214 |
let handshake = std::mem::replace(handshake_opt, None).unwrap(); |
|
215 |
Ok(((), self.handshake_impl(handshake)?)) |
|
216 |
} |
|
14457 | 217 |
ClientSocket::SslStream(ref mut stream) => { |
13799 | 218 |
NetworkClient::write_impl(&mut self.buf_out, stream) |
14457 | 219 |
} |
13799 | 220 |
} |
221 |
} |
|
222 |
}; |
|
223 |
||
224 |
self.socket.inner().flush()?; |
|
13414 | 225 |
result |
226 |
} |
|
227 |
||
13119 | 228 |
pub fn send_raw_msg(&mut self, msg: &[u8]) { |
13524 | 229 |
self.buf_out.write_all(msg).unwrap(); |
13119 | 230 |
} |
231 |
||
13524 | 232 |
pub fn send_string(&mut self, msg: &str) { |
13119 | 233 |
self.send_raw_msg(&msg.as_bytes()); |
234 |
} |
|
235 |
} |
|
236 |
||
13799 | 237 |
#[cfg(feature = "tls-connections")] |
238 |
struct ServerSsl { |
|
14457 | 239 |
context: SslContext, |
13799 | 240 |
} |
241 |
||
14779
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
242 |
#[cfg(feature = "official-server")] |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
243 |
pub struct IoLayer { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
244 |
next_request_id: RequestId, |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
245 |
request_queue: Vec<(RequestId, ClientId)>, |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
246 |
io_thread: IOThread, |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
247 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
248 |
|
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
249 |
#[cfg(feature = "official-server")] |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
250 |
impl IoLayer { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
251 |
fn new() -> Self { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
252 |
Self { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
253 |
next_request_id: 0, |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
254 |
request_queue: vec![], |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
255 |
io_thread: IOThread::new(), |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
256 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
257 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
258 |
|
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
259 |
fn send(&mut self, client_id: ClientId, task: IoTask) { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
260 |
let request_id = self.next_request_id; |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
261 |
self.next_request_id += 1; |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
262 |
self.request_queue.push((request_id, client_id)); |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
263 |
self.io_thread.send(request_id, task); |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
264 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
265 |
|
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
266 |
fn try_recv(&mut self) -> Option<(ClientId, IoResult)> { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
267 |
let (request_id, result) = self.io_thread.try_recv()?; |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
268 |
if let Some(index) = self |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
269 |
.request_queue |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
270 |
.iter() |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
271 |
.position(|(id, _)| *id == request_id) |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
272 |
{ |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
273 |
let (_, client_id) = self.request_queue.swap_remove(index); |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
274 |
Some((client_id, result)) |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
275 |
} else { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
276 |
None |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
277 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
278 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
279 |
|
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
280 |
fn cancel(&mut self, client_id: ClientId) { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
281 |
let mut index = 0; |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
282 |
while index < self.request_queue.len() { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
283 |
if self.request_queue[index].1 == client_id { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
284 |
self.request_queue.swap_remove(index); |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
285 |
} else { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
286 |
index += 1; |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
287 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
288 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
289 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
290 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
291 |
|
13119 | 292 |
pub struct NetworkLayer { |
293 |
listener: TcpListener, |
|
294 |
server: HWServer, |
|
13414 | 295 |
clients: Slab<NetworkClient>, |
13415 | 296 |
pending: HashSet<(ClientId, NetworkClientState)>, |
13799 | 297 |
pending_cache: Vec<(ClientId, NetworkClientState)>, |
298 |
#[cfg(feature = "tls-connections")] |
|
14457 | 299 |
ssl: ServerSsl, |
14779
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
300 |
#[cfg(feature = "official-server")] |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
301 |
io: IoLayer, |
13119 | 302 |
} |
303 |
||
304 |
impl NetworkLayer { |
|
305 |
pub fn new(listener: TcpListener, clients_limit: usize, rooms_limit: usize) -> NetworkLayer { |
|
14392 | 306 |
let server = HWServer::new(clients_limit, rooms_limit, Box::new(FileServerIO::new())); |
13119 | 307 |
let clients = Slab::with_capacity(clients_limit); |
13415 | 308 |
let pending = HashSet::with_capacity(2 * clients_limit); |
309 |
let pending_cache = Vec::with_capacity(2 * clients_limit); |
|
13799 | 310 |
|
311 |
NetworkLayer { |
|
14457 | 312 |
listener, |
313 |
server, |
|
314 |
clients, |
|
315 |
pending, |
|
316 |
pending_cache, |
|
13799 | 317 |
#[cfg(feature = "tls-connections")] |
14457 | 318 |
ssl: NetworkLayer::create_ssl_context(), |
14779
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
319 |
#[cfg(feature = "official-server")] |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
320 |
io: IoLayer::new(), |
13799 | 321 |
} |
322 |
} |
|
323 |
||
324 |
#[cfg(feature = "tls-connections")] |
|
325 |
fn create_ssl_context() -> ServerSsl { |
|
326 |
let mut builder = SslContextBuilder::new(SslMethod::tls()).unwrap(); |
|
327 |
builder.set_verify(SslVerifyMode::NONE); |
|
328 |
builder.set_read_ahead(true); |
|
14457 | 329 |
builder |
330 |
.set_certificate_file("ssl/cert.pem", SslFiletype::PEM) |
|
331 |
.unwrap(); |
|
332 |
builder |
|
333 |
.set_private_key_file("ssl/key.pem", SslFiletype::PEM) |
|
334 |
.unwrap(); |
|
13799 | 335 |
builder.set_options(SslOptions::NO_COMPRESSION); |
336 |
builder.set_cipher_list("DEFAULT:!LOW:!RC4:!EXP").unwrap(); |
|
14457 | 337 |
ServerSsl { |
338 |
context: builder.build(), |
|
339 |
} |
|
13119 | 340 |
} |
341 |
||
342 |
pub fn register_server(&self, poll: &Poll) -> io::Result<()> { |
|
14457 | 343 |
poll.register( |
344 |
&self.listener, |
|
14779
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
345 |
utils::SERVER_TOKEN, |
14457 | 346 |
Ready::readable(), |
347 |
PollOpt::edge(), |
|
14779
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
348 |
)?; |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
349 |
|
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
350 |
#[cfg(feature = "official-server")] |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
351 |
self.io.io_thread.register_rx(poll, utils::IO_TOKEN)?; |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
352 |
|
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
353 |
Ok(()) |
13119 | 354 |
} |
355 |
||
356 |
fn deregister_client(&mut self, poll: &Poll, id: ClientId) { |
|
357 |
let mut client_exists = false; |
|
13414 | 358 |
if let Some(ref client) = self.clients.get(id) { |
13799 | 359 |
poll.deregister(client.socket.inner()) |
13524 | 360 |
.expect("could not deregister socket"); |
13119 | 361 |
info!("client {} ({}) removed", client.id, client.peer_addr); |
362 |
client_exists = true; |
|
363 |
} |
|
364 |
if client_exists { |
|
365 |
self.clients.remove(id); |
|
14779
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
366 |
#[cfg(feature = "official-server")] |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
367 |
self.io.cancel(id); |
13119 | 368 |
} |
369 |
} |
|
370 |
||
14457 | 371 |
fn register_client( |
372 |
&mut self, |
|
373 |
poll: &Poll, |
|
374 |
client_socket: ClientSocket, |
|
375 |
addr: SocketAddr, |
|
14693 | 376 |
) -> ClientId { |
377 |
let entry = self.clients.vacant_entry(); |
|
378 |
let client_id = entry.key(); |
|
379 |
||
14457 | 380 |
poll.register( |
381 |
client_socket.inner(), |
|
14693 | 382 |
Token(client_id), |
14457 | 383 |
Ready::readable() | Ready::writable(), |
384 |
PollOpt::edge(), |
|
385 |
) |
|
386 |
.expect("could not register socket with event loop"); |
|
13119 | 387 |
|
14693 | 388 |
let client = NetworkClient::new(client_id, client_socket, addr); |
13119 | 389 |
info!("client {} ({}) added", client.id, client.peer_addr); |
390 |
entry.insert(client); |
|
14693 | 391 |
|
392 |
client_id |
|
13119 | 393 |
} |
394 |
||
14779
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
395 |
fn handle_response(&mut self, mut response: handlers::Response, poll: &Poll) { |
14672
6e6632068a33
Server action refactoring part 3 of N
alfadur <mail@none>
parents:
14671
diff
changeset
|
396 |
debug!("{} pending server messages", response.len()); |
6e6632068a33
Server action refactoring part 3 of N
alfadur <mail@none>
parents:
14671
diff
changeset
|
397 |
let output = response.extract_messages(&mut self.server); |
6e6632068a33
Server action refactoring part 3 of N
alfadur <mail@none>
parents:
14671
diff
changeset
|
398 |
for (clients, message) in output { |
13419 | 399 |
debug!("Message {:?} to {:?}", message, clients); |
400 |
let msg_string = message.to_raw_protocol(); |
|
401 |
for client_id in clients { |
|
402 |
if let Some(client) = self.clients.get_mut(client_id) { |
|
403 |
client.send_string(&msg_string); |
|
14457 | 404 |
self.pending |
405 |
.insert((client_id, NetworkClientState::NeedsWrite)); |
|
13414 | 406 |
} |
407 |
} |
|
408 |
} |
|
14696 | 409 |
|
410 |
for client_id in response.extract_removed_clients() { |
|
411 |
self.deregister_client(poll, client_id); |
|
412 |
} |
|
14779
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
413 |
|
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
414 |
#[cfg(feature = "official-server")] |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
415 |
{ |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
416 |
let client_id = response.client_id(); |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
417 |
for task in response.extract_io_tasks() { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
418 |
self.io.send(client_id, task); |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
419 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
420 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
421 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
422 |
|
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
423 |
#[cfg(feature = "official-server")] |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
424 |
pub fn handle_io_result(&mut self) { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
425 |
if let Some((client_id, result)) = self.io.try_recv() { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
426 |
let mut response = handlers::Response::new(client_id); |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
427 |
handlers::handle_io_result(&mut self.server, client_id, &mut response, result); |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
428 |
} |
13414 | 429 |
} |
430 |
||
13799 | 431 |
fn create_client_socket(&self, socket: TcpStream) -> io::Result<ClientSocket> { |
14457 | 432 |
#[cfg(not(feature = "tls-connections"))] |
433 |
{ |
|
13799 | 434 |
Ok(ClientSocket::Plain(socket)) |
435 |
} |
|
436 |
||
14457 | 437 |
#[cfg(feature = "tls-connections")] |
438 |
{ |
|
13799 | 439 |
let ssl = Ssl::new(&self.ssl.context).unwrap(); |
440 |
let mut builder = SslStreamBuilder::new(ssl, socket); |
|
441 |
builder.set_accept_state(); |
|
442 |
match builder.handshake() { |
|
14457 | 443 |
Ok(stream) => Ok(ClientSocket::SslStream(stream)), |
444 |
Err(HandshakeError::WouldBlock(stream)) => { |
|
445 |
Ok(ClientSocket::SslHandshake(Some(stream))) |
|
446 |
} |
|
13799 | 447 |
Err(e) => { |
448 |
debug!("OpenSSL handshake failed: {}", e); |
|
449 |
Err(Error::new(ErrorKind::Other, "Connection failure")) |
|
450 |
} |
|
451 |
} |
|
452 |
} |
|
453 |
} |
|
454 |
||
13119 | 455 |
pub fn accept_client(&mut self, poll: &Poll) -> io::Result<()> { |
456 |
let (client_socket, addr) = self.listener.accept()?; |
|
457 |
info!("Connected: {}", addr); |
|
458 |
||
14693 | 459 |
let client_id = self.register_client(poll, self.create_client_socket(client_socket)?, addr); |
460 |
||
461 |
let mut response = handlers::Response::new(client_id); |
|
462 |
||
463 |
handlers::handle_client_accept(&mut self.server, client_id, &mut response); |
|
464 |
||
465 |
if !response.is_empty() { |
|
14779
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
466 |
self.handle_response(response, poll); |
14693 | 467 |
} |
13119 | 468 |
|
469 |
Ok(()) |
|
470 |
} |
|
471 |
||
14457 | 472 |
fn operation_failed( |
473 |
&mut self, |
|
474 |
poll: &Poll, |
|
475 |
client_id: ClientId, |
|
476 |
error: &Error, |
|
477 |
msg: &str, |
|
478 |
) -> io::Result<()> { |
|
13414 | 479 |
let addr = if let Some(ref mut client) = self.clients.get_mut(client_id) { |
480 |
client.peer_addr |
|
481 |
} else { |
|
482 |
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0) |
|
483 |
}; |
|
484 |
debug!("{}({}): {}", msg, addr, error); |
|
485 |
self.client_error(poll, client_id) |
|
13119 | 486 |
} |
487 |
||
14457 | 488 |
pub fn client_readable(&mut self, poll: &Poll, client_id: ClientId) -> io::Result<()> { |
489 |
let messages = if let Some(ref mut client) = self.clients.get_mut(client_id) { |
|
490 |
client.read() |
|
491 |
} else { |
|
492 |
warn!("invalid readable client: {}", client_id); |
|
493 |
Ok((Vec::new(), NetworkClientState::Idle)) |
|
494 |
}; |
|
13414 | 495 |
|
14671
455865ccd36c
Server action refactoring part 2 of N
alfadur <mail@none>
parents:
14457
diff
changeset
|
496 |
let mut response = handlers::Response::new(client_id); |
455865ccd36c
Server action refactoring part 2 of N
alfadur <mail@none>
parents:
14457
diff
changeset
|
497 |
|
13414 | 498 |
match messages { |
499 |
Ok((messages, state)) => { |
|
500 |
for message in messages { |
|
14671
455865ccd36c
Server action refactoring part 2 of N
alfadur <mail@none>
parents:
14457
diff
changeset
|
501 |
debug!("Handling message {:?} for client {}", message, client_id); |
455865ccd36c
Server action refactoring part 2 of N
alfadur <mail@none>
parents:
14457
diff
changeset
|
502 |
if self.server.clients.contains(client_id) { |
455865ccd36c
Server action refactoring part 2 of N
alfadur <mail@none>
parents:
14457
diff
changeset
|
503 |
handlers::handle(&mut self.server, client_id, &mut response, message); |
455865ccd36c
Server action refactoring part 2 of N
alfadur <mail@none>
parents:
14457
diff
changeset
|
504 |
} |
13414 | 505 |
} |
506 |
match state { |
|
13415 | 507 |
NetworkClientState::NeedsRead => { |
508 |
self.pending.insert((client_id, state)); |
|
14457 | 509 |
} |
510 |
NetworkClientState::Closed => self.client_error(&poll, client_id)?, |
|
13414 | 511 |
_ => {} |
512 |
}; |
|
13119 | 513 |
} |
13414 | 514 |
Err(e) => self.operation_failed( |
14457 | 515 |
poll, |
516 |
client_id, |
|
517 |
&e, |
|
518 |
"Error while reading from client socket", |
|
519 |
)?, |
|
13119 | 520 |
} |
521 |
||
14672
6e6632068a33
Server action refactoring part 3 of N
alfadur <mail@none>
parents:
14671
diff
changeset
|
522 |
if !response.is_empty() { |
14779
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
523 |
self.handle_response(response, poll); |
13119 | 524 |
} |
525 |
||
526 |
Ok(()) |
|
527 |
} |
|
528 |
||
14457 | 529 |
pub fn client_writable(&mut self, poll: &Poll, client_id: ClientId) -> io::Result<()> { |
530 |
let result = if let Some(ref mut client) = self.clients.get_mut(client_id) { |
|
531 |
client.write() |
|
532 |
} else { |
|
533 |
warn!("invalid writable client: {}", client_id); |
|
534 |
Ok(((), NetworkClientState::Idle)) |
|
535 |
}; |
|
13414 | 536 |
|
537 |
match result { |
|
13415 | 538 |
Ok(((), state)) if state == NetworkClientState::NeedsWrite => { |
539 |
self.pending.insert((client_id, state)); |
|
14457 | 540 |
} |
13415 | 541 |
Ok(_) => {} |
14457 | 542 |
Err(e) => { |
543 |
self.operation_failed(poll, client_id, &e, "Error while writing to client socket")? |
|
544 |
} |
|
13119 | 545 |
} |
546 |
||
547 |
Ok(()) |
|
548 |
} |
|
549 |
||
14457 | 550 |
pub fn client_error(&mut self, poll: &Poll, client_id: ClientId) -> io::Result<()> { |
13119 | 551 |
self.deregister_client(poll, client_id); |
14673
08a8605bafaf
Server action refactoring part 4 of N
alfadur <mail@none>
parents:
14672
diff
changeset
|
552 |
let mut response = handlers::Response::new(client_id); |
08a8605bafaf
Server action refactoring part 4 of N
alfadur <mail@none>
parents:
14672
diff
changeset
|
553 |
handlers::handle_client_loss(&mut self.server, client_id, &mut response); |
14779
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14697
diff
changeset
|
554 |
self.handle_response(response, poll); |
13119 | 555 |
|
556 |
Ok(()) |
|
557 |
} |
|
13414 | 558 |
|
559 |
pub fn has_pending_operations(&self) -> bool { |
|
560 |
!self.pending.is_empty() |
|
561 |
} |
|
562 |
||
563 |
pub fn on_idle(&mut self, poll: &Poll) -> io::Result<()> { |
|
13415 | 564 |
if self.has_pending_operations() { |
13478 | 565 |
let mut cache = replace(&mut self.pending_cache, Vec::new()); |
13415 | 566 |
cache.extend(self.pending.drain()); |
567 |
for (id, state) in cache.drain(..) { |
|
568 |
match state { |
|
14457 | 569 |
NetworkClientState::NeedsRead => self.client_readable(poll, id)?, |
570 |
NetworkClientState::NeedsWrite => self.client_writable(poll, id)?, |
|
13415 | 571 |
_ => {} |
572 |
} |
|
13414 | 573 |
} |
13415 | 574 |
swap(&mut cache, &mut self.pending_cache); |
13414 | 575 |
} |
576 |
Ok(()) |
|
577 |
} |
|
13119 | 578 |
} |