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