connection_layer/
client_codec.rs

1use crate::client_to_host::{ClientToHostCommands, ConnectRequest};
2use crate::host_to_client::HostToClientCommands;
3use crate::{verify_hash, write_to_stream, ConnectionId, ConnectionSecretSeed, RequestId, Version};
4use datagram::{DatagramDecoder, DatagramEncoder};
5use flood_rs::in_stream::InOctetStream;
6use flood_rs::out_stream::OutOctetStream;
7use flood_rs::{Deserialize, ReadOctetStream, Serialize};
8use log::{debug, trace};
9use std::io;
10
11pub struct ConnectionInfo {
12    pub connection_id: ConnectionId,
13    pub seed: ConnectionSecretSeed,
14}
15
16
17pub struct ConnectionLayerClientCodec {
18    pub connection_info: Option<ConnectionInfo>,
19    pub request_id: RequestId,
20}
21
22impl ConnectionLayerClientCodec {
23    pub fn new(request_id: RequestId) -> Self {
24        Self {
25            connection_info: None,
26            request_id,
27        }
28    }
29}
30
31
32impl DatagramEncoder for ConnectionLayerClientCodec {
33    fn encode(&mut self, buf: &[u8]) -> io::Result<Vec<u8>> {
34        let mut stream = OutOctetStream::new();
35        match &self.connection_info {
36            None => {
37                ConnectionId { value: 0 }.to_stream(&mut stream)?;
38                let connect_request = ConnectRequest {
39                    request_id: self.request_id,
40                    version: Version { major: 0, minor: 2 },
41                };
42                debug!("client sending connect request {connect_request:?}");
43                ClientToHostCommands::Connect(connect_request).serialize(&mut stream)?;
44                trace!("send request {}", hexify::format_hex(stream.octets_ref()));
45            }
46            Some(connection_info) => {
47                trace!(
48                    "client sending payload connection_id: {} size: {}",
49                    connection_info.connection_id.value,
50                    buf.len()
51                );
52
53                write_to_stream(
54                    &mut stream,
55                    connection_info.connection_id,
56                    connection_info.seed,
57                    buf,
58                )?
59            }
60        }
61        flood_rs::WriteOctetStream::write(&mut stream, buf)?;
62
63        Ok(stream.octets().to_vec())
64    }
65}
66
67impl DatagramDecoder for ConnectionLayerClientCodec {
68    fn decode(&mut self, buf: &[u8]) -> io::Result<Vec<u8>> {
69        let mut in_stream = InOctetStream::new(buf);
70        let connection_id = ConnectionId::from_stream(&mut in_stream)?;
71
72        match &self.connection_info {
73            None => {
74                let command = HostToClientCommands::deserialize(&mut in_stream)?;
75                match command {
76                    HostToClientCommands::Connect(connect_response) => {
77                        debug!("client received connect response {connect_response:?}");
78                        self.connection_info = Some(ConnectionInfo {
79                            connection_id: connect_response.connection_id,
80                            seed: connect_response.seed,
81                        })
82                    }
83                }
84                Ok(buf[in_stream.cursor.position() as usize..].to_vec())
85            }
86            Some(connection_info) => {
87                if connection_id != connection_info.connection_id {
88                    Err(io::Error::new(io::ErrorKind::InvalidData, "problem"))
89                } else {
90                    let murmur = in_stream.read_u32()?;
91                    verify_hash(murmur, connection_info.seed, &buf[5..])?;
92                    debug!(
93                        "client received payload size:{} connection:{}",
94                        buf.len() - 5,
95                        connection_id.value
96                    );
97                    Ok(buf[5..].to_vec())
98                }
99            }
100        }
101    }
102}