feat(request-response): don't close connection on stream errors

Related: #3591.

Pull-Request: #3913.
This commit is contained in:
Thomas Eizinger
2023-05-15 04:40:55 +02:00
committed by GitHub
parent 8c00dc9680
commit 1742bffcea
6 changed files with 23 additions and 20 deletions

3
Cargo.lock generated
View File

@ -1603,6 +1603,7 @@ dependencies = [
"futures", "futures",
"libp2p", "libp2p",
"multiaddr", "multiaddr",
"void",
] ]
[[package]] [[package]]
@ -2978,8 +2979,10 @@ dependencies = [
"libp2p-swarm-test", "libp2p-swarm-test",
"libp2p-tcp", "libp2p-tcp",
"libp2p-yamux", "libp2p-yamux",
"log",
"rand 0.8.5", "rand 0.8.5",
"smallvec", "smallvec",
"void",
] ]
[[package]] [[package]]

View File

@ -14,3 +14,4 @@ env_logger = "0.10"
futures = "0.3.28" futures = "0.3.28"
libp2p = { path = "../../libp2p", features = ["async-std", "dns", "kad", "noise", "macros", "request-response", "tcp", "websocket", "yamux"] } libp2p = { path = "../../libp2p", features = ["async-std", "dns", "kad", "noise", "macros", "request-response", "tcp", "websocket", "yamux"] }
multiaddr = { version = "0.17.1" } multiaddr = { version = "0.17.1" }
void = "1.0.2"

View File

@ -16,7 +16,7 @@ use libp2p::{
multiaddr::Protocol, multiaddr::Protocol,
noise, noise,
request_response::{self, ProtocolSupport, RequestId, ResponseChannel}, request_response::{self, ProtocolSupport, RequestId, ResponseChannel},
swarm::{NetworkBehaviour, StreamUpgradeError, Swarm, SwarmBuilder, SwarmEvent}, swarm::{NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent},
tcp, yamux, PeerId, Transport, tcp, yamux, PeerId, Transport,
}; };
@ -216,7 +216,7 @@ impl EventLoop {
async fn handle_event( async fn handle_event(
&mut self, &mut self,
event: SwarmEvent<ComposedEvent, Either<StreamUpgradeError<io::Error>, io::Error>>, event: SwarmEvent<ComposedEvent, Either<void::Void, io::Error>>,
) { ) {
match event { match event {
SwarmEvent::Behaviour(ComposedEvent::Kademlia( SwarmEvent::Behaviour(ComposedEvent::Kademlia(

View File

@ -8,9 +8,14 @@
These variants are no longer constructed. These variants are no longer constructed.
See [PR 3605]. See [PR 3605].
- Don't close connections if individual streams fail.
Log the error instead.
See [PR 3913].
[PR 3605]: https://github.com/libp2p/rust-libp2p/pull/3605 [PR 3605]: https://github.com/libp2p/rust-libp2p/pull/3605
[PR 3715]: https://github.com/libp2p/rust-libp2p/pull/3715 [PR 3715]: https://github.com/libp2p/rust-libp2p/pull/3715
[PR 3702]: https://github.com/libp2p/rust-libp2p/pull/3702 [PR 3702]: https://github.com/libp2p/rust-libp2p/pull/3702
[PR 3913]: https://github.com/libp2p/rust-libp2p/pull/3913
## 0.24.1 ## 0.24.1

View File

@ -19,6 +19,8 @@ libp2p-swarm = { workspace = true }
libp2p-identity = { workspace = true } libp2p-identity = { workspace = true }
rand = "0.8" rand = "0.8"
smallvec = "1.6.1" smallvec = "1.6.1"
void = "1.0.2"
log = "0.4.17"
[dev-dependencies] [dev-dependencies]
async-std = { version = "1.6.2", features = ["attributes"] } async-std = { version = "1.6.2", features = ["attributes"] }

View File

@ -39,7 +39,7 @@ use libp2p_swarm::{
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
collections::VecDeque, collections::VecDeque,
fmt, io, fmt,
sync::{ sync::{
atomic::{AtomicU64, Ordering}, atomic::{AtomicU64, Ordering},
Arc, Arc,
@ -65,8 +65,6 @@ where
substream_timeout: Duration, substream_timeout: Duration,
/// The current connection keep-alive. /// The current connection keep-alive.
keep_alive: KeepAlive, keep_alive: KeepAlive,
/// A pending fatal error that results in the connection being closed.
pending_error: Option<StreamUpgradeError<io::Error>>,
/// Queue of events to emit in `poll()`. /// Queue of events to emit in `poll()`.
pending_events: VecDeque<Event<TCodec>>, pending_events: VecDeque<Event<TCodec>>,
/// Outbound upgrades waiting to be emitted as an `OutboundSubstreamRequest`. /// Outbound upgrades waiting to be emitted as an `OutboundSubstreamRequest`.
@ -107,7 +105,6 @@ where
outbound: VecDeque::new(), outbound: VecDeque::new(),
inbound: FuturesUnordered::new(), inbound: FuturesUnordered::new(),
pending_events: VecDeque::new(), pending_events: VecDeque::new(),
pending_error: None,
inbound_request_id, inbound_request_id,
} }
} }
@ -151,21 +148,22 @@ where
self.pending_events self.pending_events
.push_back(Event::OutboundUnsupportedProtocols(info)); .push_back(Event::OutboundUnsupportedProtocols(info));
} }
_ => { StreamUpgradeError::Apply(e) => {
// Anything else is considered a fatal error or misbehaviour of log::debug!("outbound stream {info} failed: {e}");
// the remote peer and results in closing the connection. }
self.pending_error = Some(error); StreamUpgradeError::Io(e) => {
log::debug!("outbound stream {info} failed: {e}");
} }
} }
} }
fn on_listen_upgrade_error( fn on_listen_upgrade_error(
&mut self, &mut self,
ListenUpgradeError { error, .. }: ListenUpgradeError< ListenUpgradeError { error, info }: ListenUpgradeError<
<Self as ConnectionHandler>::InboundOpenInfo, <Self as ConnectionHandler>::InboundOpenInfo,
<Self as ConnectionHandler>::InboundProtocol, <Self as ConnectionHandler>::InboundProtocol,
>, >,
) { ) {
self.pending_error = Some(StreamUpgradeError::Apply(error)); log::debug!("inbound stream {info} failed: {error}");
} }
} }
@ -241,7 +239,7 @@ where
{ {
type FromBehaviour = RequestProtocol<TCodec>; type FromBehaviour = RequestProtocol<TCodec>;
type ToBehaviour = Event<TCodec>; type ToBehaviour = Event<TCodec>;
type Error = StreamUpgradeError<io::Error>; type Error = void::Void;
type InboundProtocol = ResponseProtocol<TCodec>; type InboundProtocol = ResponseProtocol<TCodec>;
type OutboundProtocol = RequestProtocol<TCodec>; type OutboundProtocol = RequestProtocol<TCodec>;
type OutboundOpenInfo = RequestId; type OutboundOpenInfo = RequestId;
@ -296,12 +294,6 @@ where
) -> Poll< ) -> Poll<
ConnectionHandlerEvent<RequestProtocol<TCodec>, RequestId, Self::ToBehaviour, Self::Error>, ConnectionHandlerEvent<RequestProtocol<TCodec>, RequestId, Self::ToBehaviour, Self::Error>,
> { > {
// Check for a pending (fatal) error.
if let Some(err) = self.pending_error.take() {
// The handler will not be polled again by the `Swarm`.
return Poll::Ready(ConnectionHandlerEvent::Close(err));
}
// Drain pending events. // Drain pending events.
if let Some(event) = self.pending_events.pop_front() { if let Some(event) = self.pending_events.pop_front() {
return Poll::Ready(ConnectionHandlerEvent::Custom(event)); return Poll::Ready(ConnectionHandlerEvent::Custom(event));