Skip to content

Commit 6ed92ab

Browse files
authored
[swarm] MultiHandler: Respect inbound timeouts and upgrade versions. (#1786)
* Respect inbound timeouts and upgrade versions. * Update CHANGELOG
1 parent 6528114 commit 6ed92ab

File tree

2 files changed

+39
-11
lines changed

2 files changed

+39
-11
lines changed

swarm/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# 0.22.1 [unreleased]
22

3+
- Respect inbound timeouts and upgrade versions in the `MultiHandler`.
4+
[PR 1786](https://github.com/libp2p/rust-libp2p/pull/1786).
5+
36
- Instead of iterating each inbound and outbound substream upgrade looking for
47
one to make progress, use a `FuturesUnordered` for both pending inbound and
58
pending outbound upgrades. As a result only those upgrades are polled that are

swarm/src/protocols_handler/multi.rs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,20 @@ use crate::upgrade::{
3737
};
3838
use futures::{future::BoxFuture, prelude::*};
3939
use libp2p_core::{ConnectedPoint, Multiaddr, PeerId};
40-
use libp2p_core::upgrade::{ProtocolName, UpgradeError, NegotiationError, ProtocolError};
40+
use libp2p_core::upgrade::{self, ProtocolName, UpgradeError, NegotiationError, ProtocolError};
4141
use rand::Rng;
4242
use std::{
43+
cmp,
4344
collections::{HashMap, HashSet},
4445
error,
4546
fmt,
4647
hash::Hash,
4748
iter::{self, FromIterator},
48-
task::{Context, Poll}
49+
task::{Context, Poll},
50+
time::Duration
4951
};
5052

51-
/// A [`ProtocolsHandler`] for multiple other `ProtocolsHandler`s.
53+
/// A [`ProtocolsHandler`] for multiple `ProtocolsHandler`s of the same type.
5254
#[derive(Clone)]
5355
pub struct MultiHandler<K, H> {
5456
handlers: HashMap<K, H>
@@ -74,6 +76,9 @@ where
7476
/// Create and populate a `MultiHandler` from the given handler iterator.
7577
///
7678
/// It is an error for any two protocols handlers to share the same protocol name.
79+
///
80+
/// > **Note**: All handlers should use the same [`upgrade::Version`] for
81+
/// > the inbound and outbound [`SubstreamProtocol`]s.
7782
pub fn try_from_iter<I>(iter: I) -> Result<Self, DuplicateProtonameError>
7883
where
7984
I: IntoIterator<Item = (K, H)>
@@ -100,17 +105,34 @@ where
100105
type OutboundOpenInfo = (K, <H as ProtocolsHandler>::OutboundOpenInfo);
101106

102107
fn listen_protocol(&self) -> SubstreamProtocol<Self::InboundProtocol, Self::InboundOpenInfo> {
103-
let (upgrade, info) = self.handlers.iter()
108+
let (upgrade, info, timeout, version) = self.handlers.iter()
104109
.map(|(k, h)| {
105-
let (_, u, i) = h.listen_protocol().into_upgrade();
106-
(k.clone(), (u, i))
110+
let p = h.listen_protocol();
111+
let t = *p.timeout();
112+
let (v, u, i) = p.into_upgrade();
113+
(k.clone(), (v, u, i, t))
107114
})
108-
.fold((Upgrade::new(), Info::new()), |(mut upg, mut inf), (k, (u, i))| {
109-
upg.upgrades.push((k.clone(), u));
110-
inf.infos.push((k, i));
111-
(upg, inf)
112-
});
115+
.fold((Upgrade::new(), Info::new(), Duration::from_secs(0), None),
116+
|(mut upg, mut inf, mut timeout, mut version), (k, (v, u, i, t))| {
117+
upg.upgrades.push((k.clone(), u));
118+
inf.infos.push((k, i));
119+
timeout = cmp::max(timeout, t);
120+
version = version.map_or(Some(v), |vv|
121+
if v != vv {
122+
// Different upgrade (i.e. protocol negotiation) protocol
123+
// versions are usually incompatible and not negotiated
124+
// themselves, so a protocol upgrade may fail.
125+
log::warn!("Differing upgrade versions. Defaulting to V1.");
126+
Some(upgrade::Version::V1)
127+
} else {
128+
Some(v)
129+
});
130+
(upg, inf, timeout, version)
131+
}
132+
);
113133
SubstreamProtocol::new(upgrade, info)
134+
.with_timeout(timeout)
135+
.with_upgrade_protocol(version.unwrap_or(upgrade::Version::V1))
114136
}
115137

116138
fn inject_fully_negotiated_outbound (
@@ -293,6 +315,9 @@ where
293315
/// Create and populate an `IntoMultiHandler` from the given iterator.
294316
///
295317
/// It is an error for any two protocols handlers to share the same protocol name.
318+
///
319+
/// > **Note**: All handlers should use the same [`upgrade::Version`] for
320+
/// > the inbound and outbound [`SubstreamProtocol`]s.
296321
pub fn try_from_iter<I>(iter: I) -> Result<Self, DuplicateProtonameError>
297322
where
298323
I: IntoIterator<Item = (K, H)>

0 commit comments

Comments
 (0)