Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability for the behaviour to disconnect a peer #2110

Merged
merged 6 commits into from
Jul 2, 2021

Conversation

sergeyboyko0791
Copy link
Contributor

Currently, we use a custom version of the rust-libp2p crate in the https://github.com/KomodoPlatform/atomicDEX-API project that allows us to disconnect peers from the network behaviour.
I would like to propose this functionality to allow the users to build their custom behaviors with the ability to disconnect peers.
Please look at the example of using NetworkBehaviourAction::DisconnectPeer': https://github.com/KomodoPlatform/atomicDEX-API/blob/mm2.1/mm2src/mm2_libp2p/src/adex_ping.rs#L27

  • Add 'NetworkBehaviourAction::DisconnectPeer'
  • Add 'ExpandedSwarm::disconnect_peer_id'
  • Add 'test_swarm_disconnect', 'test_behaviour_disconnect_all', 'test_behaviour_disconnect_one'

* Add 'NetworkBehaviourAction::DisconnectPeer'
* Add 'ExpandedSwarm::disconnect_peer_id'
* Add 'test_swarm_disconnect', 'test_behaviour_disconnect_all', 'test_behaviour_disconnect_one'
Copy link
Contributor

@thomaseizinger thomaseizinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a need for Swarm::disconnect_peer the other day and was surprised that it doesn't exist. I am in favor of this!

Implementation looks good to me, left some minor comments!

DisconnectPeer {
/// The peer to disconnect.
peer_id: PeerId,
/// The ID of the connection whose `ProtocolsHandler` to disconnect.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These docs seems to be slightly off given that DisconnectPeerHandler is not just the ID.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thank you!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// The ID of the connection whose `ProtocolsHandler` to disconnect.
/// Whether to close a specific or all connections to the given peer.


/// The options which connection handlers to disconnect.
#[derive(Debug, Clone)]
pub enum DisconnectPeerHandler {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs mention the term Options, maybe DisconnectOptions is a better name for this?

I'd also agree to DisconnectPeer but DisconnectPeerHandler is a bit weird. In the end, we are disconnecting the actual peer, not the handler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose someone would like to disconnect a specified connection by its ConnectionId. DisconnectPeer may confuse in this case.

In the end, we are disconnecting the actual peer, not the handler.

I tried to follow the style of naming structures and enumerations that you follow :)
For example, here.

The docs mention the term Options, maybe DisconnectOptions is a better name for this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to follow the style of naming structures and enumerations that you follow :)

I did see that and thought you would have been inspired by NotifyHandler :)

What about CloseConnection::{One,All}? That naming would be inline with ProtocolsHandlerEvent::Close although that rename would affect the overall terminology used in PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be in favor of calling both the NetworkBehaviourAction CloseConnection (see my comment above) and this struct CloseConnection.

Copy link
Member

@mxinden mxinden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First off, thanks @sergeyboyko0791 for the extensive pull request.

In general, I am not opposed to these changes.

I would like to use this opportunity to give users more guidance on which mechanism to use, now that we are adding yet another one. I guess guidance would be best given via additional documentation.

Today, as a user of libp2p-swarm, I see two ways to close a connection to a peer:

  1. Via ProtocolsHandler::keep_alive in a collaborative manner across protocol handlers.
  2. Via ProtocolsHandlerEvent::Close in a direct manner, instantly closing the connection whether used by other handlers or not.

Being able to close a connection from a NetworkBehaviour by emitting a NetworkBehaviourAction is a shortcut for (1). While I see this to be useful for people wanting to implement a Connection Manager via a NetworkBehaviour, I don't think this non-collaborative style of closing connections is suitable for other protocols like libp2p-kad or libp2p-gossipsub.

Now, in order to be able to give users guidance on which mechanism to use when, I would like to understand your use-case @sergeyboyko0791. Would you mind expanding on why you need to close a connection from a NetworkBehaviour?

I had a need for Swarm::disconnect_peer the other day and was surprised that it doesn't exist. I am in favor of this!

To get more data points, would you mind expanding on your use-case as well @thomaseizinger?

Please look at the example of using NetworkBehaviourAction::DisconnectPeer': https://github.com/KomodoPlatform/atomicDEX-API/blob/mm2.1/mm2src/mm2_libp2p/src/adex_ping.rs#L27

With the default PingConfig, libp2p-ping should close the connection on the second failure. Is that not the case for you? If so, would you mind either debugging this yourself or providing a reproducer?

Comment on lines 297 to 299
/// Instructs the `Swarm` to initiate a graceful close of the connection
/// with a peer.
DisconnectPeer {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Instructs the `Swarm` to initiate a graceful close of the connection
/// with a peer.
DisconnectPeer {
/// Instructs the `Swarm` to initiate a graceful close of one or all connections
/// with the given peer.
CloseConnection {

This naming would be more intuitive to me. What do you think @sergeyboyko0791?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with you and @thomaseizinger


/// The options which connection handlers to disconnect.
#[derive(Debug, Clone)]
pub enum DisconnectPeerHandler {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be in favor of calling both the NetworkBehaviourAction CloseConnection (see my comment above) and this struct CloseConnection.

swarm/src/lib.rs Outdated
@@ -463,6 +464,18 @@ where TBehaviour: NetworkBehaviour<ProtocolsHandler = THandler>,
self.banned_peers.remove(&peer_id);
}

/// Disconnects a peer by its peer ID.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Disconnects a peer by its peer ID.
/// Disconnects a peer by its peer ID, closing all connections to said peer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 394 to 396
/// Disconnect a particular connection handler.
One(ConnectionId),
/// Disconnect all connection handlers.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Disconnect a particular connection handler.
One(ConnectionId),
/// Disconnect all connection handlers.
/// Disconnect a particular connection.
One(ConnectionId),
/// Disconnect all connections.

Your changes closes the connection. The handler is not actively being closed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thanks!

@thomaseizinger
Copy link
Contributor

To get more data points, would you mind expanding on your use-case as well @thomaseizinger?

My usecase were the examples for the rendezvous protocol. I wanted to showcase an application that:

  • connects to a rendezvous point
  • registers with the rendezvous point
  • disconnects from it
  • waits for incoming connections from other peers

To do this, I wanted an API on ExpandedSwarm analogous to dial_{peer, address} where I can disconnect from a specific peer.

For what it is worth, I think neither of the two existing approaches work very well here because the decision to disconnect is made on an application level. The individual NetworkBehaviours don't have enough knowledge to handle this.

@sergeyboyko0791
Copy link
Contributor Author

Hi @mxinden, thanks for your reply and suggestions.

With the default PingConfig, libp2p-ping should close the connection on the second failure. Is that not the case for you? If so, would you mind either debugging this yourself or providing a reproducer?

To be honest, I have not completely figured out how Ping works, and now I agree that it's not the use case to disconnect a peer manually from the behaviour.

Would you mind expanding on why you need to close a connection from a NetworkBehaviour?

We have one more example where we disconnect a peer using ExpandedSwarm::disconnect_peer_id instead of NetworkBehaviourAction::DisconnectPeer, but this logic can be moved to a behaviour:

We maintain the max number of connected relays regarding the GossipsubConfig::mesh_n_high value on every swarm poll. In theory, if this value was decreased externally (for example, on SIGHUP), we have to disconnect the extra relays.

Please, look at this.

* Rename 'NetworkBehaviourAction::DisconnectPeer' to 'NetworkBehaviourAction::CloseConnection'
* Rename `DisconnectPeerHandler` to `CloseConnection`
@sergeyboyko0791
Copy link
Contributor Author

I've pushed the changes you requested. Could you please review it again?
cc @thomaseizinger @mxinden

@mxinden
Copy link
Member

mxinden commented Jun 30, 2021

I've pushed the changes you requested. Could you please review it again?
cc @thomaseizinger @mxinden

Thanks. I will take a look likely later today.

Copy link
Member

@mxinden mxinden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for writing test cases for each of the 3 new ways to disconnect a peer! Very much appreciated @sergeyboyko0791.

I have a couple smaller suggestions around documentation, in order to guide users. What do you think?

Also, could you please apply the diff below adding a changelog entry:

diff --git a/swarm/CHANGELOG.md b/swarm/CHANGELOG.md
index 103f88d2..0f01b314 100644
--- a/swarm/CHANGELOG.md
+++ b/swarm/CHANGELOG.md
@@ -15,7 +15,12 @@
 
   See [PR 2100] for details.
 
+- Add `ExpandedSwarm::disconnect_peer_id` and
+  `NetworkBehaviourAction::CloseConnection` to close connections to a specific
+  peer via an `ExpandedSwarm` or `NetworkBehaviour`. See [PR 2110] for details.
+
 [PR 2100]: https://github.com/libp2p/rust-libp2p/pull/2100
+[PR 2110]: https://github.com/libp2p/rust-libp2p/pull/2110/

/// The peer to disconnect.
peer_id: PeerId,
/// The ID of the connection whose `ProtocolsHandler` to disconnect.
handler: CloseConnection,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
handler: CloseConnection,
connection: CloseConnection,

@@ -373,3 +387,18 @@ impl Default for DialPeerCondition {
DialPeerCondition::Disconnected
}
}

/// The options which connection handlers to disconnect.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// The options which connection handlers to disconnect.
/// The options which connections to close.

swarm/src/behaviour.rs Show resolved Hide resolved
DisconnectPeer {
/// The peer to disconnect.
peer_id: PeerId,
/// The ID of the connection whose `ProtocolsHandler` to disconnect.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// The ID of the connection whose `ProtocolsHandler` to disconnect.
/// Whether to close a specific or all connections to the given peer.

swarm/src/lib.rs Outdated
@@ -463,6 +464,18 @@ where TBehaviour: NetworkBehaviour<ProtocolsHandler = THandler>,
self.banned_peers.remove(&peer_id);
}

/// Disconnects a peer by its peer ID, closing all connections to said peer.
///
/// Returns `Ok(())` if a peer with this ID was in the list.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Returns `Ok(())` if a peer with this ID was in the list.
/// Returns `Ok(())` if there was one or more established connections to the peer

swarm/src/lib.rs Outdated
}))
}

/// Establishes a number of connections between two peers,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Establishes a number of connections between two peers,
/// Establishes multiple connections between two peers,

swarm/src/lib.rs Outdated

/// Establishes a number of connections between two peers,
/// after which one peer disconnects the other
/// using [`NetworkBehaviourAction::CloseConnection`] thrown from a behaviour.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// using [`NetworkBehaviourAction::CloseConnection`] thrown from a behaviour.
/// using [`NetworkBehaviourAction::CloseConnection`] returned by a [`NetworkBehaviour`].

swarm/src/lib.rs Outdated
@@ -1256,4 +1455,83 @@ mod tests {
}
}))
}

/// Establishes a number of connections between two peers,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Establishes a number of connections between two peers,
/// Establishes multiple connections between two peers,

swarm/src/lib.rs Outdated

/// Establishes a number of connections between two peers,
/// after which one peer closes the only one connection
/// using [`NetworkBehaviourAction::CloseConnection`] thrown from a behaviour.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// using [`NetworkBehaviourAction::CloseConnection`] thrown from a behaviour.
/// using [`NetworkBehaviourAction::CloseConnection`] returned by a [`NetworkBehaviour`].

swarm/src/lib.rs Outdated
@@ -1256,4 +1455,83 @@ mod tests {
}
}))
}

/// Establishes a number of connections between two peers,
/// after which one peer closes the only one connection
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// after which one peer closes the only one connection
/// after which one peer closes a single connection

* Rename 'NetworkBehaviourAction::CloseConnection::handler' to 'NetworkBehaviourAction::CloseConnection::connection'
@sergeyboyko0791
Copy link
Contributor Author

@mxinden, all done.
I just formatted the comments.
Thanks for the detailed review 🙃

swarm/src/behaviour.rs Outdated Show resolved Hide resolved
swarm/src/behaviour.rs Outdated Show resolved Hide resolved
swarm/src/lib.rs Outdated Show resolved Hide resolved
@sergeyboyko0791
Copy link
Contributor Author

I almost prepared the fix :D

@mxinden mxinden merged commit 4eb0659 into libp2p:master Jul 2, 2021
@sergeyboyko0791
Copy link
Contributor Author

Thank you @mxinden @thomaseizinger for the review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants