From db38f2df76977168fa5621c395e1956c176fdec1 Mon Sep 17 00:00:00 2001 From: Alexis Sellier Date: Wed, 8 Mar 2023 16:22:42 +0100 Subject: [PATCH] node: Handle `FetchOk` never being received It's possible for a peer to disconnect before responding with `FetchOk`. In that case, we make sure to return to any pending fetch request with an error. --- radicle-node/src/service.rs | 13 +++++++++++-- radicle-node/src/service/session.rs | 15 ++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/radicle-node/src/service.rs b/radicle-node/src/service.rs index 480f6c45..0d9edc2c 100644 --- a/radicle-node/src/service.rs +++ b/radicle-node/src/service.rs @@ -710,7 +710,16 @@ where debug!(target: "service", "Disconnected from {} ({})", remote, reason); if let Some(session) = self.sessions.get_mut(&remote) { - session.to_disconnected(since); + // If the peer disconnected while we were waiting for a [`Message::FetchOk`], + // return a failure to any potential fetcher. + if let Some(requested) = session.to_disconnected(since) { + if let Some(resp) = self.fetch_reqs.remove(&requested) { + resp.send(FetchResult::Failed { + reason: format!("disconnected: {reason}"), + }) + .ok(); + } + } // Attempt to re-connect to persistent peers. if let Some(address) = self.config.peer(&remote) { @@ -1484,7 +1493,7 @@ impl fmt::Display for DisconnectReason { match self { Self::Dial(err) => write!(f, "{err}"), Self::Connection(err) => write!(f, "{err}"), - Self::Session(err) => write!(f, "error: {err}"), + Self::Session(err) => write!(f, "{err}"), Self::Fetch(err) => write!(f, "fetch: {err}"), } } diff --git a/radicle-node/src/service/session.rs b/radicle-node/src/service/session.rs index 1487becf..313aaf52 100644 --- a/radicle-node/src/service/session.rs +++ b/radicle-node/src/service/session.rs @@ -292,8 +292,21 @@ impl Session { }; } - pub fn to_disconnected(&mut self, since: LocalTime) { + /// Move the session state to "disconnected". Returns any pending RID + /// that was requested. + pub fn to_disconnected(&mut self, since: LocalTime) -> Option { + let request = if let State::Connected { + protocol: Protocol::Gossip { requested }, + .. + } = self.state + { + requested + } else { + None + }; self.state = State::Disconnected { since }; + + request } pub fn ping(&mut self, reactor: &mut Reactor) -> Result<(), Error> {