connection_layer/
host_codec.rs

1use crate::client_to_host::ClientToHostCommands;
2use crate::host_to_client::{ConnectResponse, HostToClientCommands};
3use crate::{verify_hash, write_to_stream, ConnectionId, ConnectionSecretSeed, RequestId};
4use flood_rs::in_stream::InOctetStream;
5use flood_rs::out_stream::OutOctetStream;
6use flood_rs::{Deserialize, ReadOctetStream, Serialize};
7use freelist_rs::FreeList;
8use log::{debug, trace};
9use secure_random::SecureRandom;
10use std::collections::HashMap;
11use std::io;
12use std::io::ErrorKind;
13
14pub trait DatagramHostEncoder {
15    fn encode(&mut self, connection_id: u8, buf: &[u8]) -> io::Result<Vec<u8>>;
16}
17
18pub struct HostConnection {
19    pub created_from_request: RequestId,
20    pub connection_id: ConnectionId,
21    pub seed: ConnectionSecretSeed,
22    pub has_received_connect: bool,
23}
24
25pub struct ConnectionLayerHostCodec {
26    pub connection_ids: FreeList<u8>,
27    pub connections: HashMap<u8, HostConnection>,
28    pub random: Box<dyn SecureRandom>,
29}
30
31impl ConnectionLayerHostCodec {
32    pub fn new(random: Box<dyn SecureRandom>) -> Self {
33        let mut s = Self {
34            connections: HashMap::new(),
35            connection_ids: FreeList::new(0xff),
36            random,
37        };
38        s.connection_ids.allocate(); // Reserve zero
39
40        s
41    }
42}
43
44
45impl DatagramHostEncoder for ConnectionLayerHostCodec {
46    fn encode(&mut self, connection_id: u8, buf: &[u8]) -> io::Result<Vec<u8>> {
47        let connection = self.connections.get_mut(&connection_id);
48        if connection.is_none() {
49            Err(io::Error::new(
50                ErrorKind::InvalidData,
51                format!("Unknown connection {}", connection_id),
52            ))?;
53        }
54        let actual_connection = connection.unwrap();
55        let mut stream = OutOctetStream::new();
56        if actual_connection.has_received_connect {
57            trace!(
58                "host sending on connection {} size: {}",
59                actual_connection.connection_id.value,
60                buf.len()
61            );
62            write_to_stream(
63                &mut stream,
64                actual_connection.connection_id,
65                actual_connection.seed,
66                buf,
67            )?;
68        } else {
69            debug!(
70                "host sending connect response connection_id: {} for request: {}",
71                actual_connection.connection_id.value, actual_connection.created_from_request
72            );
73            ConnectionId { value: 0 }.to_stream(&mut stream)?;
74            let connect_response = ConnectResponse {
75                request_id: actual_connection.created_from_request,
76                connection_id: actual_connection.connection_id,
77                seed: actual_connection.seed,
78            };
79            HostToClientCommands::Connect(connect_response).serialize(&mut stream)?
80        }
81
82        flood_rs::WriteOctetStream::write(&mut stream, buf)?;
83
84        Ok(stream.octets().to_vec())
85    }
86}
87
88
89pub trait DatagramHostDecoder {
90    fn decode(&mut self, buf: &[u8]) -> io::Result<(u8, Vec<u8>)>;
91}
92
93impl DatagramHostDecoder for ConnectionLayerHostCodec {
94    fn decode(&mut self, buf: &[u8]) -> io::Result<(u8, Vec<u8>)> {
95        let mut in_stream = InOctetStream::new(buf);
96        let connection_id = ConnectionId::from_stream(&mut in_stream)?;
97        if connection_id.value != 0 {
98            if let Some(connection) = self.connections.get_mut(&connection_id.value) {
99                let murmur = in_stream.read_u32()?;
100                verify_hash(murmur, connection.seed, &buf[5..])?;
101                trace!(
102                    "host received payload of size: {} from connection {}",
103                    buf.len() - 5,
104                    connection.connection_id.value
105                );
106
107                connection.has_received_connect = true;
108                //                Ok(buf[5..].to_vec())
109                Ok((
110                    connection_id.value,
111                    buf[in_stream.cursor.position() as usize..].to_vec(),
112                ))
113            } else {
114                Err(io::Error::new(
115                    io::ErrorKind::InvalidData,
116                    "unknown connection_id",
117                ))?
118            }
119        } else {
120            // OOB
121            let command = ClientToHostCommands::deserialize(&mut in_stream)?;
122            match command {
123                ClientToHostCommands::Connect(connect_request) => {
124                    debug!("host received connect request {connect_request:?}");
125                    let assigned_connection_id = self.connection_ids.allocate().ok_or(
126                        io::Error::new(io::ErrorKind::InvalidData, "free list problem"),
127                    )?;
128                    let new_connection = HostConnection {
129                        created_from_request: connect_request.request_id,
130                        connection_id: ConnectionId {
131                            value: assigned_connection_id,
132                        },
133                        seed: ConnectionSecretSeed(self.random.get_random_u64() as u32),
134                        has_received_connect: false,
135                    };
136                    self.connections
137                        .insert(assigned_connection_id, new_connection);
138                    Ok((
139                        assigned_connection_id,
140                        buf[in_stream.cursor.position() as usize..].to_vec(),
141                    ))
142                }
143            }
144        }
145    }
146}