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.
This commit is contained in:
Alexis Sellier 2023-03-08 16:22:42 +01:00
parent 1168f2ddb5
commit db38f2df76
No known key found for this signature in database
2 changed files with 25 additions and 3 deletions

View File

@ -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}"),
}
}

View File

@ -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<Id> {
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> {