This will let us have a lot less locking. We can do better in the future with ebpf and pinning connection to a specific CPU with multiple listen() points on the same address, but good enough for now Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
157 lines
4.4 KiB
Rust
157 lines
4.4 KiB
Rust
//! Connection handling and send/receive queues
|
|
|
|
pub mod handshake;
|
|
pub mod packet;
|
|
pub mod socket;
|
|
|
|
use ::std::{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},
|
|
};
|
|
|
|
/// 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 {
|
|
connections: Vec<Option<Arc<Connection>>>,
|
|
/// Bitmap to track which connection ids are used or free
|
|
ids_used: Vec<::bitmaps::Bitmap<1024>>,
|
|
}
|
|
|
|
impl ConnList {
|
|
pub(crate) fn new() -> Self {
|
|
let mut bitmap_id = ::bitmaps::Bitmap::<1024>::new();
|
|
bitmap_id.set(0, true); // ID(0) == handshake
|
|
Self {
|
|
connections: Vec::with_capacity(128),
|
|
ids_used: vec![bitmap_id],
|
|
}
|
|
}
|
|
pub(crate) fn reserve_first(
|
|
&mut self,
|
|
mut conn: Connection,
|
|
) -> Arc<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: 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 = ((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 = (self.ids_used.len() as u64) * 1024;
|
|
self.ids_used.push(new_bitmap);
|
|
}
|
|
let new_id = IDRecv(ID::new_u64(id));
|
|
conn.id_recv = new_id;
|
|
let conn = Arc::new(conn);
|
|
if (self.connections.len() as u64) < id {
|
|
self.connections.push(Some(conn.clone()));
|
|
} else {
|
|
// very probably redundant
|
|
self.connections[id as usize] = Some(conn.clone());
|
|
}
|
|
conn
|
|
}
|
|
}
|