libp2p_swarm/
behaviour.rs

1// Copyright 2019 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21mod either;
22mod external_addresses;
23mod listen_addresses;
24mod peer_addresses;
25pub mod toggle;
26
27pub use external_addresses::ExternalAddresses;
28pub use listen_addresses::ListenAddresses;
29pub use peer_addresses::PeerAddresses;
30
31use crate::connection::ConnectionId;
32use crate::dial_opts::DialOpts;
33use crate::listen_opts::ListenOpts;
34use crate::{
35    ConnectionDenied, ConnectionHandler, DialError, ListenError, THandler, THandlerInEvent,
36    THandlerOutEvent,
37};
38use libp2p_core::{transport::ListenerId, ConnectedPoint, Endpoint, Multiaddr};
39use libp2p_identity::PeerId;
40use std::{task::Context, task::Poll};
41
42/// A [`NetworkBehaviour`] defines the behaviour of the local node on the network.
43///
44/// In contrast to [`Transport`](libp2p_core::Transport) which defines **how** to send bytes on the
45/// network, [`NetworkBehaviour`] defines **what** bytes to send and **to whom**.
46///
47/// Each protocol (e.g. `libp2p-ping`, `libp2p-identify` or `libp2p-kad`) implements
48/// [`NetworkBehaviour`]. Multiple implementations of [`NetworkBehaviour`] can be composed into a
49/// hierarchy of [`NetworkBehaviour`]s where parent implementations delegate to child
50/// implementations. Finally the root of the [`NetworkBehaviour`] hierarchy is passed to
51/// [`Swarm`](crate::Swarm) where it can then control the behaviour of the local node on a libp2p
52/// network.
53///
54/// # Hierarchy of [`NetworkBehaviour`]
55///
56/// To compose multiple [`NetworkBehaviour`] implementations into a single [`NetworkBehaviour`]
57/// implementation, potentially building a multi-level hierarchy of [`NetworkBehaviour`]s, one can
58/// use one of the [`NetworkBehaviour`] combinators, and/or use the [`NetworkBehaviour`] derive
59/// macro.
60///
61/// ## Combinators
62///
63/// [`NetworkBehaviour`] combinators wrap one or more [`NetworkBehaviour`] implementations and
64/// implement [`NetworkBehaviour`] themselves. Example is the
65/// [`Toggle`](crate::behaviour::toggle::Toggle) [`NetworkBehaviour`].
66///
67/// ``` rust
68/// # use libp2p_swarm::dummy;
69/// # use libp2p_swarm::behaviour::toggle::Toggle;
70/// let my_behaviour = dummy::Behaviour;
71/// let my_toggled_behaviour = Toggle::from(Some(my_behaviour));
72/// ```
73///
74/// ## Custom [`NetworkBehaviour`] with the Derive Macro
75///
76/// One can derive [`NetworkBehaviour`] for a custom `struct` via the `#[derive(NetworkBehaviour)]`
77/// proc macro re-exported by the `libp2p` crate. The macro generates a delegating `trait`
78/// implementation for the custom `struct`. Each [`NetworkBehaviour`] trait method is simply
79/// delegated to each `struct` member in the order the `struct` is defined. For example for
80/// [`NetworkBehaviour::poll`] it will first poll the first `struct` member until it returns
81/// [`Poll::Pending`] before moving on to later members.
82///
83/// Events ([`NetworkBehaviour::ToSwarm`]) returned by each `struct` member are wrapped in a new
84/// `enum` event, with an `enum` variant for each `struct` member. Users can define this event
85/// `enum` themselves and provide the name to the derive macro via `#[behaviour(to_swarm =
86/// "MyCustomOutEvent")]`. If the user does not specify an `to_swarm`, the derive macro generates
87/// the event definition itself, naming it `<STRUCT_NAME>Event`.
88///
89/// The aforementioned conversion of each of the event types generated by the struct members to the
90/// custom `to_swarm` is handled by [`From`] implementations which the user needs to define in
91/// addition to the event `enum` itself.
92///
93/// ``` rust
94/// # use libp2p_identify as identify;
95/// # use libp2p_ping as ping;
96/// # use libp2p_swarm_derive::NetworkBehaviour;
97/// #[derive(NetworkBehaviour)]
98/// #[behaviour(to_swarm = "Event")]
99/// # #[behaviour(prelude = "libp2p_swarm::derive_prelude")]
100/// struct MyBehaviour {
101///   identify: identify::Behaviour,
102///   ping: ping::Behaviour,
103/// }
104///
105/// enum Event {
106///   Identify(identify::Event),
107///   Ping(ping::Event),
108/// }
109///
110/// impl From<identify::Event> for Event {
111///   fn from(event: identify::Event) -> Self {
112///     Self::Identify(event)
113///   }
114/// }
115///
116/// impl From<ping::Event> for Event {
117///   fn from(event: ping::Event) -> Self {
118///     Self::Ping(event)
119///   }
120/// }
121/// ```
122pub trait NetworkBehaviour: 'static {
123    /// Handler for all the protocols the network behaviour supports.
124    type ConnectionHandler: ConnectionHandler;
125
126    /// Event generated by the `NetworkBehaviour` and that the swarm will report back.
127    type ToSwarm: Send + 'static;
128
129    /// Callback that is invoked for every new inbound connection.
130    ///
131    /// At this point in the connection lifecycle, only the remote's and our local address are known.
132    /// We have also already allocated a [`ConnectionId`].
133    ///
134    /// Any error returned from this function will immediately abort the dial attempt.
135    fn handle_pending_inbound_connection(
136        &mut self,
137        _connection_id: ConnectionId,
138        _local_addr: &Multiaddr,
139        _remote_addr: &Multiaddr,
140    ) -> Result<(), ConnectionDenied> {
141        Ok(())
142    }
143
144    /// Callback that is invoked for every established inbound connection.
145    ///
146    /// This is invoked once another peer has successfully dialed us.
147    ///
148    /// At this point, we have verified their [`PeerId`] and we know, which particular [`Multiaddr`] succeeded in the dial.
149    /// In order to actually use this connection, this function must return a [`ConnectionHandler`].
150    /// Returning an error will immediately close the connection.
151    fn handle_established_inbound_connection(
152        &mut self,
153        _connection_id: ConnectionId,
154        peer: PeerId,
155        local_addr: &Multiaddr,
156        remote_addr: &Multiaddr,
157    ) -> Result<THandler<Self>, ConnectionDenied>;
158
159    /// Callback that is invoked for every outbound connection attempt.
160    ///
161    /// We have access to:
162    ///
163    /// - The [`PeerId`], if known. Remember that we can dial without a [`PeerId`].
164    /// - All addresses passed to [`DialOpts`] are passed in here too.
165    /// - The effective [`Role`](Endpoint) of this peer in the dial attempt. Typically, this is set to [`Endpoint::Dialer`] except if we are attempting a hole-punch.
166    /// - The [`ConnectionId`] identifying the future connection resulting from this dial, if successful.
167    ///
168    /// Note that the addresses returned from this function are only used for dialing if [`WithPeerIdWithAddresses::extend_addresses_through_behaviour`](crate::dial_opts::WithPeerIdWithAddresses::extend_addresses_through_behaviour) is set.
169    ///
170    /// Any error returned from this function will immediately abort the dial attempt.
171    fn handle_pending_outbound_connection(
172        &mut self,
173        _connection_id: ConnectionId,
174        _maybe_peer: Option<PeerId>,
175        _addresses: &[Multiaddr],
176        _effective_role: Endpoint,
177    ) -> Result<Vec<Multiaddr>, ConnectionDenied> {
178        Ok(vec![])
179    }
180
181    /// Callback that is invoked for every established outbound connection.
182    ///
183    /// This is invoked once we have successfully dialed a peer.
184    /// At this point, we have verified their [`PeerId`] and we know, which particular [`Multiaddr`] succeeded in the dial.
185    /// In order to actually use this connection, this function must return a [`ConnectionHandler`].
186    /// Returning an error will immediately close the connection.
187    fn handle_established_outbound_connection(
188        &mut self,
189        _connection_id: ConnectionId,
190        peer: PeerId,
191        addr: &Multiaddr,
192        role_override: Endpoint,
193    ) -> Result<THandler<Self>, ConnectionDenied>;
194
195    /// Informs the behaviour about an event from the [`Swarm`](crate::Swarm).
196    fn on_swarm_event(&mut self, event: FromSwarm);
197
198    /// Informs the behaviour about an event generated by the [`ConnectionHandler`]
199    /// dedicated to the peer identified by `peer_id`. for the behaviour.
200    ///
201    /// The [`PeerId`] is guaranteed to be in a connected state. In other words,
202    /// [`FromSwarm::ConnectionEstablished`] has previously been received with this [`PeerId`].
203    fn on_connection_handler_event(
204        &mut self,
205        _peer_id: PeerId,
206        _connection_id: ConnectionId,
207        _event: THandlerOutEvent<Self>,
208    );
209
210    /// Polls for things that swarm should do.
211    ///
212    /// This API mimics the API of the `Stream` trait. The method may register the current task in
213    /// order to wake it up at a later point in time.
214    fn poll(&mut self, cx: &mut Context<'_>)
215        -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>>;
216}
217
218/// A command issued from a [`NetworkBehaviour`] for the [`Swarm`].
219///
220/// [`Swarm`]: super::Swarm
221#[derive(Debug)]
222#[non_exhaustive]
223pub enum ToSwarm<TOutEvent, TInEvent> {
224    /// Instructs the `Swarm` to return an event when it is being polled.
225    GenerateEvent(TOutEvent),
226
227    /// Instructs the swarm to start a dial.
228    ///
229    /// On success, [`NetworkBehaviour::on_swarm_event`] with `ConnectionEstablished` is invoked.
230    /// On failure, [`NetworkBehaviour::on_swarm_event`] with `DialFailure` is invoked.
231    ///
232    /// [`DialOpts`] provides access to the [`ConnectionId`] via [`DialOpts::connection_id`].
233    /// This [`ConnectionId`] will be used throughout the connection's lifecycle to associate events with it.
234    /// This allows a [`NetworkBehaviour`] to identify a connection that resulted out of its own dial request.
235    Dial { opts: DialOpts },
236
237    /// Instructs the [`Swarm`](crate::Swarm) to listen on the provided address.
238    ListenOn { opts: ListenOpts },
239
240    /// Instructs the [`Swarm`](crate::Swarm) to remove the listener.
241    RemoveListener { id: ListenerId },
242
243    /// Instructs the `Swarm` to send an event to the handler dedicated to a
244    /// connection with a peer.
245    ///
246    /// If the `Swarm` is connected to the peer, the message is delivered to the [`ConnectionHandler`]
247    /// instance identified by the peer ID and connection ID.
248    ///
249    /// If the specified connection no longer exists, the event is silently dropped.
250    ///
251    /// Typically the connection ID given is the same as the one passed to
252    /// [`NetworkBehaviour::on_connection_handler_event`], i.e. whenever the behaviour wishes to
253    /// respond to a request on the same connection (and possibly the same
254    /// substream, as per the implementation of [`ConnectionHandler`]).
255    ///
256    /// Note that even if the peer is currently connected, connections can get closed
257    /// at any time and thus the event may not reach a handler.
258    NotifyHandler {
259        /// The peer for whom a [`ConnectionHandler`] should be notified.
260        peer_id: PeerId,
261        /// The options w.r.t. which connection handler to notify of the event.
262        handler: NotifyHandler,
263        /// The event to send.
264        event: TInEvent,
265    },
266
267    /// Reports a **new** candidate for an external address to the [`Swarm`](crate::Swarm).
268    ///
269    /// The emphasis on a **new** candidate is important.
270    /// Protocols MUST take care to only emit a candidate once per "source".
271    /// For example, the observed address of a TCP connection does not change throughout its lifetime.
272    /// Thus, only one candidate should be emitted per connection.    
273    ///
274    /// This makes the report frequency of an address a meaningful data-point for consumers of this event.
275    /// This address will be shared with all [`NetworkBehaviour`]s via [`FromSwarm::NewExternalAddrCandidate`].
276    ///
277    /// This address could come from a variety of sources:
278    /// - A protocol such as identify obtained it from a remote.
279    /// - The user provided it based on configuration.
280    /// - We made an educated guess based on one of our listen addresses.
281    NewExternalAddrCandidate(Multiaddr),
282
283    /// Indicates to the [`Swarm`](crate::Swarm) that the provided address is confirmed to be externally reachable.
284    ///
285    /// This is intended to be issued in response to a [`FromSwarm::NewExternalAddrCandidate`] if we are indeed externally reachable on this address.
286    /// This address will be shared with all [`NetworkBehaviour`]s via [`FromSwarm::ExternalAddrConfirmed`].
287    ExternalAddrConfirmed(Multiaddr),
288
289    /// Indicates to the [`Swarm`](crate::Swarm) that we are no longer externally reachable under the provided address.
290    ///
291    /// This expires an address that was earlier confirmed via [`ToSwarm::ExternalAddrConfirmed`].
292    /// This address will be shared with all [`NetworkBehaviour`]s via [`FromSwarm::ExternalAddrExpired`].
293    ExternalAddrExpired(Multiaddr),
294
295    /// Instructs the `Swarm` to initiate a graceful close of one or all connections with the given peer.
296    ///
297    /// Closing a connection via [`ToSwarm::CloseConnection`] will poll [`ConnectionHandler::poll_close`] to completion.
298    /// In most cases, stopping to "use" a connection is enough to have it closed.
299    /// The keep-alive algorithm will close a connection automatically once all [`ConnectionHandler`]s are idle.
300    ///
301    /// Use this command if you want to close a connection _despite_ it still being in use by one or more handlers.
302    CloseConnection {
303        /// The peer to disconnect.
304        peer_id: PeerId,
305        /// Whether to close a specific or all connections to the given peer.
306        connection: CloseConnection,
307    },
308
309    /// Reports external address of a remote peer to the [`Swarm`](crate::Swarm) and through that to other [`NetworkBehaviour`]s.
310    NewExternalAddrOfPeer { peer_id: PeerId, address: Multiaddr },
311}
312
313impl<TOutEvent, TInEventOld> ToSwarm<TOutEvent, TInEventOld> {
314    /// Map the handler event.
315    pub fn map_in<TInEventNew>(
316        self,
317        f: impl FnOnce(TInEventOld) -> TInEventNew,
318    ) -> ToSwarm<TOutEvent, TInEventNew> {
319        match self {
320            ToSwarm::GenerateEvent(e) => ToSwarm::GenerateEvent(e),
321            ToSwarm::Dial { opts } => ToSwarm::Dial { opts },
322            ToSwarm::ListenOn { opts } => ToSwarm::ListenOn { opts },
323            ToSwarm::RemoveListener { id } => ToSwarm::RemoveListener { id },
324            ToSwarm::NotifyHandler {
325                peer_id,
326                handler,
327                event,
328            } => ToSwarm::NotifyHandler {
329                peer_id,
330                handler,
331                event: f(event),
332            },
333            ToSwarm::CloseConnection {
334                peer_id,
335                connection,
336            } => ToSwarm::CloseConnection {
337                peer_id,
338                connection,
339            },
340            ToSwarm::NewExternalAddrCandidate(addr) => ToSwarm::NewExternalAddrCandidate(addr),
341            ToSwarm::ExternalAddrConfirmed(addr) => ToSwarm::ExternalAddrConfirmed(addr),
342            ToSwarm::ExternalAddrExpired(addr) => ToSwarm::ExternalAddrExpired(addr),
343            ToSwarm::NewExternalAddrOfPeer {
344                address: addr,
345                peer_id,
346            } => ToSwarm::NewExternalAddrOfPeer {
347                address: addr,
348                peer_id,
349            },
350        }
351    }
352}
353
354impl<TOutEvent, THandlerIn> ToSwarm<TOutEvent, THandlerIn> {
355    /// Map the event the swarm will return.
356    pub fn map_out<E>(self, f: impl FnOnce(TOutEvent) -> E) -> ToSwarm<E, THandlerIn> {
357        match self {
358            ToSwarm::GenerateEvent(e) => ToSwarm::GenerateEvent(f(e)),
359            ToSwarm::Dial { opts } => ToSwarm::Dial { opts },
360            ToSwarm::ListenOn { opts } => ToSwarm::ListenOn { opts },
361            ToSwarm::RemoveListener { id } => ToSwarm::RemoveListener { id },
362            ToSwarm::NotifyHandler {
363                peer_id,
364                handler,
365                event,
366            } => ToSwarm::NotifyHandler {
367                peer_id,
368                handler,
369                event,
370            },
371            ToSwarm::NewExternalAddrCandidate(addr) => ToSwarm::NewExternalAddrCandidate(addr),
372            ToSwarm::ExternalAddrConfirmed(addr) => ToSwarm::ExternalAddrConfirmed(addr),
373            ToSwarm::ExternalAddrExpired(addr) => ToSwarm::ExternalAddrExpired(addr),
374            ToSwarm::CloseConnection {
375                peer_id,
376                connection,
377            } => ToSwarm::CloseConnection {
378                peer_id,
379                connection,
380            },
381            ToSwarm::NewExternalAddrOfPeer {
382                address: addr,
383                peer_id,
384            } => ToSwarm::NewExternalAddrOfPeer {
385                address: addr,
386                peer_id,
387            },
388        }
389    }
390}
391
392/// The options w.r.t. which connection handler to notify of an event.
393#[derive(Debug, Clone)]
394pub enum NotifyHandler {
395    /// Notify a particular connection handler.
396    One(ConnectionId),
397    /// Notify an arbitrary connection handler.
398    Any,
399}
400
401/// The options which connections to close.
402#[derive(Debug, Clone, Default)]
403pub enum CloseConnection {
404    /// Disconnect a particular connection.
405    One(ConnectionId),
406    /// Disconnect all connections.
407    #[default]
408    All,
409}
410
411/// Enumeration with the list of the possible events
412/// to pass to [`on_swarm_event`](NetworkBehaviour::on_swarm_event).
413#[derive(Debug, Clone, Copy)]
414#[non_exhaustive]
415pub enum FromSwarm<'a> {
416    /// Informs the behaviour about a newly established connection to a peer.
417    ConnectionEstablished(ConnectionEstablished<'a>),
418    /// Informs the behaviour about a closed connection to a peer.
419    ///
420    /// This event is always paired with an earlier
421    /// [`FromSwarm::ConnectionEstablished`] with the same peer ID, connection ID
422    /// and endpoint.
423    ConnectionClosed(ConnectionClosed<'a>),
424    /// Informs the behaviour that the [`ConnectedPoint`] of an existing
425    /// connection has changed.
426    AddressChange(AddressChange<'a>),
427    /// Informs the behaviour that the dial to a known
428    /// or unknown node failed.
429    DialFailure(DialFailure<'a>),
430    /// Informs the behaviour that an error
431    /// happened on an incoming connection during its initial handshake.
432    ///
433    /// This can include, for example, an error during the handshake of the encryption layer, or the
434    /// connection unexpectedly closed.
435    ListenFailure(ListenFailure<'a>),
436    /// Informs the behaviour that a new listener was created.
437    NewListener(NewListener),
438    /// Informs the behaviour that we have started listening on a new multiaddr.
439    NewListenAddr(NewListenAddr<'a>),
440    /// Informs the behaviour that a multiaddr
441    /// we were listening on has expired,
442    /// which means that we are no longer listening on it.
443    ExpiredListenAddr(ExpiredListenAddr<'a>),
444    /// Informs the behaviour that a listener experienced an error.
445    ListenerError(ListenerError<'a>),
446    /// Informs the behaviour that a listener closed.
447    ListenerClosed(ListenerClosed<'a>),
448    /// Informs the behaviour that we have discovered a new candidate for an external address for us.
449    NewExternalAddrCandidate(NewExternalAddrCandidate<'a>),
450    /// Informs the behaviour that an external address of the local node was confirmed.
451    ExternalAddrConfirmed(ExternalAddrConfirmed<'a>),
452    /// Informs the behaviour that an external address of the local node expired, i.e. is no-longer confirmed.
453    ExternalAddrExpired(ExternalAddrExpired<'a>),
454    /// Informs the behaviour that we have discovered a new external address for a remote peer.
455    NewExternalAddrOfPeer(NewExternalAddrOfPeer<'a>),
456}
457
458/// [`FromSwarm`] variant that informs the behaviour about a newly established connection to a peer.
459#[derive(Debug, Clone, Copy)]
460pub struct ConnectionEstablished<'a> {
461    pub peer_id: PeerId,
462    pub connection_id: ConnectionId,
463    pub endpoint: &'a ConnectedPoint,
464    pub failed_addresses: &'a [Multiaddr],
465    pub other_established: usize,
466}
467
468/// [`FromSwarm`] variant that informs the behaviour about a closed connection to a peer.
469///
470/// This event is always paired with an earlier
471/// [`FromSwarm::ConnectionEstablished`] with the same peer ID, connection ID
472/// and endpoint.
473#[derive(Debug, Clone, Copy)]
474pub struct ConnectionClosed<'a> {
475    pub peer_id: PeerId,
476    pub connection_id: ConnectionId,
477    pub endpoint: &'a ConnectedPoint,
478    pub remaining_established: usize,
479}
480
481/// [`FromSwarm`] variant that informs the behaviour that the [`ConnectedPoint`] of an existing
482/// connection has changed.
483#[derive(Debug, Clone, Copy)]
484pub struct AddressChange<'a> {
485    pub peer_id: PeerId,
486    pub connection_id: ConnectionId,
487    pub old: &'a ConnectedPoint,
488    pub new: &'a ConnectedPoint,
489}
490
491/// [`FromSwarm`] variant that informs the behaviour that the dial to a known
492/// or unknown node failed.
493#[derive(Debug, Clone, Copy)]
494pub struct DialFailure<'a> {
495    pub peer_id: Option<PeerId>,
496    pub error: &'a DialError,
497    pub connection_id: ConnectionId,
498}
499
500/// [`FromSwarm`] variant that informs the behaviour that an error
501/// happened on an incoming connection during its initial handshake.
502///
503/// This can include, for example, an error during the handshake of the encryption layer, or the
504/// connection unexpectedly closed.
505#[derive(Debug, Clone, Copy)]
506pub struct ListenFailure<'a> {
507    pub local_addr: &'a Multiaddr,
508    pub send_back_addr: &'a Multiaddr,
509    pub error: &'a ListenError,
510    pub connection_id: ConnectionId,
511}
512
513/// [`FromSwarm`] variant that informs the behaviour that a new listener was created.
514#[derive(Debug, Clone, Copy)]
515pub struct NewListener {
516    pub listener_id: ListenerId,
517}
518
519/// [`FromSwarm`] variant that informs the behaviour
520/// that we have started listening on a new multiaddr.
521#[derive(Debug, Clone, Copy)]
522pub struct NewListenAddr<'a> {
523    pub listener_id: ListenerId,
524    pub addr: &'a Multiaddr,
525}
526
527/// [`FromSwarm`] variant that informs the behaviour that a multiaddr
528/// we were listening on has expired,
529/// which means that we are no longer listening on it.
530#[derive(Debug, Clone, Copy)]
531pub struct ExpiredListenAddr<'a> {
532    pub listener_id: ListenerId,
533    pub addr: &'a Multiaddr,
534}
535
536/// [`FromSwarm`] variant that informs the behaviour that a listener experienced an error.
537#[derive(Debug, Clone, Copy)]
538pub struct ListenerError<'a> {
539    pub listener_id: ListenerId,
540    pub err: &'a (dyn std::error::Error + 'static),
541}
542
543/// [`FromSwarm`] variant that informs the behaviour that a listener closed.
544#[derive(Debug, Clone, Copy)]
545pub struct ListenerClosed<'a> {
546    pub listener_id: ListenerId,
547    pub reason: Result<(), &'a std::io::Error>,
548}
549
550/// [`FromSwarm`] variant that informs the behaviour about a new candidate for an external address for us.
551#[derive(Debug, Clone, Copy)]
552pub struct NewExternalAddrCandidate<'a> {
553    pub addr: &'a Multiaddr,
554}
555
556/// [`FromSwarm`] variant that informs the behaviour that an external address was confirmed.
557#[derive(Debug, Clone, Copy)]
558pub struct ExternalAddrConfirmed<'a> {
559    pub addr: &'a Multiaddr,
560}
561
562/// [`FromSwarm`] variant that informs the behaviour that an external address was removed.
563#[derive(Debug, Clone, Copy)]
564pub struct ExternalAddrExpired<'a> {
565    pub addr: &'a Multiaddr,
566}
567
568/// [`FromSwarm`] variant that informs the behaviour that a new external address for a remote peer was detected.
569#[derive(Clone, Copy, Debug)]
570pub struct NewExternalAddrOfPeer<'a> {
571    pub peer_id: PeerId,
572    pub addr: &'a Multiaddr,
573}