Code fully compiles for processing incoming peers

This commit is contained in:
Igor Katson 2023-12-05 18:24:49 +00:00
parent 9c7cf61e1a
commit 65c69f576b
No known key found for this signature in database
GPG key ID: B4EC22B66D61A3F5
11 changed files with 310 additions and 32 deletions

View file

@ -89,7 +89,9 @@ use crate::{
peer_connection::{
PeerConnection, PeerConnectionHandler, PeerConnectionOptions, WriterRequest,
},
session::CheckedIncomingConnection,
spawn_utils::spawn,
torrent_state::peer::Peer,
tracker_comms::{TrackerError, TrackerRequest, TrackerRequestEvent, TrackerResponse},
type_aliases::{PeerHandle, BF},
};
@ -100,7 +102,7 @@ use self::{
atomic::PeerCountersAtomic as AtomicPeerCounters,
snapshot::{PeerStatsFilter, PeerStatsSnapshot},
},
InflightRequest, PeerState, PeerTx, SendMany,
InflightRequest, PeerRx, PeerState, PeerTx, SendMany,
},
peers::PeerStates,
stats::{atomic::AtomicStats, snapshot::StatsSnapshot},
@ -361,7 +363,99 @@ impl TorrentStateLive {
}
}
async fn task_manage_peer(self: Arc<Self>, addr: SocketAddr) -> anyhow::Result<()> {
pub(crate) fn add_incoming_peer(
self: &Arc<Self>,
checked_peer: CheckedIncomingConnection,
) -> anyhow::Result<()> {
use dashmap::mapref::entry::Entry;
let (tx, rx) = unbounded_channel();
let counters = match self.peers.states.entry(checked_peer.addr) {
Entry::Occupied(_) => bail!("we are already managing peer {}", checked_peer.addr),
Entry::Vacant(vac) => {
let peer = Peer::new_live_for_incoming_connection(
Id20(checked_peer.handshake.peer_id),
tx.clone(),
);
let counters = peer.stats.counters.clone();
vac.insert(peer);
counters
}
};
self.spawn(
"incoming peer",
error_span!("manage_incoming_peer", addr = %checked_peer.addr),
self.clone()
.task_manage_incoming_peer(checked_peer, counters, tx, rx),
);
Ok(())
}
async fn task_manage_incoming_peer(
self: Arc<Self>,
checked_peer: CheckedIncomingConnection,
counters: Arc<AtomicPeerCounters>,
tx: PeerTx,
rx: PeerRx,
) -> anyhow::Result<()> {
// TODO: bump counters for incoming
let handler = PeerHandler {
addr: checked_peer.addr,
on_bitfield_notify: Default::default(),
unchoke_notify: Default::default(),
locked: RwLock::new(PeerHandlerLocked {
i_am_choked: true,
previously_requested_pieces: BF::new(),
}),
requests_sem: Semaphore::new(0),
state: self.clone(),
tx,
counters,
};
let options = PeerConnectionOptions {
connect_timeout: self.meta.options.peer_connect_timeout,
read_write_timeout: self.meta.options.peer_read_write_timeout,
..Default::default()
};
let peer_connection = PeerConnection::new(
checked_peer.addr,
self.meta.info_hash,
self.meta.peer_id,
&handler,
Some(options),
self.meta.spawner,
);
let requester = handler.task_peer_chunk_requester(checked_peer.addr);
let res = tokio::select! {
r = requester => {r}
r = peer_connection.manage_peer_incoming(
rx,
checked_peer.read_so_far,
checked_peer.read_buf,
checked_peer.handshake,
checked_peer.stream
) => {r}
};
handler.state.peer_semaphore.add_permits(1);
match res {
// We disconnected the peer ourselves as we don't need it
Ok(()) => {
handler.on_peer_died(None)?;
}
Err(e) => {
debug!("error managing peer: {:#}", e);
handler.on_peer_died(Some(e))?;
}
};
Ok(())
}
async fn task_manage_outgoing_peer(self: Arc<Self>, addr: SocketAddr) -> anyhow::Result<()> {
let state = self;
let (rx, tx) = state.peers.mark_peer_connecting(addr)?;
@ -440,7 +534,7 @@ impl TorrentStateLive {
state.spawn(
"manage_peer",
error_span!(parent: state.meta.span.clone(), "manage_peer", peer = addr.to_string()),
state.clone().task_manage_peer(addr),
state.clone().task_manage_outgoing_peer(addr),
);
}
}

View file

@ -52,6 +52,15 @@ pub(crate) struct Peer {
pub stats: stats::atomic::PeerStats,
}
impl Peer {
pub fn new_live_for_incoming_connection(peer_id: Id20, tx: PeerTx) -> Self {
Self {
state: PeerStateNoMut(PeerState::Live(LivePeerState::new(peer_id, tx))),
stats: Default::default(),
}
}
}
#[derive(Debug, Default)]
pub(crate) enum PeerState {
#[default]