mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-13 01:51:23 +00:00
feat(swarm)!: allow NetworkBehaviour
s to manage connections
Previously, a `ConnectionHandler` was immediately requested from the `NetworkBehaviour` as soon as a new dial was initiated or a new incoming connection accepted. With this patch, we delay the creation of the handler until the connection is actually established and fully upgraded, i.e authenticated and multiplexed. As a consequence, `NetworkBehaviour::new_handler` is now deprecated in favor of a new set of callbacks: - `NetworkBehaviour::handle_pending_inbound_connection` - `NetworkBehaviour::handle_pending_outbound_connection` - `NetworkBehaviour::handle_established_inbound_connection` - `NetworkBehaviour::handle_established_outbound_connection` All callbacks are fallible, allowing the `NetworkBehaviour` to abort the connection either immediately or after it is fully established. All callbacks also receive a `ConnectionId` parameter which uniquely identifies the connection. For example, in case a `NetworkBehaviour` issues a dial via `NetworkBehaviourAction::Dial`, it can unambiguously detect this dial in these lifecycle callbacks via the `ConnectionId`. Finally, `NetworkBehaviour::handle_pending_outbound_connection` also replaces `NetworkBehaviour::addresses_of_peer` by allowing the behaviour to return more addresses to be used for the dial. Resolves #2824. Pull-Request: #3254.
This commit is contained in:
@ -23,16 +23,19 @@
|
||||
mod handler;
|
||||
pub mod rate_limiter;
|
||||
|
||||
use crate::behaviour::handler::Handler;
|
||||
use crate::message_proto;
|
||||
use crate::multiaddr_ext::MultiaddrExt;
|
||||
use crate::protocol::{inbound_hop, outbound_stop};
|
||||
use either::Either;
|
||||
use instant::Instant;
|
||||
use libp2p_core::multiaddr::Protocol;
|
||||
use libp2p_core::PeerId;
|
||||
use libp2p_core::{ConnectedPoint, Endpoint, Multiaddr, PeerId};
|
||||
use libp2p_swarm::behaviour::{ConnectionClosed, FromSwarm};
|
||||
use libp2p_swarm::{
|
||||
ConnectionHandlerUpgrErr, ConnectionId, ExternalAddresses, NetworkBehaviour,
|
||||
NetworkBehaviourAction, NotifyHandler, PollParameters, THandlerInEvent, THandlerOutEvent,
|
||||
dummy, ConnectionDenied, ConnectionHandlerUpgrErr, ConnectionId, ExternalAddresses,
|
||||
NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, THandler,
|
||||
THandlerInEvent, THandlerOutEvent,
|
||||
};
|
||||
use std::collections::{hash_map, HashMap, HashSet, VecDeque};
|
||||
use std::num::NonZeroU32;
|
||||
@ -250,17 +253,57 @@ impl Behaviour {
|
||||
}
|
||||
|
||||
impl NetworkBehaviour for Behaviour {
|
||||
type ConnectionHandler = handler::Prototype;
|
||||
type ConnectionHandler = Either<Handler, dummy::ConnectionHandler>;
|
||||
type OutEvent = Event;
|
||||
|
||||
fn new_handler(&mut self) -> Self::ConnectionHandler {
|
||||
handler::Prototype {
|
||||
config: handler::Config {
|
||||
fn handle_established_inbound_connection(
|
||||
&mut self,
|
||||
_: ConnectionId,
|
||||
_: PeerId,
|
||||
local_addr: &Multiaddr,
|
||||
remote_addr: &Multiaddr,
|
||||
) -> Result<THandler<Self>, ConnectionDenied> {
|
||||
if local_addr.is_relayed() {
|
||||
// Deny all substreams on relayed connection.
|
||||
return Ok(Either::Right(dummy::ConnectionHandler));
|
||||
}
|
||||
|
||||
Ok(Either::Left(Handler::new(
|
||||
handler::Config {
|
||||
reservation_duration: self.config.reservation_duration,
|
||||
max_circuit_duration: self.config.max_circuit_duration,
|
||||
max_circuit_bytes: self.config.max_circuit_bytes,
|
||||
},
|
||||
ConnectedPoint::Listener {
|
||||
local_addr: local_addr.clone(),
|
||||
send_back_addr: remote_addr.clone(),
|
||||
},
|
||||
)))
|
||||
}
|
||||
|
||||
fn handle_established_outbound_connection(
|
||||
&mut self,
|
||||
_: ConnectionId,
|
||||
_: PeerId,
|
||||
addr: &Multiaddr,
|
||||
role_override: Endpoint,
|
||||
) -> Result<THandler<Self>, ConnectionDenied> {
|
||||
if addr.is_relayed() {
|
||||
// Deny all substreams on relayed connection.
|
||||
return Ok(Either::Right(dummy::ConnectionHandler));
|
||||
}
|
||||
|
||||
Ok(Either::Left(Handler::new(
|
||||
handler::Config {
|
||||
reservation_duration: self.config.reservation_duration,
|
||||
max_circuit_duration: self.config.max_circuit_duration,
|
||||
max_circuit_bytes: self.config.max_circuit_bytes,
|
||||
},
|
||||
ConnectedPoint::Dialer {
|
||||
address: addr.clone(),
|
||||
role_override,
|
||||
},
|
||||
)))
|
||||
}
|
||||
|
||||
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
|
||||
|
@ -33,11 +33,11 @@ use instant::Instant;
|
||||
use libp2p_core::{upgrade, ConnectedPoint, Multiaddr, PeerId};
|
||||
use libp2p_swarm::handler::{
|
||||
ConnectionEvent, DialUpgradeError, FullyNegotiatedInbound, FullyNegotiatedOutbound,
|
||||
ListenUpgradeError, SendWrapper,
|
||||
ListenUpgradeError,
|
||||
};
|
||||
use libp2p_swarm::{
|
||||
dummy, ConnectionHandler, ConnectionHandlerEvent, ConnectionHandlerUpgrErr, ConnectionId,
|
||||
IntoConnectionHandler, KeepAlive, NegotiatedSubstream, SubstreamProtocol,
|
||||
ConnectionHandler, ConnectionHandlerEvent, ConnectionHandlerUpgrErr, ConnectionId, KeepAlive,
|
||||
NegotiatedSubstream, SubstreamProtocol,
|
||||
};
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt;
|
||||
@ -337,31 +337,6 @@ impl fmt::Debug for Event {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Prototype {
|
||||
pub config: Config,
|
||||
}
|
||||
|
||||
impl IntoConnectionHandler for Prototype {
|
||||
type Handler = Either<Handler, dummy::ConnectionHandler>;
|
||||
|
||||
fn into_handler(self, _remote_peer_id: &PeerId, endpoint: &ConnectedPoint) -> Self::Handler {
|
||||
if endpoint.is_relayed() {
|
||||
// Deny all substreams on relayed connection.
|
||||
Either::Right(dummy::ConnectionHandler)
|
||||
} else {
|
||||
Either::Left(Handler::new(self.config, endpoint.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
fn inbound_protocol(&self) -> <Self::Handler as ConnectionHandler>::InboundProtocol {
|
||||
Either::Left(SendWrapper(inbound_hop::Upgrade {
|
||||
reservation_duration: self.config.reservation_duration,
|
||||
max_circuit_duration: self.config.max_circuit_duration,
|
||||
max_circuit_bytes: self.config.max_circuit_bytes,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// [`ConnectionHandler`] that manages substreams for a relay on a single
|
||||
/// connection with a peer.
|
||||
pub struct Handler {
|
||||
@ -418,7 +393,7 @@ pub struct Handler {
|
||||
}
|
||||
|
||||
impl Handler {
|
||||
fn new(config: Config, endpoint: ConnectedPoint) -> Handler {
|
||||
pub fn new(config: Config, endpoint: ConnectedPoint) -> Handler {
|
||||
Handler {
|
||||
endpoint,
|
||||
config,
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
mod behaviour;
|
||||
mod copy_future;
|
||||
mod multiaddr_ext;
|
||||
mod priv_client;
|
||||
mod protocol;
|
||||
pub mod v2;
|
||||
|
12
protocols/relay/src/multiaddr_ext.rs
Normal file
12
protocols/relay/src/multiaddr_ext.rs
Normal file
@ -0,0 +1,12 @@
|
||||
use libp2p_core::multiaddr::Protocol;
|
||||
use libp2p_core::Multiaddr;
|
||||
|
||||
pub(crate) trait MultiaddrExt {
|
||||
fn is_relayed(&self) -> bool;
|
||||
}
|
||||
|
||||
impl MultiaddrExt for Multiaddr {
|
||||
fn is_relayed(&self) -> bool {
|
||||
self.iter().any(|p| p == Protocol::P2pCircuit)
|
||||
}
|
||||
}
|
@ -23,6 +23,8 @@
|
||||
mod handler;
|
||||
pub(crate) mod transport;
|
||||
|
||||
use crate::multiaddr_ext::MultiaddrExt;
|
||||
use crate::priv_client::handler::Handler;
|
||||
use crate::protocol::{self, inbound_stop, outbound_hop};
|
||||
use bytes::Bytes;
|
||||
use either::Either;
|
||||
@ -32,12 +34,13 @@ use futures::future::{BoxFuture, FutureExt};
|
||||
use futures::io::{AsyncRead, AsyncWrite};
|
||||
use futures::ready;
|
||||
use futures::stream::StreamExt;
|
||||
use libp2p_core::PeerId;
|
||||
use libp2p_core::{Endpoint, Multiaddr, PeerId};
|
||||
use libp2p_swarm::behaviour::{ConnectionClosed, ConnectionEstablished, FromSwarm};
|
||||
use libp2p_swarm::dial_opts::DialOpts;
|
||||
use libp2p_swarm::{
|
||||
ConnectionHandlerUpgrErr, ConnectionId, DialFailure, NegotiatedSubstream, NetworkBehaviour,
|
||||
NetworkBehaviourAction, NotifyHandler, PollParameters, THandlerInEvent, THandlerOutEvent,
|
||||
dummy, ConnectionDenied, ConnectionHandler, ConnectionHandlerUpgrErr, ConnectionId,
|
||||
DialFailure, NegotiatedSubstream, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler,
|
||||
PollParameters, THandler, THandlerInEvent, THandlerOutEvent,
|
||||
};
|
||||
use std::collections::{hash_map, HashMap, VecDeque};
|
||||
use std::io::{Error, ErrorKind, IoSlice};
|
||||
@ -156,11 +159,47 @@ impl Behaviour {
|
||||
}
|
||||
|
||||
impl NetworkBehaviour for Behaviour {
|
||||
type ConnectionHandler = handler::Prototype;
|
||||
type ConnectionHandler = Either<Handler, dummy::ConnectionHandler>;
|
||||
type OutEvent = Event;
|
||||
|
||||
fn new_handler(&mut self) -> Self::ConnectionHandler {
|
||||
handler::Prototype::new(self.local_peer_id, None)
|
||||
fn handle_established_inbound_connection(
|
||||
&mut self,
|
||||
connection_id: ConnectionId,
|
||||
peer: PeerId,
|
||||
local_addr: &Multiaddr,
|
||||
remote_addr: &Multiaddr,
|
||||
) -> Result<THandler<Self>, ConnectionDenied> {
|
||||
if local_addr.is_relayed() {
|
||||
return Ok(Either::Right(dummy::ConnectionHandler));
|
||||
}
|
||||
|
||||
let mut handler = Handler::new(self.local_peer_id, peer, remote_addr.clone());
|
||||
|
||||
if let Some(event) = self.pending_handler_commands.remove(&connection_id) {
|
||||
handler.on_behaviour_event(event)
|
||||
}
|
||||
|
||||
Ok(Either::Left(handler))
|
||||
}
|
||||
|
||||
fn handle_established_outbound_connection(
|
||||
&mut self,
|
||||
connection_id: ConnectionId,
|
||||
peer: PeerId,
|
||||
addr: &Multiaddr,
|
||||
_: Endpoint,
|
||||
) -> Result<THandler<Self>, ConnectionDenied> {
|
||||
if addr.is_relayed() {
|
||||
return Ok(Either::Right(dummy::ConnectionHandler));
|
||||
}
|
||||
|
||||
let mut handler = Handler::new(self.local_peer_id, peer, addr.clone());
|
||||
|
||||
if let Some(event) = self.pending_handler_commands.remove(&connection_id) {
|
||||
handler.on_behaviour_event(event)
|
||||
}
|
||||
|
||||
Ok(Either::Left(handler))
|
||||
}
|
||||
|
||||
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
|
||||
|
@ -29,14 +29,14 @@ use futures::stream::{FuturesUnordered, StreamExt};
|
||||
use futures_timer::Delay;
|
||||
use instant::Instant;
|
||||
use libp2p_core::multiaddr::Protocol;
|
||||
use libp2p_core::{upgrade, ConnectedPoint, Multiaddr, PeerId};
|
||||
use libp2p_core::{upgrade, Multiaddr, PeerId};
|
||||
use libp2p_swarm::handler::{
|
||||
ConnectionEvent, DialUpgradeError, FullyNegotiatedInbound, FullyNegotiatedOutbound,
|
||||
ListenUpgradeError, SendWrapper,
|
||||
ListenUpgradeError,
|
||||
};
|
||||
use libp2p_swarm::{
|
||||
dummy, ConnectionHandler, ConnectionHandlerEvent, ConnectionHandlerUpgrErr,
|
||||
IntoConnectionHandler, KeepAlive, SubstreamProtocol,
|
||||
ConnectionHandler, ConnectionHandlerEvent, ConnectionHandlerUpgrErr, KeepAlive,
|
||||
SubstreamProtocol,
|
||||
};
|
||||
use log::debug;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
@ -109,56 +109,6 @@ pub enum Event {
|
||||
},
|
||||
}
|
||||
|
||||
pub struct Prototype {
|
||||
local_peer_id: PeerId,
|
||||
/// Initial [`In`] event from [`super::Behaviour`] provided at creation time.
|
||||
initial_in: Option<In>,
|
||||
}
|
||||
|
||||
impl Prototype {
|
||||
pub(crate) fn new(local_peer_id: PeerId, initial_in: Option<In>) -> Self {
|
||||
Self {
|
||||
local_peer_id,
|
||||
initial_in,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoConnectionHandler for Prototype {
|
||||
type Handler = Either<Handler, dummy::ConnectionHandler>;
|
||||
|
||||
fn into_handler(self, remote_peer_id: &PeerId, endpoint: &ConnectedPoint) -> Self::Handler {
|
||||
if endpoint.is_relayed() {
|
||||
if let Some(event) = self.initial_in {
|
||||
debug!(
|
||||
"Established relayed instead of direct connection to {:?}, \
|
||||
dropping initial in event {:?}.",
|
||||
remote_peer_id, event
|
||||
);
|
||||
}
|
||||
|
||||
// Deny all substreams on relayed connection.
|
||||
Either::Right(dummy::ConnectionHandler)
|
||||
} else {
|
||||
let mut handler = Handler::new(
|
||||
self.local_peer_id,
|
||||
*remote_peer_id,
|
||||
endpoint.get_remote_address().clone(),
|
||||
);
|
||||
|
||||
if let Some(event) = self.initial_in {
|
||||
handler.on_behaviour_event(event)
|
||||
}
|
||||
|
||||
Either::Left(handler)
|
||||
}
|
||||
}
|
||||
|
||||
fn inbound_protocol(&self) -> <Self::Handler as ConnectionHandler>::InboundProtocol {
|
||||
Either::Left(SendWrapper(inbound_stop::Upgrade {}))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Handler {
|
||||
local_peer_id: PeerId,
|
||||
remote_peer_id: PeerId,
|
||||
@ -205,7 +155,7 @@ pub struct Handler {
|
||||
}
|
||||
|
||||
impl Handler {
|
||||
fn new(local_peer_id: PeerId, remote_peer_id: PeerId, remote_addr: Multiaddr) -> Self {
|
||||
pub fn new(local_peer_id: PeerId, remote_peer_id: PeerId, remote_addr: Multiaddr) -> Self {
|
||||
Self {
|
||||
local_peer_id,
|
||||
remote_peer_id,
|
||||
|
@ -19,6 +19,7 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use crate::multiaddr_ext::MultiaddrExt;
|
||||
use crate::priv_client::Connection;
|
||||
use crate::RequestId;
|
||||
use futures::channel::mpsc;
|
||||
@ -247,7 +248,7 @@ struct RelayedMultiaddr {
|
||||
|
||||
/// Parse a [`Multiaddr`] containing a [`Protocol::P2pCircuit`].
|
||||
fn parse_relayed_multiaddr(addr: Multiaddr) -> Result<RelayedMultiaddr, TransportError<Error>> {
|
||||
if !addr.iter().any(|p| matches!(p, Protocol::P2pCircuit)) {
|
||||
if !addr.is_relayed() {
|
||||
return Err(TransportError::MultiaddrNotSupported(addr));
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user