@@ -73,6 +73,7 @@ pub struct MdnsDiscovery {
7373 #[ allow( dead_code) ]
7474 handle : AbortOnDropHandle < ( ) > ,
7575 sender : mpsc:: Sender < Message > ,
76+ advertise : bool ,
7677 /// When `local_addrs` changes, we re-publish our info.
7778 local_addrs : Watchable < Option < NodeData > > ,
7879}
@@ -127,39 +128,73 @@ impl Subscribers {
127128
128129/// Builder for [`MdnsDiscovery`].
129130#[ derive( Debug ) ]
130- pub struct MdnsDiscoveryBuilder ;
131+ pub struct MdnsDiscoveryBuilder {
132+ advertise : bool ,
133+ }
134+
135+ impl MdnsDiscoveryBuilder {
136+ /// Creates a new [`MdnsDiscoveryBuilder`] with default settings.
137+ pub fn new ( ) -> Self {
138+ Self { advertise : true }
139+ }
140+
141+ /// Sets whether this node should advertise its presence.
142+ ///
143+ /// Default is true.
144+ pub fn advertise ( mut self , advertise : bool ) -> Self {
145+ self . advertise = advertise;
146+ self
147+ }
148+
149+ /// Builds an [`MdnsDiscovery`] instance with the configured settings.
150+ pub fn build ( self , node_id : NodeId ) -> Result < MdnsDiscovery , IntoDiscoveryError > {
151+ MdnsDiscovery :: new ( node_id, self . advertise )
152+ }
153+ }
154+
155+ impl Default for MdnsDiscoveryBuilder {
156+ fn default ( ) -> Self {
157+ Self :: new ( )
158+ }
159+ }
131160
132161impl IntoDiscovery for MdnsDiscoveryBuilder {
133162 fn into_discovery (
134163 self ,
135164 context : & DiscoveryContext ,
136165 ) -> Result < impl Discovery , IntoDiscoveryError > {
137- MdnsDiscovery :: new ( context. node_id ( ) )
166+ self . build ( context. node_id ( ) )
138167 }
139168}
140169
141170impl MdnsDiscovery {
142171 /// Returns a [`MdnsDiscoveryBuilder`] that implements [`IntoDiscovery`].
143172 pub fn builder ( ) -> MdnsDiscoveryBuilder {
144- MdnsDiscoveryBuilder
173+ MdnsDiscoveryBuilder :: new ( )
145174 }
146175
147176 /// Create a new [`MdnsDiscovery`] Service.
148177 ///
149- /// This starts a [`Discoverer`] that broadcasts your addresses and receives addresses from other nodes in your local network.
178+ /// This starts a [`Discoverer`] that broadcasts your addresses (if advertise is set to true)
179+ /// and receives addresses from other nodes in your local network.
150180 ///
151181 /// # Errors
152182 /// Returns an error if the network does not allow ipv4 OR ipv6.
153183 ///
154184 /// # Panics
155185 /// This relies on [`tokio::runtime::Handle::current`] and will panic if called outside of the context of a tokio runtime.
156- pub fn new ( node_id : NodeId ) -> Result < Self , IntoDiscoveryError > {
186+ pub fn new ( node_id : NodeId , advertise : bool ) -> Result < Self , IntoDiscoveryError > {
157187 debug ! ( "Creating new MdnsDiscovery service" ) ;
158188 let ( send, mut recv) = mpsc:: channel ( 64 ) ;
159189 let task_sender = send. clone ( ) ;
160190 let rt = tokio:: runtime:: Handle :: current ( ) ;
161- let discovery =
162- MdnsDiscovery :: spawn_discoverer ( node_id, task_sender. clone ( ) , BTreeSet :: new ( ) , & rt) ?;
191+ let discovery = MdnsDiscovery :: spawn_discoverer (
192+ node_id,
193+ advertise,
194+ task_sender. clone ( ) ,
195+ BTreeSet :: new ( ) ,
196+ & rt,
197+ ) ?;
163198
164199 let local_addrs: Watchable < Option < NodeData > > = Watchable :: default ( ) ;
165200 let mut addrs_change = local_addrs. watch ( ) ;
@@ -311,13 +346,15 @@ impl MdnsDiscovery {
311346 let handle = task:: spawn ( discovery_fut. instrument ( info_span ! ( "swarm-discovery.actor" ) ) ) ;
312347 Ok ( Self {
313348 handle : AbortOnDropHandle :: new ( handle) ,
349+ advertise,
314350 sender : send,
315351 local_addrs,
316352 } )
317353 }
318354
319355 fn spawn_discoverer (
320356 node_id : PublicKey ,
357+ advertise : bool ,
321358 sender : mpsc:: Sender < Message > ,
322359 socketaddrs : BTreeSet < SocketAddr > ,
323360 rt : & tokio:: runtime:: Handle ,
@@ -337,15 +374,17 @@ impl MdnsDiscovery {
337374 sender. send ( Message :: Discovery ( node_id, peer) ) . await . ok ( ) ;
338375 } ) ;
339376 } ;
340- let addrs = MdnsDiscovery :: socketaddrs_to_addrs ( & socketaddrs) ;
341377 let node_id_str = data_encoding:: BASE32_NOPAD
342378 . encode ( node_id. as_bytes ( ) )
343379 . to_ascii_lowercase ( ) ;
344380 let mut discoverer = Discoverer :: new_interactive ( N0_LOCAL_SWARM . to_string ( ) , node_id_str)
345381 . with_callback ( callback)
346382 . with_ip_class ( IpClass :: Auto ) ;
347- for addr in addrs {
348- discoverer = discoverer. with_addrs ( addr. 0 , addr. 1 ) ;
383+ if advertise {
384+ let addrs = MdnsDiscovery :: socketaddrs_to_addrs ( & socketaddrs) ;
385+ for addr in addrs {
386+ discoverer = discoverer. with_addrs ( addr. 0 , addr. 1 ) ;
387+ }
349388 }
350389 discoverer
351390 . spawn ( rt)
@@ -406,7 +445,9 @@ impl Discovery for MdnsDiscovery {
406445 }
407446
408447 fn publish ( & self , data : & NodeData ) {
409- self . local_addrs . set ( Some ( data. clone ( ) ) ) . ok ( ) ;
448+ if self . advertise {
449+ self . local_addrs . set ( Some ( data. clone ( ) ) ) . ok ( ) ;
450+ }
410451 }
411452
412453 fn subscribe ( & self ) -> Option < BoxStream < DiscoveryItem > > {
@@ -440,8 +481,10 @@ mod tests {
440481 #[ tokio:: test]
441482 #[ traced_test]
442483 async fn mdns_publish_resolve ( ) -> Result {
443- let ( _, discovery_a) = make_discoverer ( ) ?;
444- let ( node_id_b, discovery_b) = make_discoverer ( ) ?;
484+ // Create discoverer A with advertise=false (only listens)
485+ let ( _, discovery_a) = make_discoverer ( false ) ?;
486+ // Create discoverer B with advertise=true (will broadcast)
487+ let ( node_id_b, discovery_b) = make_discoverer ( true ) ?;
445488
446489 // make addr info for discoverer b
447490 let user_data: UserData = "foobar" . parse ( ) ?;
@@ -477,11 +520,11 @@ mod tests {
477520 let mut node_ids = BTreeSet :: new ( ) ;
478521 let mut discoverers = vec ! [ ] ;
479522
480- let ( _, discovery) = make_discoverer ( ) ?;
523+ let ( _, discovery) = make_discoverer ( false ) ?;
481524 let node_data = NodeData :: new ( None , BTreeSet :: from ( [ "0.0.0.0:11111" . parse ( ) . unwrap ( ) ] ) ) ;
482525
483526 for i in 0 ..num_nodes {
484- let ( node_id, discovery) = make_discoverer ( ) ?;
527+ let ( node_id, discovery) = make_discoverer ( true ) ?;
485528 let user_data: UserData = format ! ( "node{i}" ) . parse ( ) ?;
486529 let node_data = node_data. clone ( ) . with_user_data ( Some ( user_data. clone ( ) ) ) ;
487530 node_ids. insert ( ( node_id, Some ( user_data) ) ) ;
@@ -513,9 +556,38 @@ mod tests {
513556 . context ( "timeout" ) ?
514557 }
515558
516- fn make_discoverer ( ) -> Result < ( PublicKey , MdnsDiscovery ) > {
559+ #[ tokio:: test]
560+ #[ traced_test]
561+ async fn non_advertising_node_not_discovered ( ) -> Result {
562+ let ( _, discovery_a) = make_discoverer ( false ) ?;
563+ let ( node_id_b, discovery_b) = make_discoverer ( false ) ?;
564+
565+ let ( node_id_c, discovery_c) = make_discoverer ( true ) ?;
566+ let node_data_c =
567+ NodeData :: new ( None , BTreeSet :: from ( [ "0.0.0.0:22222" . parse ( ) . unwrap ( ) ] ) ) ;
568+ discovery_c. publish ( & node_data_c) ;
569+
570+ let node_data_b =
571+ NodeData :: new ( None , BTreeSet :: from ( [ "0.0.0.0:11111" . parse ( ) . unwrap ( ) ] ) ) ;
572+ discovery_b. publish ( & node_data_b) ;
573+
574+ let mut stream_c = discovery_a. resolve ( node_id_c) . unwrap ( ) ;
575+ let result_c = tokio:: time:: timeout ( Duration :: from_secs ( 2 ) , stream_c. next ( ) ) . await ;
576+ assert ! ( result_c. is_ok( ) , "Advertising node should be discoverable" ) ;
577+
578+ let mut stream_b = discovery_a. resolve ( node_id_b) . unwrap ( ) ;
579+ let result_b = tokio:: time:: timeout ( Duration :: from_secs ( 2 ) , stream_b. next ( ) ) . await ;
580+ assert ! (
581+ result_b. is_err( ) ,
582+ "Expected timeout since node b isn't advertising"
583+ ) ;
584+
585+ Ok ( ( ) )
586+ }
587+
588+ fn make_discoverer ( advertise : bool ) -> Result < ( PublicKey , MdnsDiscovery ) > {
517589 let node_id = SecretKey :: generate ( rand:: thread_rng ( ) ) . public ( ) ;
518- Ok ( ( node_id, MdnsDiscovery :: new ( node_id) ?) )
590+ Ok ( ( node_id, MdnsDiscovery :: new ( node_id, advertise ) ?) )
519591 }
520592 }
521593}
0 commit comments