improve network error handling
This commit is contained in:
parent
62bc447f71
commit
1add8b500a
@ -5,13 +5,38 @@ use async_std::io::prelude::{ReadExt, WriteExt};
|
|||||||
use async_std::prelude::{StreamExt};
|
use async_std::prelude::{StreamExt};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use libpso::crypto::{PSOCipher, NullCipher};
|
use libpso::crypto::{PSOCipher, NullCipher, CipherError};
|
||||||
|
use libpso::PacketParseError;
|
||||||
use crate::common::serverstate::ClientId;
|
use crate::common::serverstate::ClientId;
|
||||||
use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect};
|
use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect};
|
||||||
|
|
||||||
|
|
||||||
enum PacketReceiverError {
|
#[derive(Debug)]
|
||||||
ClientDisconnect,
|
pub enum NetworkError {
|
||||||
|
CouldNotSend,
|
||||||
|
CipherError(CipherError),
|
||||||
|
PacketParseError(PacketParseError),
|
||||||
|
IOError(std::io::Error),
|
||||||
|
DataNotReady,
|
||||||
|
ClientDisconnected,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CipherError> for NetworkError {
|
||||||
|
fn from(err: CipherError) -> NetworkError {
|
||||||
|
NetworkError::CipherError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for NetworkError {
|
||||||
|
fn from(err: std::io::Error) -> NetworkError {
|
||||||
|
NetworkError::IOError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PacketParseError> for NetworkError {
|
||||||
|
fn from(err: PacketParseError) -> NetworkError {
|
||||||
|
NetworkError::PacketParseError(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PacketReceiver {
|
struct PacketReceiver {
|
||||||
@ -31,13 +56,13 @@ impl PacketReceiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fill_recv_buffer(&mut self) -> Result<(), PacketReceiverError>{
|
async fn fill_recv_buffer(&mut self) -> Result<(), NetworkError> {
|
||||||
let mut data = [0u8; 0x8000];
|
let mut data = [0u8; 0x8000];
|
||||||
|
|
||||||
let mut socket = &*self.socket;
|
let mut socket = &*self.socket;
|
||||||
let len = socket.read(&mut data).await.unwrap();
|
let len = socket.read(&mut data).await?;
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Err(PacketReceiverError::ClientDisconnect);
|
return Err(NetworkError::ClientDisconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.recv_buffer.extend_from_slice(&mut data[..len]);
|
self.recv_buffer.extend_from_slice(&mut data[..len]);
|
||||||
@ -46,14 +71,14 @@ impl PacketReceiver {
|
|||||||
let mut cipher = self.cipher.lock().await;
|
let mut cipher = self.cipher.lock().await;
|
||||||
let block_chunk_len = self.recv_buffer.len() / cipher.block_size() * cipher.block_size();
|
let block_chunk_len = self.recv_buffer.len() / cipher.block_size() * cipher.block_size();
|
||||||
let buf = self.recv_buffer.drain(..block_chunk_len).collect();
|
let buf = self.recv_buffer.drain(..block_chunk_len).collect();
|
||||||
cipher.decrypt(&buf).unwrap()
|
cipher.decrypt(&buf)?
|
||||||
};
|
};
|
||||||
self.incoming_data.append(&mut dec_buf);
|
self.incoming_data.append(&mut dec_buf);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn recv_pkts<R: RecvServerPacket + Send + std::fmt::Debug>(&mut self) -> Result<Vec<R>, PacketReceiverError> {
|
async fn recv_pkts<R: RecvServerPacket + Send + std::fmt::Debug>(&mut self) -> Result<Vec<R>, NetworkError> {
|
||||||
self.fill_recv_buffer().await?;
|
self.fill_recv_buffer().await?;
|
||||||
|
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
@ -89,12 +114,15 @@ impl PacketReceiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_pkt<S: SendServerPacket + Send + std::fmt::Debug>(socket: Arc<async_std::net::TcpStream>, cipher: Arc<Mutex<Box<dyn PSOCipher + Send>>>, pkt: S) {
|
async fn send_pkt<S: SendServerPacket + Send + std::fmt::Debug>(socket: Arc<async_std::net::TcpStream>,
|
||||||
|
cipher: Arc<Mutex<Box<dyn PSOCipher + Send>>>, pkt: S)
|
||||||
|
-> Result<(), NetworkError>
|
||||||
|
{
|
||||||
let buf = pkt.as_bytes();
|
let buf = pkt.as_bytes();
|
||||||
let cbuf = cipher.lock().await.encrypt(&buf).unwrap();
|
let cbuf = cipher.lock().await.encrypt(&buf)?;
|
||||||
let mut ssock = &*socket;
|
let mut ssock = &*socket;
|
||||||
ssock.write_all(&cbuf).await;
|
ssock.write_all(&cbuf).await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -118,7 +146,7 @@ async fn server_state_loop<STATE, S, R, E>(mut state: STATE,
|
|||||||
E: std::fmt::Debug + Send,
|
E: std::fmt::Debug + Send,
|
||||||
{
|
{
|
||||||
async_std::task::spawn(async move {
|
async_std::task::spawn(async move {
|
||||||
let mut clients = HashMap::new();
|
let mut clients = HashMap::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let action = server_state_receiver.recv().await.unwrap();
|
let action = server_state_receiver.recv().await.unwrap();
|
||||||
@ -138,22 +166,31 @@ async fn server_state_loop<STATE, S, R, E>(mut state: STATE,
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
ClientAction::Packet(client_id, pkt) => {
|
ClientAction::Packet(client_id, pkt) => {
|
||||||
let k = state.handle(client_id, &pkt);
|
let pkts = state.handle(client_id, &pkt);
|
||||||
let pkts = k.unwrap().collect::<Vec<_>>();
|
match pkts {
|
||||||
for (client_id, pkt) in pkts {
|
Ok(pkts) => {
|
||||||
let client = clients.get_mut(&client_id).unwrap();
|
for (client_id, pkt) in pkts {
|
||||||
client.send(ServerStateAction::Packet(pkt)).await;
|
if let Some(client) = clients.get_mut(&client_id) {
|
||||||
|
client.send(ServerStateAction::Packet(pkt)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
warn!("[client {:?} state handler error] {:?}", client_id, err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ClientAction::Disconnect(client_id) => {
|
ClientAction::Disconnect(client_id) => {
|
||||||
let pkts = state.on_disconnect(client_id);
|
let pkts = state.on_disconnect(client_id);
|
||||||
for (client_id, pkt) in pkts {
|
for (client_id, pkt) in pkts {
|
||||||
let client = clients.get_mut(&client_id).unwrap();
|
if let Some(client) = clients.get_mut(&client_id) {
|
||||||
client.send(ServerStateAction::Packet(pkt)).await;
|
client.send(ServerStateAction::Packet(pkt)).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let client = clients.remove(&client_id).unwrap();
|
if let Some(client) = clients.get_mut(&client_id) {
|
||||||
client.send(ServerStateAction::Disconnect).await;
|
client.send(ServerStateAction::Disconnect).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,11 +219,14 @@ async fn client_recv_loop<S, R>(client_id: ClientId,
|
|||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
match err {
|
match err {
|
||||||
PacketReceiverError::ClientDisconnect => {
|
NetworkError::ClientDisconnected => {
|
||||||
trace!("[client disconnected] {:?}", client_id);
|
trace!("[client disconnected] {:?}", client_id);
|
||||||
server_sender.send(ClientAction::Disconnect(client_id));
|
server_sender.send(ClientAction::Disconnect(client_id));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
warn!("[client {:?} recv error] {:?}", client_id, err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,7 +253,9 @@ async fn client_send_loop<S>(client_id: ClientId,
|
|||||||
}
|
}
|
||||||
ServerStateAction::Packet(pkt) => {
|
ServerStateAction::Packet(pkt) => {
|
||||||
trace!("[send to {:?}] {:?}", client_id, pkt);
|
trace!("[send to {:?}] {:?}", client_id, pkt);
|
||||||
send_pkt(socket.clone(), cipher_out.clone(), pkt).await
|
if let Err(err) = send_pkt(socket.clone(), cipher_out.clone(), pkt).await {
|
||||||
|
warn!("[client {:?} send error ] {:?}", client_id, err);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ServerStateAction::Disconnect => {
|
ServerStateAction::Disconnect => {
|
||||||
break;
|
break;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
pub mod cipherkeys;
|
pub mod cipherkeys;
|
||||||
pub mod network;
|
|
||||||
pub mod serverstate;
|
pub mod serverstate;
|
||||||
pub mod mainloop;
|
pub mod mainloop;
|
||||||
pub mod leveltable;
|
pub mod leveltable;
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
use std::io::{Read};
|
|
||||||
use log::trace;
|
|
||||||
|
|
||||||
use libpso::crypto::{PSOCipher, CipherError};
|
|
||||||
use libpso::PacketParseError;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum PacketNetworkError {
|
|
||||||
CouldNotSend,
|
|
||||||
CipherError(CipherError),
|
|
||||||
PacketParseError(PacketParseError),
|
|
||||||
IOError(std::io::Error),
|
|
||||||
DataNotReady,
|
|
||||||
ClientDisconnected,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<CipherError> for PacketNetworkError {
|
|
||||||
fn from(err: CipherError) -> PacketNetworkError {
|
|
||||||
PacketNetworkError::CipherError(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<std::io::Error> for PacketNetworkError {
|
|
||||||
fn from(err: std::io::Error) -> PacketNetworkError {
|
|
||||||
PacketNetworkError::IOError(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<PacketParseError> for PacketNetworkError {
|
|
||||||
fn from(err: PacketParseError) -> PacketNetworkError {
|
|
||||||
PacketNetworkError::PacketParseError(err)
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,18 +11,18 @@ use libpso::crypto::pc::PSOPCCipher;
|
|||||||
use ron::de::from_str;
|
use ron::de::from_str;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::common::network::{PacketNetworkError};
|
use crate::common::mainloop::{NetworkError};
|
||||||
use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect, ClientId};
|
use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect, ClientId};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum PatchError {
|
pub enum PatchError {
|
||||||
PacketNetworkError(PacketNetworkError),
|
NetworkError(NetworkError),
|
||||||
IOError(std::io::Error),
|
IOError(std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PacketNetworkError> for PatchError {
|
impl From<NetworkError> for PatchError {
|
||||||
fn from(err: PacketNetworkError) -> PatchError {
|
fn from(err: NetworkError) -> PatchError {
|
||||||
PatchError::PacketNetworkError(err)
|
PatchError::NetworkError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user