move the anteroom out of the server
authoralfadur <mail@none>
Mon, 23 Dec 2019 18:08:55 +0300
changeset 15520 fd3a20e9d095
parent 15519 b3157d218ae2
child 15521 1fcce8feace4
move the anteroom out of the server
rust/hedgewars-server/src/core.rs
rust/hedgewars-server/src/core/server.rs
rust/hedgewars-server/src/handlers.rs
rust/hedgewars-server/src/handlers/inanteroom.rs
rust/hedgewars-server/src/server/network.rs
--- a/rust/hedgewars-server/src/core.rs	Sat Dec 21 23:33:50 2019 +0300
+++ b/rust/hedgewars-server/src/core.rs	Mon Dec 23 18:08:55 2019 +0300
@@ -1,3 +1,4 @@
+pub mod anteroom;
 pub mod client;
 pub mod indexslab;
 pub mod room;
--- a/rust/hedgewars-server/src/core/server.rs	Sat Dec 21 23:33:50 2019 +0300
+++ b/rust/hedgewars-server/src/core/server.rs	Mon Dec 23 18:08:55 2019 +0300
@@ -1,4 +1,5 @@
 use super::{
+    anteroom::HwAnteroomClient,
     client::HwClient,
     indexslab::IndexSlab,
     room::HwRoom,
@@ -8,10 +9,9 @@
 
 use bitflags::_core::hint::unreachable_unchecked;
 use bitflags::*;
-use chrono::{offset, DateTime};
 use log::*;
 use slab::Slab;
-use std::{borrow::BorrowMut, collections::HashSet, iter, mem::replace, num::NonZeroU16};
+use std::{borrow::BorrowMut, collections::HashSet, iter, mem::replace};
 
 #[derive(Debug)]
 pub enum CreateRoomError {
@@ -106,91 +106,6 @@
 #[derive(Debug)]
 pub struct AccessError();
 
-pub struct HwAnteClient {
-    pub nick: Option<String>,
-    pub protocol_number: Option<NonZeroU16>,
-    pub server_salt: String,
-    pub is_checker: bool,
-    pub is_local_admin: bool,
-    pub is_registered: bool,
-    pub is_admin: bool,
-    pub is_contributor: bool,
-}
-
-struct Ipv4AddrRange {
-    min: [u8; 4],
-    max: [u8; 4],
-}
-
-impl Ipv4AddrRange {
-    fn contains(&self, addr: [u8; 4]) -> bool {
-        (0..4).all(|i| self.min[i] <= addr[i] && addr[i] <= self.max[i])
-    }
-}
-
-struct BanCollection {
-    ban_ips: Vec<Ipv4AddrRange>,
-    ban_timeouts: Vec<DateTime<offset::Utc>>,
-    ban_reasons: Vec<String>,
-}
-
-impl BanCollection {
-    fn new() -> Self {
-        Self {
-            ban_ips: vec![],
-            ban_timeouts: vec![],
-            ban_reasons: vec![],
-        }
-    }
-
-    fn find(&self, addr: [u8; 4]) -> Option<String> {
-        let time = offset::Utc::now();
-        self.ban_ips
-            .iter()
-            .enumerate()
-            .find(|(i, r)| r.contains(addr) && time < self.ban_timeouts[*i])
-            .map(|(i, _)| self.ban_reasons[i].clone())
-    }
-}
-
-pub struct HwAnteroom {
-    pub clients: IndexSlab<HwAnteClient>,
-    bans: BanCollection,
-}
-
-impl HwAnteroom {
-    pub fn new(clients_limit: usize) -> Self {
-        let clients = IndexSlab::with_capacity(clients_limit);
-        HwAnteroom {
-            clients,
-            bans: BanCollection::new(),
-        }
-    }
-
-    pub fn find_ip_ban(&self, addr: [u8; 4]) -> Option<String> {
-        self.bans.find(addr)
-    }
-
-    pub fn add_client(&mut self, client_id: ClientId, salt: String, is_local_admin: bool) {
-        let client = HwAnteClient {
-            nick: None,
-            protocol_number: None,
-            server_salt: salt,
-            is_checker: false,
-            is_local_admin,
-            is_registered: false,
-            is_admin: false,
-            is_contributor: false,
-        };
-        self.clients.insert(client_id, client);
-    }
-
-    pub fn remove_client(&mut self, client_id: ClientId) -> Option<HwAnteClient> {
-        let client = self.clients.remove(client_id);
-        client
-    }
-}
-
 pub struct ServerGreetings {
     pub for_latest_protocol: String,
     pub for_old_protocols: String,
@@ -212,9 +127,8 @@
 }
 
 pub struct HwServer {
-    pub clients: IndexSlab<HwClient>,
+    clients: IndexSlab<HwClient>,
     pub rooms: Slab<HwRoom>,
-    pub anteroom: HwAnteroom,
     pub latest_protocol: u16,
     pub flags: ServerFlags,
     pub greetings: ServerGreetings,
@@ -227,7 +141,6 @@
         Self {
             clients,
             rooms,
-            anteroom: HwAnteroom::new(clients_limit),
             greetings: ServerGreetings::new(),
             latest_protocol: 58,
             flags: ServerFlags::empty(),
@@ -286,7 +199,7 @@
             .unwrap_or(false)
     }
 
-    pub fn add_client(&mut self, client_id: ClientId, data: HwAnteClient) {
+    pub fn add_client(&mut self, client_id: ClientId, data: HwAnteroomClient) {
         if let (Some(protocol), Some(nick)) = (data.protocol_number, data.nick) {
             let mut client = HwClient::new(client_id, protocol.get(), nick);
             client.set_is_checker(data.is_checker);
--- a/rust/hedgewars-server/src/handlers.rs	Sat Dec 21 23:33:50 2019 +0300
+++ b/rust/hedgewars-server/src/handlers.rs	Mon Dec 23 18:08:55 2019 +0300
@@ -12,6 +12,7 @@
 };
 use crate::{
     core::{
+        anteroom::HwAnteroom,
         room::RoomSave,
         server::HwServer,
         types::{ClientId, GameCfg, Replay, RoomId, TeamInfo},
@@ -81,6 +82,20 @@
     }
 }
 
+pub struct ServerState {
+    pub server: HwServer,
+    pub anteroom: HwAnteroom,
+}
+
+impl ServerState {
+    pub fn new(clients_limit: usize, rooms_limit: usize) -> Self {
+        Self {
+            server: HwServer::new(clients_limit, rooms_limit),
+            anteroom: HwAnteroom::new(clients_limit),
+        }
+    }
+}
+
 #[derive(Debug)]
 pub struct AccountInfo {
     pub is_registered: bool,
@@ -236,7 +251,7 @@
 }
 
 pub fn handle(
-    server: &mut HwServer,
+    state: &mut ServerState,
     client_id: ClientId,
     response: &mut Response,
     message: HwProtocolMessage,
@@ -245,35 +260,39 @@
         HwProtocolMessage::Ping => response.add(Pong.send_self()),
         HwProtocolMessage::Pong => (),
         _ => {
-            if server.anteroom.clients.contains(client_id) {
-                match inanteroom::handle(server, client_id, response, message) {
+            if state.anteroom.clients.contains(client_id) {
+                match inanteroom::handle(state, client_id, response, message) {
                     LoginResult::Unchanged => (),
                     LoginResult::Complete => {
-                        if let Some(client) = server.anteroom.remove_client(client_id) {
-                            server.add_client(client_id, client);
-                            common::get_lobby_join_data(server, response);
+                        if let Some(client) = state.anteroom.remove_client(client_id) {
+                            state.server.add_client(client_id, client);
+                            common::get_lobby_join_data(&state.server, response);
                         }
                     }
                     LoginResult::Exit => {
-                        server.anteroom.remove_client(client_id);
+                        state.anteroom.remove_client(client_id);
                         response.remove_client(client_id);
                     }
                 }
-            } else if server.has_client(client_id) {
+            } else if state.server.has_client(client_id) {
                 match message {
                     HwProtocolMessage::Quit(Some(msg)) => {
-                        common::remove_client(server, response, "User quit: ".to_string() + &msg);
+                        common::remove_client(
+                            &mut state.server,
+                            response,
+                            "User quit: ".to_string() + &msg,
+                        );
                     }
                     HwProtocolMessage::Quit(None) => {
-                        common::remove_client(server, response, "User quit".to_string());
+                        common::remove_client(&mut state.server, response, "User quit".to_string());
                     }
                     HwProtocolMessage::Info(nick) => {
-                        if let Some(client) = server.find_client(&nick) {
+                        if let Some(client) = state.server.find_client(&nick) {
                             let admin_sign = if client.is_admin() { "@" } else { "" };
                             let master_sign = if client.is_master() { "+" } else { "" };
                             let room_info = match client.room_id {
                                 Some(room_id) => {
-                                    let room = server.room(room_id);
+                                    let room = state.server.room(room_id);
                                     let status = match room.game_info {
                                         Some(_) if client.teams_in_game == 0 => "(spectating)",
                                         Some(_) => "(playing)",
@@ -299,11 +318,13 @@
                         }
                     }
                     HwProtocolMessage::ToggleServerRegisteredOnly => {
-                        if !server.is_admin(client_id) {
+                        if !state.server.is_admin(client_id) {
                             response.warn(ACCESS_DENIED);
                         } else {
-                            server.set_is_registered_only(!server.is_registered_only());
-                            let msg = if server.is_registered_only() {
+                            state
+                                .server
+                                .set_is_registered_only(!state.server.is_registered_only());
+                            let msg = if state.server.is_registered_only() {
                                 REGISTERED_ONLY_ENABLED
                             } else {
                                 REGISTERED_ONLY_DISABLED
@@ -312,14 +333,14 @@
                         }
                     }
                     HwProtocolMessage::Global(msg) => {
-                        if !server.is_admin(client_id) {
+                        if !state.server.is_admin(client_id) {
                             response.warn(ACCESS_DENIED);
                         } else {
                             response.add(global_chat(msg).send_all())
                         }
                     }
                     HwProtocolMessage::SuperPower => {
-                        if server.enable_super_power(client_id) {
+                        if state.server.enable_super_power(client_id) {
                             response.add(server_chat(SUPER_POWER.to_string()).send_self())
                         } else {
                             response.warn(ACCESS_DENIED);
@@ -336,10 +357,10 @@
                             response.warn(REPLAY_NOT_SUPPORTED);
                         }
                     }
-                    _ => match server.client(client_id).room_id {
-                        None => inlobby::handle(server, client_id, response, message),
+                    _ => match state.server.client(client_id).room_id {
+                        None => inlobby::handle(&mut state.server, client_id, response, message),
                         Some(room_id) => {
-                            inroom::handle(server, client_id, response, room_id, message)
+                            inroom::handle(&mut state.server, client_id, response, room_id, message)
                         }
                     },
                 }
@@ -349,7 +370,7 @@
 }
 
 pub fn handle_client_accept(
-    server: &mut HwServer,
+    state: &mut ServerState,
     client_id: ClientId,
     response: &mut Response,
     addr: [u8; 4],
@@ -357,7 +378,7 @@
 ) {
     let ban_reason = Some(addr)
         .filter(|_| !is_local)
-        .and_then(|a| server.anteroom.find_ip_ban(a));
+        .and_then(|a| state.anteroom.find_ip_ban(a));
     if let Some(reason) = ban_reason {
         response.add(HwServerMessage::Bye(reason).send_self());
         response.remove_client(client_id);
@@ -365,7 +386,7 @@
         let mut salt = [0u8; 18];
         thread_rng().fill_bytes(&mut salt);
 
-        server
+        state
             .anteroom
             .add_client(client_id, encode(&salt), is_local);
 
@@ -373,39 +394,39 @@
     }
 }
 
-pub fn handle_client_loss(server: &mut HwServer, client_id: ClientId, response: &mut Response) {
-    if server.anteroom.remove_client(client_id).is_none() {
-        common::remove_client(server, response, "Connection reset".to_string());
+pub fn handle_client_loss(state: &mut ServerState, client_id: ClientId, response: &mut Response) {
+    if state.anteroom.remove_client(client_id).is_none() {
+        common::remove_client(&mut state.server, response, "Connection reset".to_string());
     }
 }
 
 pub fn handle_io_result(
-    server: &mut HwServer,
+    state: &mut ServerState,
     client_id: ClientId,
     response: &mut Response,
     io_result: IoResult,
 ) {
     match io_result {
         IoResult::AccountRegistered(is_registered) => {
-            if !is_registered && server.is_registered_only() {
+            if !is_registered && state.server.is_registered_only() {
                 response.add(Bye(REGISTRATION_REQUIRED.to_string()).send_self());
                 response.remove_client(client_id);
             } else if is_registered {
-                let salt = server.anteroom.clients[client_id].server_salt.clone();
+                let salt = state.anteroom.clients[client_id].server_salt.clone();
                 response.add(AskPassword(salt).send_self());
-            } else if let Some(client) = server.anteroom.remove_client(client_id) {
-                server.add_client(client_id, client);
-                common::get_lobby_join_data(server, response);
+            } else if let Some(client) = state.anteroom.remove_client(client_id) {
+                state.server.add_client(client_id, client);
+                common::get_lobby_join_data(&state.server, response);
             }
         }
         IoResult::Account(Some(info)) => {
             response.add(ServerAuth(format!("{:x}", info.server_hash)).send_self());
-            if let Some(mut client) = server.anteroom.remove_client(client_id) {
+            if let Some(mut client) = state.anteroom.remove_client(client_id) {
                 client.is_registered = info.is_registered;
                 client.is_admin = info.is_admin;
                 client.is_contributor = info.is_contributor;
-                server.add_client(client_id, client);
-                common::get_lobby_join_data(server, response);
+                state.server.add_client(client_id, client);
+                common::get_lobby_join_data(&state.server, response);
             }
         }
         IoResult::Account(None) => {
@@ -413,7 +434,7 @@
             response.remove_client(client_id);
         }
         IoResult::Replay(Some(replay)) => {
-            let client = server.client(client_id);
+            let client = state.server.client(client_id);
             let protocol = client.protocol_number;
             let start_msg = if protocol < 58 {
                 RoomJoined(vec![client.nick.clone()])
@@ -441,7 +462,7 @@
             response.warn(ROOM_CONFIG_SAVE_FAILED);
         }
         IoResult::LoadRoom(room_id, Some(contents)) => {
-            if let Some(ref mut room) = server.rooms.get_mut(room_id) {
+            if let Some(ref mut room) = state.server.rooms.get_mut(room_id) {
                 match room.set_saves(&contents) {
                     Ok(_) => response.add(server_chat(ROOM_CONFIG_LOADED.to_string()).send_self()),
                     Err(e) => {
--- a/rust/hedgewars-server/src/handlers/inanteroom.rs	Sat Dec 21 23:33:50 2019 +0300
+++ b/rust/hedgewars-server/src/handlers/inanteroom.rs	Mon Dec 23 18:08:55 2019 +0300
@@ -2,8 +2,9 @@
 
 use crate::{
     core::{
+        anteroom::{HwAnteroom, HwAnteroomClient},
         client::HwClient,
-        server::{HwAnteClient, HwAnteroom, HwServer},
+        server::HwServer,
         types::ClientId,
     },
     protocol::messages::{HwProtocolMessage, HwProtocolMessage::LoadRoom, HwServerMessage::*},
@@ -26,14 +27,14 @@
 
 fn completion_result<'a, I>(
     mut other_clients: I,
-    client: &mut HwAnteClient,
+    client: &mut HwAnteroomClient,
     response: &mut super::Response,
 ) -> LoginResult
 where
-    I: Iterator<Item = (ClientId, &'a HwClient)>,
+    I: Iterator<Item = &'a HwClient>,
 {
     let has_nick_clash =
-        other_clients.any(|(_, c)| !c.is_checker() && c.nick == *client.nick.as_ref().unwrap());
+        other_clients.any(|c| !c.is_checker() && c.nick == *client.nick.as_ref().unwrap());
 
     if has_nick_clash {
         if client.protocol_number.unwrap().get() < 38 {
@@ -61,7 +62,7 @@
 }
 
 pub fn handle(
-    server: &mut HwServer,
+    server_state: &mut super::ServerState,
     client_id: ClientId,
     response: &mut super::Response,
     message: HwProtocolMessage,
@@ -72,7 +73,7 @@
             LoginResult::Exit
         }
         HwProtocolMessage::Nick(nick) => {
-            let client = &mut server.anteroom.clients[client_id];
+            let client = &mut server_state.anteroom.clients[client_id];
 
             if client.nick.is_some() {
                 response.add(Error("Nickname already provided.".to_string()).send_self());
@@ -85,14 +86,14 @@
                 response.add(Nick(nick).send_self());
 
                 if client.protocol_number.is_some() {
-                    completion_result(server.clients.iter(), client, response)
+                    completion_result(server_state.server.iter_clients(), client, response)
                 } else {
                     LoginResult::Unchanged
                 }
             }
         }
         HwProtocolMessage::Proto(proto) => {
-            let client = &mut server.anteroom.clients[client_id];
+            let client = &mut server_state.anteroom.clients[client_id];
             if client.protocol_number.is_some() {
                 response.add(Error("Protocol already known.".to_string()).send_self());
                 LoginResult::Unchanged
@@ -104,7 +105,7 @@
                 response.add(Proto(proto).send_self());
 
                 if client.nick.is_some() {
-                    completion_result(server.clients.iter(), client, response)
+                    completion_result(server_state.server.iter_clients(), client, response)
                 } else {
                     LoginResult::Unchanged
                 }
@@ -112,7 +113,7 @@
         }
         #[cfg(feature = "official-server")]
         HwProtocolMessage::Password(hash, salt) => {
-            let client = &server.anteroom.clients[client_id];
+            let client = &server_state.anteroom.clients[client_id];
 
             if let (Some(nick), Some(protocol)) = (client.nick.as_ref(), client.protocol_number) {
                 response.request_io(super::IoTask::GetAccount {
@@ -128,7 +129,7 @@
         }
         #[cfg(feature = "official-server")]
         HwProtocolMessage::Checker(protocol, nick, password) => {
-            let client = &mut server.anteroom.clients[client_id];
+            let client = &mut server_state.anteroom.clients[client_id];
             if protocol == 0 {
                 response.add(Error("Bad number.".to_string()).send_self());
                 LoginResult::Unchanged
--- a/rust/hedgewars-server/src/server/network.rs	Sat Dec 21 23:33:50 2019 +0300
+++ b/rust/hedgewars-server/src/server/network.rs	Mon Dec 23 18:08:55 2019 +0300
@@ -18,9 +18,9 @@
 use slab::Slab;
 
 use crate::{
-    core::{server::HwServer, types::ClientId},
+    core::types::ClientId,
     handlers,
-    handlers::{IoResult, IoTask},
+    handlers::{IoResult, IoTask, ServerState},
     protocol::{messages::HwServerMessage::Redirect, messages::*, ProtocolDecoder},
     utils,
 };
@@ -317,7 +317,7 @@
 
 pub struct NetworkLayer {
     listener: TcpListener,
-    server: HwServer,
+    server_state: ServerState,
     clients: Slab<NetworkClient>,
     pending: HashSet<(ClientId, NetworkClientState)>,
     pending_cache: Vec<(ClientId, NetworkClientState)>,
@@ -425,7 +425,7 @@
         }
 
         debug!("{} pending server messages", response.len());
-        let output = response.extract_messages(&mut self.server);
+        let output = response.extract_messages(&mut self.server_state.server);
         for (clients, message) in output {
             debug!("Message {:?} to {:?}", message, clients);
             let msg_string = message.to_raw_protocol();
@@ -525,7 +525,7 @@
 
         if let IpAddr::V4(addr) = self.clients[client_id].peer_addr.ip() {
             handlers::handle_client_accept(
-                &mut self.server,
+                &mut self.server_state,
                 client_id,
                 &mut response,
                 addr.octets(),
@@ -594,7 +594,7 @@
             Ok((messages, state)) => {
                 for message in messages {
                     debug!("Handling message {:?} for client {}", message, client_id);
-                    handlers::handle(&mut self.server, client_id, &mut response, message);
+                    handlers::handle(&mut self.server_state, client_id, &mut response, message);
                 }
                 match state {
                     NetworkClientState::NeedsRead => {
@@ -649,7 +649,7 @@
 
         if !pending_close {
             let mut response = handlers::Response::new(client_id);
-            handlers::handle_client_loss(&mut self.server, client_id, &mut response);
+            handlers::handle_client_loss(&mut self.server_state, client_id, &mut response);
             self.handle_response(response, poll);
         }
 
@@ -730,7 +730,8 @@
     }
 
     pub fn build(self) -> NetworkLayer {
-        let server = HwServer::new(self.clients_capacity, self.rooms_capacity);
+        let server_state = ServerState::new(self.clients_capacity, self.rooms_capacity);
+
         let clients = Slab::with_capacity(self.clients_capacity);
         let pending = HashSet::with_capacity(2 * self.clients_capacity);
         let pending_cache = Vec::with_capacity(2 * self.clients_capacity);
@@ -738,7 +739,7 @@
 
         NetworkLayer {
             listener: self.listener.expect("No listener provided"),
-            server,
+            server_state,
             clients,
             pending,
             pending_cache,