Rename `Peer` to `Session`

Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
Alexis Sellier 2022-09-22 17:48:03 +02:00
parent 51f2d4e3fc
commit 1fa85f0da3
No known key found for this signature in database
3 changed files with 61 additions and 59 deletions

View File

@ -27,7 +27,7 @@ use crate::git::Url;
use crate::identity::{Doc, Id}; use crate::identity::{Doc, Id};
use crate::service::config::ProjectTracking; use crate::service::config::ProjectTracking;
use crate::service::message::{NodeAnnouncement, RefsAnnouncement}; use crate::service::message::{NodeAnnouncement, RefsAnnouncement};
use crate::service::peer::{Peer, PeerError, PeerState}; use crate::service::peer::{Session, SessionError, SessionState};
use crate::storage; use crate::storage;
use crate::storage::{Inventory, ReadRepository, RefUpdate, WriteRepository, WriteStorage}; use crate::storage::{Inventory, ReadRepository, RefUpdate, WriteRepository, WriteStorage};
@ -138,8 +138,8 @@ pub enum CommandError {}
#[derive(Debug)] #[derive(Debug)]
pub struct Service<S, T, G> { pub struct Service<S, T, G> {
/// Peers currently or recently connected. /// Peer sessions, currently or recently connected.
peers: Peers, sessions: Sessions,
/// Service state that isn't peer-specific. /// Service state that isn't peer-specific.
context: Context<S, T, G>, context: Context<S, T, G>,
/// Whether our local inventory no long represents what we have announced to the network. /// Whether our local inventory no long represents what we have announced to the network.
@ -169,7 +169,7 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Service
Self { Self {
context: Context::new(config, clock, storage, addrmgr, signer, rng.clone()), context: Context::new(config, clock, storage, addrmgr, signer, rng.clone()),
peers: Peers::new(rng), sessions: Sessions::new(rng),
out_of_sync: false, out_of_sync: false,
last_idle: LocalTime::default(), last_idle: LocalTime::default(),
last_sync: LocalTime::default(), last_sync: LocalTime::default(),
@ -180,17 +180,17 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Service
} }
pub fn disconnect(&mut self, remote: &IpAddr, reason: DisconnectReason) { pub fn disconnect(&mut self, remote: &IpAddr, reason: DisconnectReason) {
if let Some(addr) = self.peers.get(remote).map(|p| p.addr) { if let Some(addr) = self.sessions.get(remote).map(|p| p.addr) {
self.context.disconnect(addr, reason); self.context.disconnect(addr, reason);
} }
} }
pub fn seeds(&self, id: &Id) -> Box<dyn Iterator<Item = (&NodeId, &Peer)> + '_> { pub fn seeds(&self, id: &Id) -> Box<dyn Iterator<Item = (&NodeId, &Session)> + '_> {
if let Some(peers) = self.routing.get(id) { if let Some(peers) = self.routing.get(id) {
Box::new( Box::new(
peers peers
.iter() .iter()
.filter_map(|id| self.peers.by_id(id).map(|p| (id, p))), .filter_map(|id| self.sessions.by_id(id).map(|p| (id, p))),
) )
} else { } else {
Box::new(std::iter::empty()) Box::new(std::iter::empty())
@ -236,8 +236,8 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Service
} }
/// Get the connected peers. /// Get the connected peers.
pub fn peers(&self) -> &Peers { pub fn peers(&self) -> &Sessions {
&self.peers &self.sessions
} }
/// Get the current inventory. /// Get the current inventory.
@ -427,7 +427,7 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Service
let node = self.node_id(); let node = self.node_id();
let repo = self.storage.repository(&id).unwrap(); let repo = self.storage.repository(&id).unwrap();
let remote = repo.remote(&node).unwrap(); let remote = repo.remote(&node).unwrap();
let peers = self.peers.negotiated().map(|(_, p)| p); let peers = self.sessions.negotiated().map(|(_, p)| p);
let refs = remote.refs.into(); let refs = remote.refs.into();
let message = RefsAnnouncement { id, refs }; let message = RefsAnnouncement { id, refs };
let signature = message.sign(&self.signer); let signature = message.sign(&self.signer);
@ -448,9 +448,9 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Service
let ip = addr.ip(); let ip = addr.ip();
let persistent = self.context.config.is_persistent(addr); let persistent = self.context.config.is_persistent(addr);
let peer = self let peer = self
.peers .sessions
.entry(ip) .entry(ip)
.or_insert_with(|| Peer::new(*addr, Link::Outbound, persistent)); .or_insert_with(|| Session::new(*addr, Link::Outbound, persistent));
peer.attempted(); peer.attempted();
} }
@ -472,14 +472,14 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Service
// TODO: Refactor this so that we don't create messages if the peer isn't found. // TODO: Refactor this so that we don't create messages if the peer isn't found.
let messages = self.handshake_messages(); let messages = self.handshake_messages();
if let Some(peer) = self.peers.get_mut(&ip) { if let Some(peer) = self.sessions.get_mut(&ip) {
self.context.write_all(peer.addr, messages); self.context.write_all(peer.addr, messages);
peer.connected(); peer.connected();
} }
} else { } else {
self.peers.insert( self.sessions.insert(
ip, ip,
Peer::new( Session::new(
addr, addr,
Link::Inbound, Link::Inbound,
self.context.config.is_persistent(&addr), self.context.config.is_persistent(&addr),
@ -498,8 +498,8 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Service
debug!("Disconnected from {} ({})", ip, reason); debug!("Disconnected from {} ({})", ip, reason);
if let Some(peer) = self.peers.get_mut(&ip) { if let Some(peer) = self.sessions.get_mut(&ip) {
peer.state = PeerState::Disconnected { since }; peer.state = SessionState::Disconnected { since };
// Attempt to re-connect to persistent peers. // Attempt to re-connect to persistent peers.
if self.context.config.is_persistent(addr) && peer.attempts() < MAX_CONNECTION_ATTEMPTS if self.context.config.is_persistent(addr) && peer.attempts() < MAX_CONNECTION_ATTEMPTS
@ -529,7 +529,7 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Service
pub fn received_message(&mut self, addr: &std::net::SocketAddr, msg: Envelope) { pub fn received_message(&mut self, addr: &std::net::SocketAddr, msg: Envelope) {
let peer_ip = addr.ip(); let peer_ip = addr.ip();
let peer = if let Some(peer) = self.peers.get_mut(&peer_ip) { let peer = if let Some(peer) = self.sessions.get_mut(&peer_ip) {
peer peer
} else { } else {
return; return;
@ -551,7 +551,7 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Service
if let Some(msg) = relay { if let Some(msg) = relay {
let negotiated = self let negotiated = self
.peers .sessions
.negotiated() .negotiated()
.filter(|(ip, _)| **ip != peer_ip) .filter(|(ip, _)| **ip != peer_ip)
.map(|(_, p)| p); .map(|(_, p)| p);
@ -568,7 +568,7 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Service
fn announce_inventory(&mut self) -> Result<(), storage::Error> { fn announce_inventory(&mut self) -> Result<(), storage::Error> {
let inv = Message::inventory(self.context.inventory_announcement()?, &self.context.signer); let inv = Message::inventory(self.context.inventory_announcement()?, &self.context.signer);
for addr in self.peers.negotiated().map(|(_, p)| p.addr) { for addr in self.sessions.negotiated().map(|(_, p)| p.addr) {
self.context.write(addr, inv.clone()); self.context.write(addr, inv.clone());
} }
Ok(()) Ok(())
@ -580,8 +580,8 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Service
fn maintain_connections(&mut self) { fn maintain_connections(&mut self) {
// TODO: Connect to all potential seeds. // TODO: Connect to all potential seeds.
if self.peers.len() < TARGET_OUTBOUND_PEERS { if self.sessions.len() < TARGET_OUTBOUND_PEERS {
let delta = TARGET_OUTBOUND_PEERS - self.peers.len(); let delta = TARGET_OUTBOUND_PEERS - self.sessions.len();
for _ in 0..delta { for _ in 0..delta {
// TODO: Connect to random peer. // TODO: Connect to random peer.
@ -607,7 +607,7 @@ impl<S, T, G> DerefMut for Service<S, T, G> {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum DisconnectReason { pub enum DisconnectReason {
User, User,
Error(PeerError), Error(SessionError),
} }
impl DisconnectReason { impl DisconnectReason {
@ -823,14 +823,14 @@ impl<S, T, G> Context<S, T, G> {
} }
/// Broadcast a message to a list of peers. /// Broadcast a message to a list of peers.
fn broadcast<'a>(&mut self, msg: Message, peers: impl IntoIterator<Item = &'a Peer>) { fn broadcast<'a>(&mut self, msg: Message, peers: impl IntoIterator<Item = &'a Session>) {
for peer in peers { for peer in peers {
self.write(peer.addr, msg.clone()); self.write(peer.addr, msg.clone());
} }
} }
/// Relay a message to interested peers. /// Relay a message to interested peers.
fn relay<'a>(&mut self, msg: Message, peers: impl IntoIterator<Item = &'a Peer>) { fn relay<'a>(&mut self, msg: Message, peers: impl IntoIterator<Item = &'a Session>) {
if let Message::RefsAnnouncement { message, .. } = &msg { if let Message::RefsAnnouncement { message, .. } = &msg {
let id = message.id.clone(); let id = message.id.clone();
let peers = peers.into_iter().filter(|p| { let peers = peers.into_iter().filter(|p| {
@ -851,16 +851,16 @@ impl<S, T, G> Context<S, T, G> {
#[derive(Debug)] #[derive(Debug)]
/// Holds currently (or recently) connected peers. /// Holds currently (or recently) connected peers.
pub struct Peers(AddressBook<IpAddr, Peer>); pub struct Sessions(AddressBook<IpAddr, Session>);
impl Peers { impl Sessions {
pub fn new(rng: Rng) -> Self { pub fn new(rng: Rng) -> Self {
Self(AddressBook::new(rng)) Self(AddressBook::new(rng))
} }
pub fn by_id(&self, id: &NodeId) -> Option<&Peer> { pub fn by_id(&self, id: &NodeId) -> Option<&Session> {
self.0.values().find(|p| { self.0.values().find(|p| {
if let PeerState::Negotiated { id: _id, .. } = &p.state { if let SessionState::Negotiated { id: _id, .. } = &p.state {
_id == id _id == id
} else { } else {
false false
@ -869,20 +869,20 @@ impl Peers {
} }
/// Iterator over fully negotiated peers. /// Iterator over fully negotiated peers.
pub fn negotiated(&self) -> impl Iterator<Item = (&IpAddr, &Peer)> + Clone { pub fn negotiated(&self) -> impl Iterator<Item = (&IpAddr, &Session)> + Clone {
self.0.iter().filter(move |(_, p)| p.is_negotiated()) self.0.iter().filter(move |(_, p)| p.is_negotiated())
} }
} }
impl Deref for Peers { impl Deref for Sessions {
type Target = AddressBook<IpAddr, Peer>; type Target = AddressBook<IpAddr, Session>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.0
} }
} }
impl DerefMut for Peers { impl DerefMut for Sessions {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0 &mut self.0
} }

View File

@ -3,7 +3,7 @@ use crate::service::*;
#[derive(Debug, Default)] #[derive(Debug, Default)]
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
pub enum PeerState { pub enum SessionState {
/// Initial peer state. For outgoing peers this /// Initial peer state. For outgoing peers this
/// means we've attempted a connection. For incoming /// means we've attempted a connection. For incoming
/// peers, this means they've successfully connected /// peers, this means they've successfully connected
@ -24,7 +24,7 @@ pub enum PeerState {
} }
#[derive(thiserror::Error, Debug, Clone)] #[derive(thiserror::Error, Debug, Clone)]
pub enum PeerError { pub enum SessionError {
#[error("wrong network constant in message: {0}")] #[error("wrong network constant in message: {0}")]
WrongMagic(u32), WrongMagic(u32),
#[error("wrong protocol version in message: {0}")] #[error("wrong protocol version in message: {0}")]
@ -35,8 +35,9 @@ pub enum PeerError {
Misbehavior, Misbehavior,
} }
/// A peer session. Each connected peer will have one session.
#[derive(Debug)] #[derive(Debug)]
pub struct Peer { pub struct Session {
/// Peer address. /// Peer address.
pub addr: net::SocketAddr, pub addr: net::SocketAddr,
/// Connection direction. /// Connection direction.
@ -45,7 +46,7 @@ pub struct Peer {
/// to this peer upon disconnection. /// to this peer upon disconnection.
pub persistent: bool, pub persistent: bool,
/// Peer connection state. /// Peer connection state.
pub state: PeerState, pub state: SessionState,
/// Last known peer time. /// Last known peer time.
pub timestamp: Timestamp, pub timestamp: Timestamp,
/// Peer subscription. /// Peer subscription.
@ -57,11 +58,11 @@ pub struct Peer {
attempts: usize, attempts: usize,
} }
impl Peer { impl Session {
pub fn new(addr: net::SocketAddr, link: Link, persistent: bool) -> Self { pub fn new(addr: net::SocketAddr, link: Link, persistent: bool) -> Self {
Self { Self {
addr, addr,
state: PeerState::default(), state: SessionState::default(),
link, link,
timestamp: Timestamp::default(), timestamp: Timestamp::default(),
subscribe: None, subscribe: None,
@ -75,7 +76,7 @@ impl Peer {
} }
pub fn is_negotiated(&self) -> bool { pub fn is_negotiated(&self) -> bool {
matches!(self.state, PeerState::Negotiated { .. }) matches!(self.state, SessionState::Negotiated { .. })
} }
pub fn attempts(&self) -> usize { pub fn attempts(&self) -> usize {
@ -94,19 +95,19 @@ impl Peer {
&mut self, &mut self,
envelope: Envelope, envelope: Envelope,
ctx: &mut Context<S, T, G>, ctx: &mut Context<S, T, G>,
) -> Result<Option<Message>, PeerError> ) -> Result<Option<Message>, SessionError>
where where
T: storage::WriteStorage<'r>, T: storage::WriteStorage<'r>,
G: crypto::Signer, G: crypto::Signer,
{ {
if envelope.magic != ctx.config.network.magic() { if envelope.magic != ctx.config.network.magic() {
return Err(PeerError::WrongMagic(envelope.magic)); return Err(SessionError::WrongMagic(envelope.magic));
} }
debug!("Received {:?} from {}", &envelope.msg, self.ip()); debug!("Received {:?} from {}", &envelope.msg, self.ip());
match (&self.state, envelope.msg) { match (&self.state, envelope.msg) {
( (
PeerState::Initial, SessionState::Initial,
Message::Initialize { Message::Initialize {
id, id,
timestamp, timestamp,
@ -118,10 +119,10 @@ impl Peer {
let now = ctx.timestamp(); let now = ctx.timestamp();
if timestamp.abs_diff(now) > MAX_TIME_DELTA.as_secs() { if timestamp.abs_diff(now) > MAX_TIME_DELTA.as_secs() {
return Err(PeerError::InvalidTimestamp(timestamp)); return Err(SessionError::InvalidTimestamp(timestamp));
} }
if version != PROTOCOL_VERSION { if version != PROTOCOL_VERSION {
return Err(PeerError::WrongVersion(version)); return Err(SessionError::WrongVersion(version));
} }
// Nb. This is a very primitive handshake. Eventually we should have anyhow // Nb. This is a very primitive handshake. Eventually we should have anyhow
// extra "acknowledgment" message sent when the `Initialize` is well received. // extra "acknowledgment" message sent when the `Initialize` is well received.
@ -131,34 +132,35 @@ impl Peer {
// Nb. we don't set the peer timestamp here, since it is going to be // Nb. we don't set the peer timestamp here, since it is going to be
// set after the first message is received only. Setting it here would // set after the first message is received only. Setting it here would
// mean that messages received right after the handshake could be ignored. // mean that messages received right after the handshake could be ignored.
self.state = PeerState::Negotiated { self.state = SessionState::Negotiated {
id, id,
since: ctx.clock.local_time(), since: ctx.clock.local_time(),
addrs, addrs,
git, git,
}; };
} }
(PeerState::Initial, _) => { (SessionState::Initial, _) => {
debug!( debug!(
"Disconnecting peer {} for sending us a message before handshake", "Disconnecting peer {} for sending us a message before handshake",
self.ip() self.ip()
); );
return Err(PeerError::Misbehavior); return Err(SessionError::Misbehavior);
} }
( (
PeerState::Negotiated { git, .. }, SessionState::Negotiated { git, .. },
Message::InventoryAnnouncement { Message::InventoryAnnouncement {
node, node,
message, message,
signature, signature,
}, },
) => { ) => {
// FIXME: This is wrong, we are comparing timestamps of different peers.
let now = ctx.clock.local_time(); let now = ctx.clock.local_time();
let last = self.timestamp; let last = self.timestamp;
// Don't allow messages from too far in the past or future. // Don't allow messages from too far in the past or future.
if message.timestamp.abs_diff(now.as_secs()) > MAX_TIME_DELTA.as_secs() { if message.timestamp.abs_diff(now.as_secs()) > MAX_TIME_DELTA.as_secs() {
return Err(PeerError::InvalidTimestamp(message.timestamp)); return Err(SessionError::InvalidTimestamp(message.timestamp));
} }
// Discard inventory messages we've already seen, otherwise update // Discard inventory messages we've already seen, otherwise update
// out last seen time. // out last seen time.
@ -179,7 +181,7 @@ impl Peer {
} }
// Process a peer inventory update announcement by (maybe) fetching. // Process a peer inventory update announcement by (maybe) fetching.
( (
PeerState::Negotiated { git, .. }, SessionState::Negotiated { git, .. },
Message::RefsAnnouncement { Message::RefsAnnouncement {
node, node,
message, message,
@ -209,11 +211,11 @@ impl Peer {
} }
} }
} else { } else {
return Err(PeerError::Misbehavior); return Err(SessionError::Misbehavior);
} }
} }
( (
PeerState::Negotiated { .. }, SessionState::Negotiated { .. },
Message::NodeAnnouncement { Message::NodeAnnouncement {
node, node,
message, message,
@ -221,21 +223,21 @@ impl Peer {
}, },
) => { ) => {
if !message.verify(&node, &signature) { if !message.verify(&node, &signature) {
return Err(PeerError::Misbehavior); return Err(SessionError::Misbehavior);
} }
log::warn!("Node announcement handling is not implemented"); log::warn!("Node announcement handling is not implemented");
} }
(PeerState::Negotiated { .. }, Message::Subscribe(subscribe)) => { (SessionState::Negotiated { .. }, Message::Subscribe(subscribe)) => {
self.subscribe = Some(subscribe); self.subscribe = Some(subscribe);
} }
(PeerState::Negotiated { .. }, Message::Initialize { .. }) => { (SessionState::Negotiated { .. }, Message::Initialize { .. }) => {
debug!( debug!(
"Disconnecting peer {} for sending us a redundant handshake message", "Disconnecting peer {} for sending us a redundant handshake message",
self.ip() self.ip()
); );
return Err(PeerError::Misbehavior); return Err(SessionError::Misbehavior);
} }
(PeerState::Disconnected { .. }, msg) => { (SessionState::Disconnected { .. }, msg) => {
debug!("Ignoring {:?} from disconnected peer {}", msg, self.ip()); debug!("Ignoring {:?} from disconnected peer {}", msg, self.ip());
} }
} }

View File

@ -226,7 +226,7 @@ fn test_inventory_relay_bad_timestamp() {
); );
assert_matches!( assert_matches!(
alice.outbox().next(), alice.outbox().next(),
Some(Io::Disconnect(addr, DisconnectReason::Error(PeerError::InvalidTimestamp(t)))) Some(Io::Disconnect(addr, DisconnectReason::Error(SessionError::InvalidTimestamp(t))))
if addr == bob.addr() && t == timestamp if addr == bob.addr() && t == timestamp
); );
} }