vpncloud/src/engine/common.rs

159 lines
4.5 KiB
Rust

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::{fs::File, hash::BuildHasherDefault};
use fnv::FnvHasher;
use crate::util::CtrlC;
use crate::{
config::Config,
crypto::PeerCrypto,
device::Device,
engine::{
device_thread::DeviceThread,
shared::{SharedPeerCrypto, SharedTable, SharedTraffic},
socket_thread::{ReconnectEntry, SocketThread},
},
error::Error,
messages::AddrList,
net::Socket,
payload::Protocol,
port_forwarding::PortForwarding,
types::NodeId,
util::{resolve, Time, TimeSource},
};
pub type Hash = BuildHasherDefault<FnvHasher>;
pub const STATS_INTERVAL: Time = 60;
pub const SPACE_BEFORE: usize = 100;
pub struct PeerData {
pub addrs: AddrList,
#[allow(dead_code)] // TODO: export in status
pub last_seen: Time,
pub timeout: Time,
pub peer_timeout: u16,
pub node_id: NodeId,
pub crypto: PeerCrypto,
}
pub struct GenericCloud<D: Device, P: Protocol, S: Socket, TS: TimeSource> {
socket_thread: SocketThread<S, D, P, TS>,
device_thread: DeviceThread<S, D, P, TS>,
running: Arc<AtomicBool>,
}
impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS> {
#[allow(clippy::too_many_arguments)]
pub fn new(
config: &Config, socket: S, device: D, port_forwarding: Option<PortForwarding>, stats_file: Option<File>,
) -> Result<Self, Error> {
let table = SharedTable::<TS>::new(config);
let traffic = SharedTraffic::new();
let peer_crypto = SharedPeerCrypto::new();
let running = Arc::new(AtomicBool::new(true));
let device_thread = DeviceThread::<S, D, P, TS>::new(
config.clone(),
device.duplicate()?,
socket.clone(),
traffic.clone(),
peer_crypto.clone(),
table.clone(),
running.clone(),
);
let mut socket_thread = SocketThread::<S, D, P, TS>::new(
config.clone(),
device,
socket,
traffic,
peer_crypto,
table,
port_forwarding,
stats_file,
running.clone(),
);
socket_thread.housekeep()?;
Ok(Self { socket_thread, device_thread, running })
}
pub fn add_peer(&mut self, addr: String) -> Result<(), Error> {
let resolved = resolve(addr.clone())?;
self.socket_thread.reconnect_peers.push(ReconnectEntry {
address: Some((addr, TS::now())),
resolved,
tries: 0,
timeout: 1,
next: TS::now(),
final_timeout: None,
});
Ok(())
}
pub fn run(self) {
debug!("Starting threads");
let running = self.running.clone();
let device = self.device_thread;
let device_thread_handle = thread::spawn(move || device.run());
let socket = self.socket_thread;
let socket_thread_handle = thread::spawn(move || socket.run());
let ctrlc = CtrlC::new();
ctrlc.wait();
running.store(false, Ordering::SeqCst);
debug!("Waiting for threads to end");
device_thread_handle.join().unwrap();
socket_thread_handle.join().unwrap();
debug!("Threads stopped");
}
}
#[cfg(test)]
use crate::device::MockDevice;
#[cfg(test)]
use crate::net::MockSocket;
#[cfg(test)]
use crate::util::MockTimeSource;
#[cfg(test)]
use std::net::SocketAddr;
#[cfg(test)]
impl<P: Protocol> GenericCloud<MockDevice, P, MockSocket, MockTimeSource> {
pub fn socket(&mut self) -> &mut MockSocket {
&mut self.socket_thread.socket
}
pub fn device(&mut self) -> &mut MockDevice {
&mut self.device_thread.device
}
pub fn connect(&mut self, addr: SocketAddr) -> Result<(), Error> {
self.socket_thread.connect(addr)
}
pub fn trigger_socket_event(&mut self) {
self.socket_thread.iteration()
}
pub fn trigger_device_event(&mut self) {
self.device_thread.iteration()
}
pub fn trigger_housekeep(&mut self) {
try_fail!(self.socket_thread.housekeep(), "Housekeep failed: {}");
try_fail!(self.device_thread.housekeep(), "Housekeep failed: {}");
}
pub fn is_connected(&self, addr: &SocketAddr) -> bool {
self.socket_thread.peers.contains_key(addr)
}
pub fn own_addresses(&self) -> &[SocketAddr] {
&self.socket_thread.own_addresses
}
pub fn get_num(&self) -> usize {
self.socket_thread.socket.address().unwrap().port() as usize
}
}