libFenrir/src/connection/mod.rs

164 lines
4.7 KiB
Rust
Raw Normal View History

//! Connection handling and send/receive queues
pub mod handshake;
pub mod packet;
pub mod socket;
use ::std::{rc::Rc, sync::Arc, vec::Vec};
pub use crate::connection::{
handshake::Handshake,
packet::{ConnectionID as ID, Packet, PacketData},
};
use crate::{
enc::{
hkdf::HkdfSha3,
sym::{CipherKind, CipherRecv, CipherSend},
},
inner::ThreadTracker,
};
/// strong typedef for receiving connection id
#[derive(Debug, Copy, Clone)]
pub struct IDRecv(pub ID);
/// strong typedef for sending connection id
#[derive(Debug, Copy, Clone)]
pub struct IDSend(pub ID);
/// Version of the fenrir protocol in use
#[derive(::num_derive::FromPrimitive, Debug, Copy, Clone)]
#[repr(u8)]
pub enum ProtocolVersion {
/// First Fenrir Protocol Version
V0 = 0,
}
impl ProtocolVersion {
/// actual length of the protocol version field
pub const fn len() -> usize {
1
}
/// Serialize into raw bytes
pub fn serialize(&self, out: &mut u8) {
*out = *self as u8;
}
}
/// A single connection and its data
#[derive(Debug)]
pub struct Connection {
/// Receiving Connection ID
pub id_recv: IDRecv,
/// Sending Connection ID
pub id_send: IDSend,
/// The main hkdf used for all secrets in this connection
pub hkdf: HkdfSha3,
/// Cipher for decrypting data
pub cipher_recv: CipherRecv,
/// Cipher for encrypting data
pub cipher_send: CipherSend,
}
/// Role: used to set the correct secrets
/// * Server: Connection is Incoming
/// * Client: Connection is Outgoing
#[derive(Debug, Copy, Clone)]
#[repr(u8)]
pub enum Role {
/// Server: we receive the connection
Server = 0,
/// Client: we initate the connection
Client,
}
impl Connection {
pub(crate) fn new(
hkdf: HkdfSha3,
cipher: CipherKind,
role: Role,
rand: &::ring::rand::SystemRandom,
) -> Self {
let (secret_recv, secret_send) = match role {
Role::Server => {
(hkdf.get_secret(b"to_server"), hkdf.get_secret(b"to_client"))
}
Role::Client => {
(hkdf.get_secret(b"to_client"), hkdf.get_secret(b"to_server"))
}
};
let mut cipher_recv = CipherRecv::new(cipher, secret_recv);
let mut cipher_send = CipherSend::new(cipher, secret_send, rand);
Self {
id_recv: IDRecv(ID::Handshake),
id_send: IDSend(ID::Handshake),
hkdf,
cipher_recv,
cipher_send,
}
}
}
// PERF: Arc<RwLock<ConnList>> loks a bit too much, need to find
// faster ways to do this
pub(crate) struct ConnList {
thread_id: ThreadTracker,
connections: Vec<Option<Rc<Connection>>>,
/// Bitmap to track which connection ids are used or free
ids_used: Vec<::bitmaps::Bitmap<1024>>,
}
impl ConnList {
pub(crate) fn new(thread_id: ThreadTracker) -> Self {
let mut bitmap_id = ::bitmaps::Bitmap::<1024>::new();
bitmap_id.set(0, true); // ID(0) == handshake
Self {
thread_id,
connections: Vec::with_capacity(128),
ids_used: vec![bitmap_id],
}
}
pub(crate) fn reserve_first(
&mut self,
mut conn: Connection,
) -> Rc<Connection> {
// uhm... bad things are going on here:
// * id must be initialized, but only because:
// * rust does not understand that after the `!found` id is always
// initialized
// * `ID::new_u64` is really safe only with >0, but here it always is
// ...we should probably rewrite it in better, safer rust
let mut id_in_thread: u64 = 0;
let mut found = false;
for (i, b) in self.ids_used.iter_mut().enumerate() {
match b.first_false_index() {
Some(idx) => {
b.set(idx, true);
id_in_thread = ((i as u64) * 1024) + (idx as u64);
found = true;
break;
}
None => {}
}
}
if !found {
let mut new_bitmap = ::bitmaps::Bitmap::<1024>::new();
new_bitmap.set(0, true);
id_in_thread = (self.ids_used.len() as u64) * 1024;
self.ids_used.push(new_bitmap);
}
let actual_id = (id_in_thread * (self.thread_id.total as u64))
+ (self.thread_id.id as u64);
let new_id = IDRecv(ID::new_u64(actual_id));
conn.id_recv = new_id;
let conn = Rc::new(conn);
if (self.connections.len() as u64) < id_in_thread {
self.connections.push(Some(conn.clone()));
} else {
// very probably redundant
self.connections[id_in_thread as usize] = Some(conn.clone());
}
conn
}
}