use parking_lot::Mutex;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
use collections::UniqueLinkedList;
use network_messages::{Message, SignalMessage, SignalMessageFlags};
use network_primitives::address::PeerId;
use crate::address::peer_address_book::PeerAddressBook;
use crate::network_config::NetworkConfig;
use crate::peer_channel::PeerChannel;
use super::close_type::CloseType;
pub struct SignalProcessor {
addresses: Arc<PeerAddressBook>,
network_config: Arc<NetworkConfig>,
forwards: Mutex<SignalStore>,
}
impl SignalProcessor {
const SIGNAL_TTL_INITIAL: u8 = 3;
const SIGNAL_STORE_MAX_SIZE: usize = 1000;
pub fn new(addresses: Arc<PeerAddressBook>, network_config: Arc<NetworkConfig>) -> Self {
Self {
addresses,
network_config,
forwards: Mutex::new(SignalStore::new(Self::SIGNAL_STORE_MAX_SIZE)),
}
}
pub fn on_signal(&self, channel: Arc<PeerChannel>, msg: SignalMessage) {
if msg.ttl > Self::SIGNAL_TTL_INITIAL {
channel.close(CloseType::InvalidSignalTtl);
return;
}
let my_peer_id = self.network_config.peer_id();
if msg.sender_id == *my_peer_id {
warn!("Received signal from myself to {:?} from {:?} (myId: {:?})", &msg.recipient_id, &channel.address_info.peer_address(), my_peer_id);
return;
}
if msg.flags.contains(SignalMessageFlags::UNROUTABLE) && self.forwards.lock().signal_forwarded(
msg.recipient_id.clone(),
msg.sender_id.clone(),
msg.nonce
) {
if let Some(sender_address) = self.addresses.state().get_by_peer_id(&msg.sender_id) {
self.addresses.unroutable(channel.clone(), sender_address);
}
}
if msg.recipient_id == *my_peer_id {
warn!("Received signal from the id {:?} for myself through the channel {:?}", &msg.recipient_id, &channel.address_info.peer_address());
return;
}
if msg.ttl == 0 {
debug!("Discarding signal from {:?} to {:?} - TTL reached", &msg.sender_id, &msg.recipient_id);
if msg.flags.is_empty() {
channel.send_or_close(Message::Signal(Box::new(SignalMessage {
sender_id: msg.recipient_id,
recipient_id: msg.sender_id,
nonce: msg.nonce,
ttl: Self::SIGNAL_TTL_INITIAL,
flags: SignalMessageFlags::TTL_EXCEEDED,
payload: Vec::new(),
sender_public_key: None,
signature: None,
})));
}
return;
}
let peer_address_book_state = self.addresses.state();
let signal_channel = peer_address_book_state.get_channel_by_peer_id(&msg.recipient_id);
if signal_channel.is_none() {
debug!("Failed to forward signal from {:?} to {:?} - no route found", msg.sender_id, msg.recipient_id);
if msg.flags.is_empty() {
channel.send_or_close(Message::Signal(Box::new(SignalMessage {
sender_id: msg.recipient_id,
recipient_id: msg.sender_id,
nonce: msg.nonce,
ttl: Self::SIGNAL_TTL_INITIAL,
flags: SignalMessageFlags::UNROUTABLE,
payload: Vec::new(),
sender_public_key: None,
signature: None,
})));
}
return;
}
let signal_channel = signal_channel.expect("This should always work because we dealed with the None case above");
if signal_channel.address_info.peer_address() == channel.address_info.peer_address() {
debug!("Discarding signal from {:?} to {:?} - shortest route via sending peer", msg.sender_id, msg.recipient_id);
if msg.flags.is_empty() {
channel.send_or_close(Message::Signal(Box::new(SignalMessage {
sender_id: msg.recipient_id,
recipient_id: msg.sender_id,
nonce: msg.nonce,
ttl: Self::SIGNAL_TTL_INITIAL,
flags: SignalMessageFlags::UNROUTABLE,
payload: Vec::new(),
sender_public_key: None,
signature: None,
})));
}
return;
}
signal_channel.send_or_close(Message::Signal(Box::new(SignalMessage {
sender_id: msg.sender_id.clone(),
recipient_id: msg.recipient_id.clone(),
nonce: msg.nonce,
ttl: msg.ttl - 1,
flags: msg.flags,
payload: msg.payload,
sender_public_key: msg.sender_public_key,
signature: msg.signature,
})));
debug!("Forwarded signal to {:?} from {:?}", &msg.recipient_id, &msg.sender_id);
if msg.flags.is_empty() {
self.forwards.lock().add(msg.sender_id, msg.recipient_id, msg.nonce);
}
}
}
pub struct SignalStore {
max_size: usize,
queue: UniqueLinkedList<ForwardedSignal>,
store: HashMap<ForwardedSignal, Instant>,
}
impl SignalStore {
pub fn new(max_size: usize) -> Self {
Self {
max_size,
queue: UniqueLinkedList::new(),
store: HashMap::new(),
}
}
pub fn add(&mut self, sender_id: PeerId, recipient_id: PeerId, nonce: u32) {
let signal = ForwardedSignal::new(sender_id, recipient_id, nonce);
if self.store.contains_key(&signal) {
self.store.insert(signal.clone(), Instant::now());
self.queue.remove(&signal);
self.queue.push_front(signal);
return
}
if self.queue.len() >= self.max_size {
if let Some(oldest) = self.queue.pop_back() {
self.store.remove(&oldest);
}
}
self.queue.push_front(signal.clone());
self.store.insert(signal, Instant::now());
}
pub fn signal_forwarded(&mut self, sender_id: PeerId, recipient_id: PeerId, nonce: u32) -> bool {
let signal = ForwardedSignal::new(sender_id, recipient_id, nonce);
if let Some(last_seen) = self.store.get(&signal) {
let valid = last_seen.elapsed() < ForwardedSignal::SIGNAL_MAX_AGE;
if !valid {
for _ in 0..self.queue.len() {
let signal_to_remove = self.queue.pop_back().expect("The check above guarantees this is Some()");
self.store.remove(&signal_to_remove);
if signal == signal_to_remove {
break;
}
}
}
valid
} else {
false
}
}
}
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct ForwardedSignal {
sender_id: PeerId,
recipient_id: PeerId,
nonce: u32,
}
impl ForwardedSignal {
const SIGNAL_MAX_AGE: Duration = Duration::from_secs(10);
pub fn new(sender_id: PeerId, recipient_id: PeerId, nonce: u32) -> Self {
Self {
sender_id,
recipient_id,
nonce
}
}
}