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

feat(swarm): allow NetworkBehaviours to create and remove listeners #3292

Merged
merged 50 commits into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
4f3b233
feat/networkbehaviour: Added ListenOn and RemoveListener
dariusc93 Dec 30, 2022
d7cc720
Merge branch 'master' into networkbehaviour-listen
dariusc93 Mar 4, 2023
14d0c49
Merge branch 'master' into networkbehaviour-listen
dariusc93 Mar 7, 2023
518295d
Merge branch 'master' into networkbehaviour-listen
dariusc93 Mar 9, 2023
f9f50f8
Merge branch 'networkbehaviour-listen' of github.com:dariusc93/rust-l…
dariusc93 May 3, 2023
ed11db4
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 3, 2023
eaff6f0
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 4, 2023
d104545
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 14, 2023
1892fd8
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 14, 2023
ee4cf30
chore: Use ListenerId in `ToSwarm::ListenOn`
dariusc93 May 14, 2023
a5331cb
Update swarm-derive/src/lib.rs
dariusc93 May 14, 2023
ced5bb0
Update swarm/src/behaviour.rs
dariusc93 May 14, 2023
9d2db40
Update swarm/src/behaviour.rs
dariusc93 May 14, 2023
b26f4fc
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 14, 2023
84895ef
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 15, 2023
ad8856e
chore: Send ListenerError to behaviour
dariusc93 May 15, 2023
df1a19c
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 15, 2023
ec128ac
Update swarm/src/behaviour.rs
thomaseizinger May 15, 2023
97be0c6
chore: Update CHANGELOG.md
dariusc93 May 15, 2023
8cbf386
chore: Update comments
dariusc93 May 15, 2023
6c163a6
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 16, 2023
b326e32
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 23, 2023
0b0f04e
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 24, 2023
ae1089f
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 25, 2023
590f198
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 25, 2023
97ec46d
chore: Return listener error to behaviour
dariusc93 May 25, 2023
48523bf
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 25, 2023
fa64bca
chore: emit event when calling ToSwarm::ListenOn
dariusc93 May 25, 2023
4c9b192
Merge branch 'networkbehaviour-listen' of github.com:dariusc93/rust-l…
dariusc93 May 25, 2023
124a150
chore: Add Swarm::add_listener
dariusc93 May 26, 2023
1f6a798
chore: Add test
dariusc93 May 27, 2023
15fd6e4
chore: Rename test function
dariusc93 May 27, 2023
c8968e0
chore: Formatted code
dariusc93 May 27, 2023
1e40992
chore: Updated test
dariusc93 May 27, 2023
82a9898
Merge branch 'master' into networkbehaviour-listen
dariusc93 May 31, 2023
4d2946d
Merge branch 'master' into networkbehaviour-listen
dariusc93 Jun 2, 2023
d5e36f5
Merge branch 'master' into networkbehaviour-listen
dariusc93 Jun 5, 2023
3e09dc0
Merge branch 'master' into networkbehaviour-listen
dariusc93 Jun 6, 2023
2666615
Merge branch 'master' into networkbehaviour-listen
dariusc93 Jun 6, 2023
95e61ab
chore: Update test
dariusc93 Jun 6, 2023
f880ba2
chore: Move code into add_listener
dariusc93 Jun 6, 2023
7068f12
fix: Move listen on into add_listener
dariusc93 Jun 6, 2023
0bd41ab
chore: Added ListenOpts
dariusc93 Jun 7, 2023
f4c196f
chore: Formatted code
dariusc93 Jun 7, 2023
bc789b2
chore: re-export ListenOpts
dariusc93 Jun 7, 2023
5ea58d1
chore: Updated code
dariusc93 Jun 7, 2023
603933c
chore: Added comment
dariusc93 Jun 7, 2023
08d7659
chore: Formatted code
dariusc93 Jun 7, 2023
92bf3aa
Merge branch 'master' into networkbehaviour-listen
dariusc93 Jun 7, 2023
64d0ad4
Merge branch 'master' into networkbehaviour-listen
dariusc93 Jun 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions swarm-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,12 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> syn::Result<Toke
std::task::Poll::Ready(#network_behaviour_action::Dial { opts }) => {
return std::task::Poll::Ready(#network_behaviour_action::Dial { opts });
}
std::task::Poll::Ready(#network_behaviour_action::ListenOn { id, address }) => {
return std::task::Poll::Ready(#network_behaviour_action::ListenOn { id, address });
}
std::task::Poll::Ready(#network_behaviour_action::RemoveListener { id }) => {
return std::task::Poll::Ready(#network_behaviour_action::RemoveListener { id });
}
std::task::Poll::Ready(#network_behaviour_action::NotifyHandler { peer_id, handler, event }) => {
return std::task::Poll::Ready(#network_behaviour_action::NotifyHandler {
peer_id,
Expand Down
4 changes: 4 additions & 0 deletions swarm/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## 0.43.0 - unreleased

- Allow `NetworkBehaviours` to create and remove listeners.
See [PR 3292].

- Raise MSRV to 1.65.
See [PR 3715].

Expand Down Expand Up @@ -58,6 +61,7 @@

- Remove deprecated items. See [PR 3956].

[PR 3292]: https://github.com/libp2p/rust-libp2p/pull/3292
[PR 3605]: https://github.com/libp2p/rust-libp2p/pull/3605
[PR 3651]: https://github.com/libp2p/rust-libp2p/pull/3651
[PR 3715]: https://github.com/libp2p/rust-libp2p/pull/3715
Expand Down
10 changes: 10 additions & 0 deletions swarm/src/behaviour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,12 @@ pub enum ToSwarm<TOutEvent, TInEvent> {
/// This allows a [`NetworkBehaviour`] to identify a connection that resulted out of its own dial request.
Dial { opts: DialOpts },

/// Instructs the [`Swarm`](crate::Swarm) to listen on the provided address.
ListenOn { id: ListenerId, address: Multiaddr },
dariusc93 marked this conversation as resolved.
Show resolved Hide resolved

/// Instructs the [`Swarm`](crate::Swarm) to remove the listener.
RemoveListener { id: ListenerId },

/// Instructs the `Swarm` to send an event to the handler dedicated to a
/// connection with a peer.
///
Expand Down Expand Up @@ -324,6 +330,8 @@ impl<TOutEvent, TInEventOld> ToSwarm<TOutEvent, TInEventOld> {
match self {
ToSwarm::GenerateEvent(e) => ToSwarm::GenerateEvent(e),
ToSwarm::Dial { opts } => ToSwarm::Dial { opts },
ToSwarm::ListenOn { id, address } => ToSwarm::ListenOn { id, address },
ToSwarm::RemoveListener { id } => ToSwarm::RemoveListener { id },
ToSwarm::NotifyHandler {
peer_id,
handler,
Expand Down Expand Up @@ -353,6 +361,8 @@ impl<TOutEvent, THandlerIn> ToSwarm<TOutEvent, THandlerIn> {
match self {
ToSwarm::GenerateEvent(e) => ToSwarm::GenerateEvent(f(e)),
ToSwarm::Dial { opts } => ToSwarm::Dial { opts },
ToSwarm::ListenOn { id, address } => ToSwarm::ListenOn { id, address },
ToSwarm::RemoveListener { id } => ToSwarm::RemoveListener { id },
ToSwarm::NotifyHandler {
peer_id,
handler,
Expand Down
39 changes: 34 additions & 5 deletions swarm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,11 +372,17 @@ where
/// Depending on the underlying transport, one listener may have multiple listening addresses.
pub fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<io::Error>> {
let id = ListenerId::next();
self.transport.listen_on(id, addr)?;
self.behaviour
.on_swarm_event(FromSwarm::NewListener(behaviour::NewListener {
listener_id: id,
}));

if let Err(e) = self.transport.listen_on(id, addr) {
self.behaviour
.on_swarm_event(FromSwarm::ListenerError(behaviour::ListenerError {
listener_id: id,
err: &e,
}));
return Err(e);
}
dariusc93 marked this conversation as resolved.
Show resolved Hide resolved

self.add_listener(id);
Ok(id)
}

Expand Down Expand Up @@ -544,6 +550,14 @@ where
self.confirmed_external_addr.iter()
}

/// TBD
dariusc93 marked this conversation as resolved.
Show resolved Hide resolved
fn add_listener(&mut self, listener_id: ListenerId) {
self.behaviour
.on_swarm_event(FromSwarm::NewListener(behaviour::NewListener {
listener_id,
}));
}

/// Add a **confirmed** external address for the local node.
///
/// This function should only be called with addresses that are guaranteed to be reachable.
Expand Down Expand Up @@ -1016,6 +1030,21 @@ where
});
}
}
ToSwarm::ListenOn { id, address } => {
if let Err(e) = self.transport.listen_on(id, address) {
self.behaviour.on_swarm_event(FromSwarm::ListenerError(
behaviour::ListenerError {
listener_id: id,
err: &e,
},
));
dariusc93 marked this conversation as resolved.
Show resolved Hide resolved
}

self.add_listener(id);
}
ToSwarm::RemoveListener { id } => {
self.remove_listener(id);
}
ToSwarm::NotifyHandler {
peer_id,
handler,
Expand Down
146 changes: 146 additions & 0 deletions swarm/tests/listener.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use std::{
collections::{HashSet, VecDeque},
task::{Context, Poll},
};

use libp2p_core::{multiaddr::Protocol, transport::ListenerId, Endpoint, Multiaddr};
use libp2p_identity::PeerId;
use libp2p_swarm::{
derive_prelude::NewListener, dummy, ConnectionDenied, ConnectionId, FromSwarm, ListenerClosed,
ListenerError, NetworkBehaviour, NewListenAddr, PollParameters, Swarm, SwarmEvent, THandler,
THandlerInEvent, THandlerOutEvent, ToSwarm,
};

use libp2p_swarm_test::SwarmExt;

#[derive(Default)]
struct Behaviour {
events: VecDeque<ToSwarm<<Self as NetworkBehaviour>::ToSwarm, THandlerInEvent<Self>>>,
listeners: HashSet<ListenerId>,
}

impl Behaviour {
pub(crate) fn listen(&mut self, addr: Multiaddr) -> ListenerId {
let listener_id = ListenerId::next();
assert!(!self.listeners.contains(&listener_id));
self.events.push_back(ToSwarm::ListenOn {
id: listener_id,
address: addr,
});

self.listeners.insert(listener_id);

listener_id
}

pub(crate) fn stop_listening(&mut self, id: ListenerId) {
self.events.push_back(ToSwarm::RemoveListener { id });
}
}

impl NetworkBehaviour for Behaviour {
type ConnectionHandler = dummy::ConnectionHandler;
type ToSwarm = void::Void;

fn handle_established_inbound_connection(
&mut self,
_: ConnectionId,
_: PeerId,
_: &Multiaddr,
_: &Multiaddr,
) -> Result<libp2p_swarm::THandler<Self>, ConnectionDenied> {
Ok(dummy::ConnectionHandler)
}

fn handle_established_outbound_connection(
&mut self,
_: ConnectionId,
_: PeerId,
_: &Multiaddr,
_: Endpoint,
) -> Result<THandler<Self>, ConnectionDenied> {
Ok(dummy::ConnectionHandler)
}

fn on_connection_handler_event(
&mut self,
_: PeerId,
_: ConnectionId,
_: THandlerOutEvent<Self>,
) {
}

fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::NewListener(NewListener { listener_id }) => {
assert!(self.listeners.contains(&listener_id));
}
FromSwarm::NewListenAddr(NewListenAddr { listener_id, .. }) => {
assert!(self.listeners.contains(&listener_id));
}
FromSwarm::ListenerError(ListenerError { listener_id, err }) => {
panic!("Error for listener {listener_id:?}: {err}");
}
FromSwarm::ListenerClosed(ListenerClosed {
listener_id,
reason,
}) => {
assert!(self.listeners.contains(&listener_id));
assert!(reason.is_ok());
self.listeners.remove(&listener_id);
assert!(!self.listeners.contains(&listener_id));
}
_ => {}
}
}

fn poll(
&mut self,
_: &mut Context<'_>,
_: &mut impl PollParameters,
) -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>> {
if let Some(event) = self.events.pop_front() {
return Poll::Ready(event);
}

Poll::Pending
}
}

#[async_std::test]
async fn behaviour_listener() {
dariusc93 marked this conversation as resolved.
Show resolved Hide resolved
let mut swarm = Swarm::new_ephemeral(|_| Behaviour::default());
let addr: Multiaddr = Protocol::Memory(0).into();
let id = swarm.behaviour_mut().listen(addr.clone());

let address = swarm
.wait(|e| match e {
SwarmEvent::NewListenAddr {
listener_id,
address,
} => {
assert_eq!(listener_id, id);
Some(address)
}
_ => None,
})
.await;

swarm.behaviour_mut().stop_listening(id);

swarm
.wait(|e| match e {
SwarmEvent::ListenerClosed {
listener_id,
addresses,
reason,
} => {
assert_eq!(listener_id, id);
assert!(addresses.contains(&address));
assert!(reason.is_ok());
Some(())
}
_ => None,
})
.await;
}