@@ -25,7 +25,8 @@ mod timer;
25
25
use self :: iface:: InterfaceState ;
26
26
use crate :: behaviour:: { socket:: AsyncSocket , timer:: Builder } ;
27
27
use crate :: Config ;
28
- use futures:: Stream ;
28
+ use futures:: channel:: mpsc;
29
+ use futures:: { Stream , StreamExt } ;
29
30
use if_watch:: IfEvent ;
30
31
use libp2p_core:: { Endpoint , Multiaddr } ;
31
32
use libp2p_identity:: PeerId ;
@@ -36,6 +37,8 @@ use libp2p_swarm::{
36
37
} ;
37
38
use smallvec:: SmallVec ;
38
39
use std:: collections:: hash_map:: { Entry , HashMap } ;
40
+ use std:: future:: Future ;
41
+ use std:: sync:: { Arc , RwLock } ;
39
42
use std:: { cmp, fmt, io, net:: IpAddr , pin:: Pin , task:: Context , task:: Poll , time:: Instant } ;
40
43
41
44
/// An abstraction to allow for compatibility with various async runtimes.
@@ -47,16 +50,27 @@ pub trait Provider: 'static {
47
50
/// The IfWatcher type.
48
51
type Watcher : Stream < Item = std:: io:: Result < IfEvent > > + fmt:: Debug + Unpin ;
49
52
53
+ type TaskHandle : Abort ;
54
+
50
55
/// Create a new instance of the `IfWatcher` type.
51
56
fn new_watcher ( ) -> Result < Self :: Watcher , std:: io:: Error > ;
57
+
58
+ fn spawn ( task : impl Future < Output = ( ) > + Send + ' static ) -> Self :: TaskHandle ;
59
+ }
60
+
61
+ #[ allow( unreachable_pub) ] // Not re-exported.
62
+ pub trait Abort {
63
+ fn abort ( self ) ;
52
64
}
53
65
54
66
/// The type of a [`Behaviour`] using the `async-io` implementation.
55
67
#[ cfg( feature = "async-io" ) ]
56
68
pub mod async_io {
57
69
use super :: Provider ;
58
- use crate :: behaviour:: { socket:: asio:: AsyncUdpSocket , timer:: asio:: AsyncTimer } ;
70
+ use crate :: behaviour:: { socket:: asio:: AsyncUdpSocket , timer:: asio:: AsyncTimer , Abort } ;
71
+ use async_std:: task:: JoinHandle ;
59
72
use if_watch:: smol:: IfWatcher ;
73
+ use std:: future:: Future ;
60
74
61
75
#[ doc( hidden) ]
62
76
pub enum AsyncIo { }
@@ -65,10 +79,21 @@ pub mod async_io {
65
79
type Socket = AsyncUdpSocket ;
66
80
type Timer = AsyncTimer ;
67
81
type Watcher = IfWatcher ;
82
+ type TaskHandle = JoinHandle < ( ) > ;
68
83
69
84
fn new_watcher ( ) -> Result < Self :: Watcher , std:: io:: Error > {
70
85
IfWatcher :: new ( )
71
86
}
87
+
88
+ fn spawn ( task : impl Future < Output = ( ) > + Send + ' static ) -> JoinHandle < ( ) > {
89
+ async_std:: task:: spawn ( task)
90
+ }
91
+ }
92
+
93
+ impl Abort for JoinHandle < ( ) > {
94
+ fn abort ( self ) {
95
+ async_std:: task:: spawn ( self . cancel ( ) ) ;
96
+ }
72
97
}
73
98
74
99
pub type Behaviour = super :: Behaviour < AsyncIo > ;
@@ -78,8 +103,10 @@ pub mod async_io {
78
103
#[ cfg( feature = "tokio" ) ]
79
104
pub mod tokio {
80
105
use super :: Provider ;
81
- use crate :: behaviour:: { socket:: tokio:: TokioUdpSocket , timer:: tokio:: TokioTimer } ;
106
+ use crate :: behaviour:: { socket:: tokio:: TokioUdpSocket , timer:: tokio:: TokioTimer , Abort } ;
82
107
use if_watch:: tokio:: IfWatcher ;
108
+ use std:: future:: Future ;
109
+ use tokio:: task:: JoinHandle ;
83
110
84
111
#[ doc( hidden) ]
85
112
pub enum Tokio { }
@@ -88,10 +115,21 @@ pub mod tokio {
88
115
type Socket = TokioUdpSocket ;
89
116
type Timer = TokioTimer ;
90
117
type Watcher = IfWatcher ;
118
+ type TaskHandle = JoinHandle < ( ) > ;
91
119
92
120
fn new_watcher ( ) -> Result < Self :: Watcher , std:: io:: Error > {
93
121
IfWatcher :: new ( )
94
122
}
123
+
124
+ fn spawn ( task : impl Future < Output = ( ) > + Send + ' static ) -> Self :: TaskHandle {
125
+ tokio:: spawn ( task)
126
+ }
127
+ }
128
+
129
+ impl Abort for JoinHandle < ( ) > {
130
+ fn abort ( self ) {
131
+ JoinHandle :: abort ( & self )
132
+ }
95
133
}
96
134
97
135
pub type Behaviour = super :: Behaviour < Tokio > ;
@@ -110,8 +148,11 @@ where
110
148
/// Iface watcher.
111
149
if_watch : P :: Watcher ,
112
150
113
- /// Mdns interface states.
114
- iface_states : HashMap < IpAddr , InterfaceState < P :: Socket , P :: Timer > > ,
151
+ /// Handles to tasks running the mDNS queries.
152
+ if_tasks : HashMap < IpAddr , P :: TaskHandle > ,
153
+
154
+ query_response_receiver : mpsc:: Receiver < ( PeerId , Multiaddr , Instant ) > ,
155
+ query_response_sender : mpsc:: Sender < ( PeerId , Multiaddr , Instant ) > ,
115
156
116
157
/// List of nodes that we have discovered, the address, and when their TTL expires.
117
158
///
@@ -124,7 +165,11 @@ where
124
165
/// `None` if `discovered_nodes` is empty.
125
166
closest_expiration : Option < P :: Timer > ,
126
167
127
- listen_addresses : ListenAddresses ,
168
+ /// The current set of listen addresses.
169
+ ///
170
+ /// This is shared across all interface tasks using an [`RwLock`].
171
+ /// The [`Behaviour`] updates this upon new [`FromSwarm`] events where as [`InterfaceState`]s read from it to answer inbound mDNS queries.
172
+ listen_addresses : Arc < RwLock < ListenAddresses > > ,
128
173
129
174
local_peer_id : PeerId ,
130
175
}
@@ -135,10 +180,14 @@ where
135
180
{
136
181
/// Builds a new `Mdns` behaviour.
137
182
pub fn new ( config : Config , local_peer_id : PeerId ) -> io:: Result < Self > {
183
+ let ( tx, rx) = mpsc:: channel ( 10 ) ; // Chosen arbitrarily.
184
+
138
185
Ok ( Self {
139
186
config,
140
187
if_watch : P :: new_watcher ( ) ?,
141
- iface_states : Default :: default ( ) ,
188
+ if_tasks : Default :: default ( ) ,
189
+ query_response_receiver : rx,
190
+ query_response_sender : tx,
142
191
discovered_nodes : Default :: default ( ) ,
143
192
closest_expiration : Default :: default ( ) ,
144
193
listen_addresses : Default :: default ( ) ,
@@ -147,6 +196,7 @@ where
147
196
}
148
197
149
198
/// Returns true if the given `PeerId` is in the list of nodes discovered through mDNS.
199
+ #[ deprecated( note = "Use `discovered_nodes` iterator instead." ) ]
150
200
pub fn has_node ( & self , peer_id : & PeerId ) -> bool {
151
201
self . discovered_nodes ( ) . any ( |p| p == peer_id)
152
202
}
@@ -157,6 +207,7 @@ where
157
207
}
158
208
159
209
/// Expires a node before the ttl.
210
+ #[ deprecated( note = "Unused API. Will be removed in the next release." ) ]
160
211
pub fn expire_node ( & mut self , peer_id : & PeerId ) {
161
212
let now = Instant :: now ( ) ;
162
213
for ( peer, _addr, expires) in & mut self . discovered_nodes {
@@ -225,28 +276,10 @@ where
225
276
}
226
277
227
278
fn on_swarm_event ( & mut self , event : FromSwarm < Self :: ConnectionHandler > ) {
228
- self . listen_addresses . on_swarm_event ( & event) ;
229
-
230
- match event {
231
- FromSwarm :: NewListener ( _) => {
232
- log:: trace!( "waking interface state because listening address changed" ) ;
233
- for iface in self . iface_states . values_mut ( ) {
234
- iface. fire_timer ( ) ;
235
- }
236
- }
237
- FromSwarm :: ConnectionClosed ( _)
238
- | FromSwarm :: ConnectionEstablished ( _)
239
- | FromSwarm :: DialFailure ( _)
240
- | FromSwarm :: AddressChange ( _)
241
- | FromSwarm :: ListenFailure ( _)
242
- | FromSwarm :: NewListenAddr ( _)
243
- | FromSwarm :: ExpiredListenAddr ( _)
244
- | FromSwarm :: ListenerError ( _)
245
- | FromSwarm :: ListenerClosed ( _)
246
- | FromSwarm :: NewExternalAddrCandidate ( _)
247
- | FromSwarm :: ExternalAddrExpired ( _)
248
- | FromSwarm :: ExternalAddrConfirmed ( _) => { }
249
- }
279
+ self . listen_addresses
280
+ . write ( )
281
+ . unwrap_or_else ( |e| e. into_inner ( ) )
282
+ . on_swarm_event ( & event) ;
250
283
}
251
284
252
285
fn poll (
@@ -267,43 +300,50 @@ where
267
300
{
268
301
continue ;
269
302
}
270
- if let Entry :: Vacant ( e) = self . iface_states . entry ( addr) {
271
- match InterfaceState :: new ( addr, self . config . clone ( ) , self . local_peer_id ) {
303
+ if let Entry :: Vacant ( e) = self . if_tasks . entry ( addr) {
304
+ match InterfaceState :: < P :: Socket , P :: Timer > :: new (
305
+ addr,
306
+ self . config . clone ( ) ,
307
+ self . local_peer_id ,
308
+ self . listen_addresses . clone ( ) ,
309
+ self . query_response_sender . clone ( ) ,
310
+ ) {
272
311
Ok ( iface_state) => {
273
- e. insert ( iface_state) ;
312
+ e. insert ( P :: spawn ( iface_state) ) ;
274
313
}
275
314
Err ( err) => log:: error!( "failed to create `InterfaceState`: {}" , err) ,
276
315
}
277
316
}
278
317
}
279
318
Ok ( IfEvent :: Down ( inet) ) => {
280
- if self . iface_states . contains_key ( & inet. addr ( ) ) {
319
+ if let Some ( handle ) = self . if_tasks . remove ( & inet. addr ( ) ) {
281
320
log:: info!( "dropping instance {}" , inet. addr( ) ) ;
282
- self . iface_states . remove ( & inet. addr ( ) ) ;
321
+
322
+ handle. abort ( ) ;
283
323
}
284
324
}
285
325
Err ( err) => log:: error!( "if watch returned an error: {}" , err) ,
286
326
}
287
327
}
288
328
// Emit discovered event.
289
329
let mut discovered = Vec :: new ( ) ;
290
- for iface_state in self . iface_states . values_mut ( ) {
291
- while let Poll :: Ready ( ( peer, addr, expiration) ) =
292
- iface_state. poll ( cx, & self . listen_addresses )
330
+
331
+ while let Poll :: Ready ( Some ( ( peer, addr, expiration) ) ) =
332
+ self . query_response_receiver . poll_next_unpin ( cx)
333
+ {
334
+ if let Some ( ( _, _, cur_expires) ) = self
335
+ . discovered_nodes
336
+ . iter_mut ( )
337
+ . find ( |( p, a, _) | * p == peer && * a == addr)
293
338
{
294
- if let Some ( ( _, _, cur_expires) ) = self
295
- . discovered_nodes
296
- . iter_mut ( )
297
- . find ( |( p, a, _) | * p == peer && * a == addr)
298
- {
299
- * cur_expires = cmp:: max ( * cur_expires, expiration) ;
300
- } else {
301
- log:: info!( "discovered: {} {}" , peer, addr) ;
302
- self . discovered_nodes . push ( ( peer, addr. clone ( ) , expiration) ) ;
303
- discovered. push ( ( peer, addr) ) ;
304
- }
339
+ * cur_expires = cmp:: max ( * cur_expires, expiration) ;
340
+ } else {
341
+ log:: info!( "discovered: {} {}" , peer, addr) ;
342
+ self . discovered_nodes . push ( ( peer, addr. clone ( ) , expiration) ) ;
343
+ discovered. push ( ( peer, addr) ) ;
305
344
}
306
345
}
346
+
307
347
if !discovered. is_empty ( ) {
308
348
let event = Event :: Discovered ( discovered) ;
309
349
return Poll :: Ready ( ToSwarm :: GenerateEvent ( event) ) ;
0 commit comments