2022-05-04 20:40:10 -04:00
|
|
|
use crate::connection_limits::*;
|
2022-01-03 23:58:26 -05:00
|
|
|
use crate::network_connection::*;
|
2021-11-22 11:28:30 -05:00
|
|
|
use crate::xx::*;
|
|
|
|
use crate::*;
|
2022-01-05 12:01:02 -05:00
|
|
|
use alloc::collections::btree_map::Entry;
|
2022-05-04 20:40:10 -04:00
|
|
|
use hashlink::LruCache;
|
2021-11-22 11:28:30 -05:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ConnectionTable {
|
2022-05-04 20:40:10 -04:00
|
|
|
max_connections: Vec<usize>,
|
|
|
|
conn_by_descriptor: Vec<LruCache<ConnectionDescriptor, NetworkConnection>>,
|
2022-01-05 12:01:02 -05:00
|
|
|
conns_by_remote: BTreeMap<PeerAddress, Vec<NetworkConnection>>,
|
2022-05-04 20:40:10 -04:00
|
|
|
address_filter: ConnectionLimits,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn protocol_to_index(protocol: ProtocolType) -> usize {
|
|
|
|
match protocol {
|
|
|
|
ProtocolType::TCP => 0,
|
|
|
|
ProtocolType::WS => 1,
|
|
|
|
ProtocolType::WSS => 2,
|
|
|
|
ProtocolType::UDP => panic!("not a connection-oriented protocol"),
|
|
|
|
}
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ConnectionTable {
|
2022-05-04 20:40:10 -04:00
|
|
|
pub fn new(config: VeilidConfig) -> Self {
|
|
|
|
let max_connections = {
|
|
|
|
let c = config.get();
|
|
|
|
vec![
|
|
|
|
c.network.protocol.tcp.max_connections as usize,
|
|
|
|
c.network.protocol.ws.max_connections as usize,
|
|
|
|
c.network.protocol.wss.max_connections as usize,
|
|
|
|
]
|
|
|
|
};
|
2021-11-22 11:28:30 -05:00
|
|
|
Self {
|
2022-05-04 20:40:10 -04:00
|
|
|
max_connections,
|
|
|
|
conn_by_descriptor: vec![
|
|
|
|
LruCache::new_unbounded(),
|
|
|
|
LruCache::new_unbounded(),
|
|
|
|
LruCache::new_unbounded(),
|
|
|
|
],
|
2022-01-05 12:01:02 -05:00
|
|
|
conns_by_remote: BTreeMap::new(),
|
2022-05-04 20:40:10 -04:00
|
|
|
address_filter: ConnectionLimits::new(config),
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-03 23:58:26 -05:00
|
|
|
pub fn add_connection(&mut self, conn: NetworkConnection) -> Result<(), String> {
|
2022-01-02 23:49:01 -05:00
|
|
|
let descriptor = conn.connection_descriptor();
|
2022-05-04 20:40:10 -04:00
|
|
|
let ip_addr = descriptor.remote.socket_address.to_ip_addr();
|
|
|
|
|
|
|
|
let index = protocol_to_index(descriptor.protocol_type());
|
|
|
|
if self.conn_by_descriptor[index].contains_key(&descriptor) {
|
2021-12-14 09:48:33 -05:00
|
|
|
return Err(format!(
|
|
|
|
"Connection already added to table: {:?}",
|
|
|
|
descriptor
|
|
|
|
));
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
2022-05-04 20:40:10 -04:00
|
|
|
|
|
|
|
// Filter by ip for connection limits
|
|
|
|
self.address_filter.add(ip_addr).map_err(map_to_string)?;
|
|
|
|
|
|
|
|
// Add the connection to the table
|
|
|
|
let res = self.conn_by_descriptor[index].insert(descriptor, conn.clone());
|
2021-11-22 11:28:30 -05:00
|
|
|
assert!(res.is_none());
|
2022-01-05 12:01:02 -05:00
|
|
|
|
2022-05-04 20:40:10 -04:00
|
|
|
// if we have reached the maximum number of connections per protocol type
|
|
|
|
// then drop the least recently used connection
|
|
|
|
if self.conn_by_descriptor[index].len() > self.max_connections[index] {
|
|
|
|
if let Some((lruk, _)) = self.conn_by_descriptor[index].remove_lru() {
|
|
|
|
self.remove_connection_records(lruk);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add connection records
|
2022-01-05 12:01:02 -05:00
|
|
|
let conns = self.conns_by_remote.entry(descriptor.remote).or_default();
|
2022-05-04 20:40:10 -04:00
|
|
|
|
2022-01-05 16:58:18 -05:00
|
|
|
//warn!("add_connection: {:?}", conn);
|
2022-01-05 12:01:02 -05:00
|
|
|
conns.push(conn);
|
|
|
|
|
2022-01-04 09:53:30 -05:00
|
|
|
Ok(())
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
|
2022-05-04 20:40:10 -04:00
|
|
|
pub fn get_connection(
|
|
|
|
&mut self,
|
|
|
|
descriptor: ConnectionDescriptor,
|
|
|
|
) -> Option<NetworkConnection> {
|
|
|
|
let index = protocol_to_index(descriptor.protocol_type());
|
|
|
|
let out = self.conn_by_descriptor[index].get(&descriptor).cloned();
|
2022-01-05 16:58:18 -05:00
|
|
|
//warn!("get_connection: {:?} -> {:?}", descriptor, out);
|
2022-01-05 12:01:02 -05:00
|
|
|
out
|
|
|
|
}
|
2022-05-04 20:40:10 -04:00
|
|
|
|
|
|
|
pub fn get_last_connection_by_remote(
|
|
|
|
&mut self,
|
|
|
|
remote: PeerAddress,
|
|
|
|
) -> Option<NetworkConnection> {
|
2022-01-05 12:01:02 -05:00
|
|
|
let out = self
|
|
|
|
.conns_by_remote
|
|
|
|
.get(&remote)
|
|
|
|
.map(|v| v[(v.len() - 1)].clone());
|
2022-01-05 16:58:18 -05:00
|
|
|
//warn!("get_last_connection_by_remote: {:?} -> {:?}", remote, out);
|
2022-05-04 20:40:10 -04:00
|
|
|
if let Some(connection) = &out {
|
|
|
|
// lru bump
|
|
|
|
let index = protocol_to_index(connection.connection_descriptor().protocol_type());
|
|
|
|
let _ = self.conn_by_descriptor[index].get(&connection.connection_descriptor());
|
|
|
|
}
|
2022-01-05 12:01:02 -05:00
|
|
|
out
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn connection_count(&self) -> usize {
|
2022-05-04 20:40:10 -04:00
|
|
|
self.conn_by_descriptor.iter().fold(0, |b, c| b + c.len())
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
|
2022-05-04 20:40:10 -04:00
|
|
|
fn remove_connection_records(&mut self, descriptor: ConnectionDescriptor) {
|
|
|
|
let ip_addr = descriptor.remote.socket_address.to_ip_addr();
|
2022-01-05 12:01:02 -05:00
|
|
|
|
2022-05-04 20:40:10 -04:00
|
|
|
// conns_by_remote
|
2022-01-05 12:01:02 -05:00
|
|
|
match self.conns_by_remote.entry(descriptor.remote) {
|
|
|
|
Entry::Vacant(_) => {
|
|
|
|
panic!("inconsistency in connection table")
|
|
|
|
}
|
|
|
|
Entry::Occupied(mut o) => {
|
|
|
|
let v = o.get_mut();
|
|
|
|
|
|
|
|
// Remove one matching connection from the list
|
|
|
|
for (n, elem) in v.iter().enumerate() {
|
|
|
|
if elem.connection_descriptor() == descriptor {
|
|
|
|
v.remove(n);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// No connections left for this remote, remove the entry from conns_by_remote
|
|
|
|
if v.is_empty() {
|
|
|
|
o.remove_entry();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-04 20:40:10 -04:00
|
|
|
self.address_filter
|
|
|
|
.remove(ip_addr)
|
|
|
|
.expect("Inconsistency in connection table");
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove_connection(
|
|
|
|
&mut self,
|
|
|
|
descriptor: ConnectionDescriptor,
|
|
|
|
) -> Result<NetworkConnection, String> {
|
|
|
|
//warn!("remove_connection: {:?}", descriptor);
|
|
|
|
let index = protocol_to_index(descriptor.protocol_type());
|
|
|
|
let out = self.conn_by_descriptor[index]
|
|
|
|
.remove(&descriptor)
|
|
|
|
.ok_or_else(|| format!("Connection not in table: {:?}", descriptor))?;
|
|
|
|
|
|
|
|
self.remove_connection_records(descriptor);
|
2022-01-05 12:01:02 -05:00
|
|
|
|
|
|
|
Ok(out)
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
}
|