rust/hedgewars-server/src/protocol.rs
author alfadur
Mon, 25 Mar 2024 16:05:11 +0300
changeset 16029 d9f1b239b6d7
parent 16028 d73e6cb37f83
permissions -rw-r--r--
fix rejoining
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
15853
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
     1
use bytes::{Buf, BufMut, BytesMut};
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
     2
use log::*;
15854
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
     3
use std::{
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
     4
    error::Error,
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
     5
    fmt::{Debug, Display, Formatter},
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
     6
    io,
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
     7
    io::ErrorKind,
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
     8
    marker::Unpin,
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
     9
    time::Duration,
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    10
};
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    11
use tokio::{io::AsyncReadExt, time::timeout};
15853
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    12
15854
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    13
use crate::protocol::ProtocolError::Timeout;
15826
747278149393 Extract network protocol into a separate crate
unc0rr
parents: 15817
diff changeset
    14
use hedgewars_network_protocol::{
747278149393 Extract network protocol into a separate crate
unc0rr
parents: 15817
diff changeset
    15
    messages::HwProtocolMessage,
15854
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    16
    parser::HwProtocolError,
15826
747278149393 Extract network protocol into a separate crate
unc0rr
parents: 15817
diff changeset
    17
    parser::{malformed_message, message},
747278149393 Extract network protocol into a separate crate
unc0rr
parents: 15817
diff changeset
    18
};
12129
07972a8c2433 - Start protocol parser implementation
unc0rr
parents:
diff changeset
    19
15854
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    20
#[derive(Debug)]
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    21
pub enum ProtocolError {
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    22
    Eof,
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    23
    Timeout,
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    24
    Network(Box<dyn Error + Send>),
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    25
}
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    26
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    27
impl Display for ProtocolError {
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    28
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    29
        match self {
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    30
            ProtocolError::Eof => write!(f, "Connection reset by peer"),
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    31
            ProtocolError::Timeout => write!(f, "Read operation timed out"),
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    32
            ProtocolError::Network(source) => write!(f, "{:?}", source),
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    33
        }
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    34
    }
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    35
}
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    36
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    37
impl Error for ProtocolError {
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    38
    fn source(&self) -> Option<&(dyn Error + 'static)> {
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    39
        if let Self::Network(source) = self {
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    40
            Some(source.as_ref())
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    41
        } else {
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    42
            None
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    43
        }
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    44
    }
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    45
}
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    46
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    47
pub type Result<T> = std::result::Result<T, ProtocolError>;
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    48
12136
e25a82ce2374 - Render messages to string
unc0rr
parents: 12133
diff changeset
    49
pub struct ProtocolDecoder {
15853
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    50
    buffer: BytesMut,
15854
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    51
    read_timeout: Duration,
14816
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    52
    is_recovering: bool,
12129
07972a8c2433 - Start protocol parser implementation
unc0rr
parents:
diff changeset
    53
}
07972a8c2433 - Start protocol parser implementation
unc0rr
parents:
diff changeset
    54
12136
e25a82ce2374 - Render messages to string
unc0rr
parents: 12133
diff changeset
    55
impl ProtocolDecoder {
15854
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    56
    pub fn new(read_timeout: Duration) -> ProtocolDecoder {
12136
e25a82ce2374 - Render messages to string
unc0rr
parents: 12133
diff changeset
    57
        ProtocolDecoder {
15853
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    58
            buffer: BytesMut::with_capacity(1024),
15854
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
    59
            read_timeout,
14816
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    60
            is_recovering: false,
12129
07972a8c2433 - Start protocol parser implementation
unc0rr
parents:
diff changeset
    61
        }
07972a8c2433 - Start protocol parser implementation
unc0rr
parents:
diff changeset
    62
    }
07972a8c2433 - Start protocol parser implementation
unc0rr
parents:
diff changeset
    63
14816
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    64
    fn recover(&mut self) -> bool {
15853
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    65
        self.is_recovering = match malformed_message(&self.buffer[..]) {
14816
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    66
            Ok((tail, ())) => {
15853
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    67
                let remaining = tail.len();
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    68
                self.buffer.advance(self.buffer.len() - remaining);
14816
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    69
                false
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    70
            }
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    71
            _ => {
15853
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    72
                self.buffer.clear();
14816
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    73
                true
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    74
            }
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    75
        };
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    76
        !self.is_recovering
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    77
    }
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    78
15853
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    79
    fn extract_message(&mut self) -> Option<HwProtocolMessage> {
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    80
        if !self.is_recovering || self.recover() {
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    81
            match message(&self.buffer[..]) {
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    82
                Ok((tail, message)) => {
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    83
                    let remaining = tail.len();
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    84
                    self.buffer.advance(self.buffer.len() - remaining);
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    85
                    return Some(message);
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    86
                }
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    87
                Err(nom::Err::Incomplete(_)) => {}
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    88
                Err(nom::Err::Failure(e) | nom::Err::Error(e)) => {
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    89
                    debug!("Invalid message: {:?}", e);
16029
d9f1b239b6d7 fix rejoining
alfadur
parents: 16028
diff changeset
    90
                    trace!(
d9f1b239b6d7 fix rejoining
alfadur
parents: 16028
diff changeset
    91
                        "Buffer content: {:?}",
d9f1b239b6d7 fix rejoining
alfadur
parents: 16028
diff changeset
    92
                        String::from_utf8_lossy(&self.buffer[..])
d9f1b239b6d7 fix rejoining
alfadur
parents: 16028
diff changeset
    93
                    );
15853
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    94
                    self.recover();
14816
add191d825f4 add parser error handling
alfadur
parents: 14796
diff changeset
    95
                }
14478
98ef2913ec73 Apply rustfmt to all files
unc0rr
parents: 14436
diff changeset
    96
            }
12136
e25a82ce2374 - Render messages to string
unc0rr
parents: 12133
diff changeset
    97
        }
15853
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    98
        None
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
    99
    }
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
   100
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
   101
    pub async fn read_from<R: AsyncReadExt + Unpin>(
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
   102
        &mut self,
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
   103
        stream: &mut R,
15854
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
   104
    ) -> Result<HwProtocolMessage> {
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
   105
        use ProtocolError::*;
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
   106
15853
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
   107
        loop {
16028
d73e6cb37f83 add some more buffer space
alfadur
parents: 16027
diff changeset
   108
            let remaining = self.buffer.capacity() - self.buffer.len();
d73e6cb37f83 add some more buffer space
alfadur
parents: 16027
diff changeset
   109
            if remaining < 1024 {
d73e6cb37f83 add some more buffer space
alfadur
parents: 16027
diff changeset
   110
                self.buffer.reserve(2048 - remaining);
16027
14fe5bfe9862 grow network buffer periodically
alfadur
parents: 16018
diff changeset
   111
            }
14fe5bfe9862 grow network buffer periodically
alfadur
parents: 16018
diff changeset
   112
14fe5bfe9862 grow network buffer periodically
alfadur
parents: 16018
diff changeset
   113
            if !self.buffer.has_remaining() || self.is_recovering {
16018
fb389df02e3e add some more todo!s
alfadur
parents: 15854
diff changeset
   114
                //todo!("ensure the buffer doesn't grow indefinitely")
15854
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
   115
                match timeout(self.read_timeout, stream.read_buf(&mut self.buffer)).await {
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
   116
                    Err(_) => return Err(Timeout),
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
   117
                    Ok(Err(e)) => return Err(Network(Box::new(e))),
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
   118
                    Ok(Ok(0)) => return Err(Eof),
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
   119
                    Ok(Ok(_)) => (),
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
   120
                };
15853
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
   121
            }
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
   122
            while !self.buffer.is_empty() {
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
   123
                if let Some(result) = self.extract_message() {
15854
a4d505a32879 add back client timeouts
alfadur
parents: 15853
diff changeset
   124
                    return Ok(result);
15853
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
   125
                }
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
   126
            }
7d0f747afcb8 move server network to tokio
alfadur
parents: 15826
diff changeset
   127
        }
12129
07972a8c2433 - Start protocol parser implementation
unc0rr
parents:
diff changeset
   128
    }
07972a8c2433 - Start protocol parser implementation
unc0rr
parents:
diff changeset
   129
}