/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2024 Dyne.org foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
use std::{sync::Arc, time::UNIX_EPOCH};
use async_trait::async_trait;
use log::debug;
use smol::Executor;
use super::{
super::{
channel::ChannelPtr,
hosts::{HostColor, HostsPtr},
message::{AddrsMessage, GetAddrsMessage},
message_publisher::MessageSubscription,
p2p::P2pPtr,
settings::SettingsPtr,
},
protocol_base::{ProtocolBase, ProtocolBasePtr},
};
use crate::Result;
/// Implements the seed protocol
pub struct ProtocolSeed {
channel: ChannelPtr,
hosts: HostsPtr,
settings: SettingsPtr,
addr_sub: MessageSubscription,
}
const PROTO_NAME: &str = "ProtocolSeed";
impl ProtocolSeed {
/// Create a new seed protocol.
pub async fn init(channel: ChannelPtr, p2p: P2pPtr) -> ProtocolBasePtr {
let hosts = p2p.hosts();
let settings = p2p.settings();
// Create a subscription to address message
let addr_sub =
channel.subscribe_msg::().await.expect("Missing addr dispatcher!");
Arc::new(Self { channel, hosts, settings, addr_sub })
}
/// Send our own external addresses over a channel. Set the
/// last_seen field to now.
pub async fn send_my_addrs(&self) -> Result<()> {
debug!(target: "net::protocol_seed::send_my_addrs()",
"[START] channel address={}", self.channel.address());
if self.settings.external_addrs.is_empty() {
debug!(target: "net::protocol_seed::send_my_addrs()",
"External address is not configured. Stopping");
return Ok(())
}
let mut addrs = vec![];
for addr in self.settings.external_addrs.clone() {
let last_seen = UNIX_EPOCH.elapsed().unwrap().as_secs();
addrs.push((addr, last_seen));
}
debug!(target: "net::protocol_seed::send_my_addrs()",
"Broadcasting {} addresses", addrs.len());
let ext_addr_msg = AddrsMessage { addrs };
self.channel.send(&ext_addr_msg).await?;
debug!(target: "net::protocol_seed::send_my_addrs()",
"[END] channel address={}", self.channel.address());
Ok(())
}
}
#[async_trait]
impl ProtocolBase for ProtocolSeed {
/// Starts the seed protocol. Creates a subscription to the address
/// message. If our external address is enabled, then send our address
/// to the seed server. Sends a get-address message and receives an
/// address messsage.
async fn start(self: Arc, _ex: Arc>) -> Result<()> {
debug!(target: "net::protocol_seed::start()", "START => address={}", self.channel.address());
// Send own address to the seed server
self.send_my_addrs().await?;
// Send get address message
let get_addr = GetAddrsMessage {
max: self.settings.outbound_connections as u32,
transports: self.settings.allowed_transports.clone(),
};
self.channel.send(&get_addr).await?;
// Receive addresses
let addrs_msg = self.addr_sub.receive().await?;
debug!(
target: "net::protocol_seed::start()",
"Received {} addrs from {}", addrs_msg.addrs.len(), self.channel.address(),
);
if !addrs_msg.addrs.is_empty() {
debug!(
target: "net::protocol_seed::start()",
"Appending to greylist...",
);
self.hosts.insert(HostColor::Grey, &addrs_msg.addrs).await;
}
debug!(target: "net::protocol_seed::start()", "END => address={}", self.channel.address());
Ok(())
}
fn name(&self) -> &'static str {
PROTO_NAME
}
}