use super::constants::*; use super::router; use super::timers::{Events, Timers}; use super::HandshakeJob; use super::bind::Bind; use super::tun::Tun; use std::fmt; use std::ops::Deref; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::Arc; use std::time::{Instant, SystemTime}; use spin::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; use crossbeam_channel::Sender; use x25519_dalek::PublicKey; pub struct Peer { pub router: Arc, T::Writer, B::Writer>>, pub state: Arc>, } pub struct PeerInner { // internal id (for logging) pub id: u64, // handshake state pub walltime_last_handshake: Mutex, pub last_handshake_sent: Mutex, // instant for last handshake pub handshake_queued: AtomicBool, // is a handshake job currently queued for the peer? pub queue: Mutex>>, // handshake queue // stats and configuration pub pk: PublicKey, // public key, DISCUSS: avoid this. TODO: remove pub rx_bytes: AtomicU64, // received bytes pub tx_bytes: AtomicU64, // transmitted bytes // timer model pub timers: RwLock, } impl Clone for Peer { fn clone(&self) -> Peer { Peer { router: self.router.clone(), state: self.state.clone(), } } } impl PeerInner { #[inline(always)] pub fn timers(&self) -> RwLockReadGuard { self.timers.read() } #[inline(always)] pub fn timers_mut(&self) -> RwLockWriteGuard { self.timers.write() } } impl fmt::Display for Peer { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "peer(id = {})", self.id) } } impl Deref for Peer { type Target = PeerInner; fn deref(&self) -> &Self::Target { &self.state } } impl Peer { /// Bring the peer down. Causing: /// /// - Timers to be stopped and disabled. /// - All keystate to be zeroed pub fn down(&self) { self.stop_timers(); self.router.down(); } /// Bring the peer up. pub fn up(&self) { self.router.up(); self.start_timers(); } } impl PeerInner { /* Queue a handshake request for the parallel workers * (if one does not already exist) * * The function is ratelimited. */ pub fn packet_send_handshake_initiation(&self) { // the function is rate limited { let mut lhs = self.last_handshake_sent.lock(); if lhs.elapsed() < REKEY_TIMEOUT { return; } *lhs = Instant::now(); } // create a new handshake job for the peer if !self.handshake_queued.swap(true, Ordering::SeqCst) { self.queue.lock().send(HandshakeJob::New(self.pk)).unwrap(); } } }