@@ -15,7 +15,7 @@ use crate::{
15
15
discovery:: { Discovery , DiscoveryTask } ,
16
16
dns:: { default_resolver, DnsResolver } ,
17
17
key:: { PublicKey , SecretKey } ,
18
- magicsock:: { self , MagicSock } ,
18
+ magicsock:: { self , ConnectionTypeStream , MagicSock } ,
19
19
relay:: { RelayMap , RelayMode , RelayUrl } ,
20
20
tls, NodeId ,
21
21
} ;
@@ -402,6 +402,16 @@ impl MagicEndpoint {
402
402
self . connect ( addr, alpn) . await
403
403
}
404
404
405
+ /// Returns a stream that reports changes in the [`crate::magicsock::ConnectionType`]
406
+ /// for the given `node_id`.
407
+ ///
408
+ /// # Errors
409
+ ///
410
+ /// Will error if we do not have any address information for the given `node_id`
411
+ pub fn conn_type_stream ( & self , node_id : & PublicKey ) -> Result < ConnectionTypeStream > {
412
+ self . msock . conn_type_stream ( node_id)
413
+ }
414
+
405
415
/// Connect to a remote endpoint.
406
416
///
407
417
/// A [`NodeAddr`] is required. It must contain the [`NodeId`] to dial and may also contain a
@@ -630,7 +640,7 @@ mod tests {
630
640
use rand_core:: SeedableRng ;
631
641
use tracing:: { error_span, info, info_span, Instrument } ;
632
642
633
- use crate :: test_utils:: run_relay_server;
643
+ use crate :: { magicsock :: ConnectionType , test_utils:: run_relay_server} ;
634
644
635
645
use super :: * ;
636
646
@@ -971,4 +981,100 @@ mod tests {
971
981
p1_connect. await . unwrap ( ) ;
972
982
p2_connect. await . unwrap ( ) ;
973
983
}
984
+
985
+ #[ tokio:: test]
986
+ async fn magic_endpoint_conn_type_stream ( ) {
987
+ let _logging_guard = iroh_test:: logging:: setup ( ) ;
988
+ let ( relay_map, relay_url, _relay_guard) = run_relay_server ( ) . await . unwrap ( ) ;
989
+ let mut rng = rand_chacha:: ChaCha8Rng :: seed_from_u64 ( 42 ) ;
990
+ let ep1_secret_key = SecretKey :: generate_with_rng ( & mut rng) ;
991
+ let ep2_secret_key = SecretKey :: generate_with_rng ( & mut rng) ;
992
+ let ep1 = MagicEndpoint :: builder ( )
993
+ . secret_key ( ep1_secret_key)
994
+ . insecure_skip_relay_cert_verify ( true )
995
+ . alpns ( vec ! [ TEST_ALPN . to_vec( ) ] )
996
+ . relay_mode ( RelayMode :: Custom ( relay_map. clone ( ) ) )
997
+ . bind ( 0 )
998
+ . await
999
+ . unwrap ( ) ;
1000
+ let ep2 = MagicEndpoint :: builder ( )
1001
+ . secret_key ( ep2_secret_key)
1002
+ . insecure_skip_relay_cert_verify ( true )
1003
+ . alpns ( vec ! [ TEST_ALPN . to_vec( ) ] )
1004
+ . relay_mode ( RelayMode :: Custom ( relay_map) )
1005
+ . bind ( 0 )
1006
+ . await
1007
+ . unwrap ( ) ;
1008
+
1009
+ async fn handle_direct_conn ( ep : MagicEndpoint , node_id : PublicKey ) -> Result < ( ) > {
1010
+ let node_addr = NodeAddr :: new ( node_id) ;
1011
+ ep. add_node_addr ( node_addr) ?;
1012
+ let stream = ep. conn_type_stream ( & node_id) ?;
1013
+ async fn get_direct_event (
1014
+ src : & PublicKey ,
1015
+ dst : & PublicKey ,
1016
+ mut stream : ConnectionTypeStream ,
1017
+ ) -> Result < ( ) > {
1018
+ let src = src. fmt_short ( ) ;
1019
+ let dst = dst. fmt_short ( ) ;
1020
+ while let Some ( conn_type) = stream. next ( ) . await {
1021
+ tracing:: info!( me = %src, dst = %dst, conn_type = ?conn_type) ;
1022
+ if matches ! ( conn_type, ConnectionType :: Direct ( _) ) {
1023
+ return Ok ( ( ) ) ;
1024
+ }
1025
+ }
1026
+ anyhow:: bail!( "conn_type stream ended before `ConnectionType::Direct`" ) ;
1027
+ }
1028
+ tokio:: time:: timeout (
1029
+ Duration :: from_secs ( 15 ) ,
1030
+ get_direct_event ( & ep. node_id ( ) , & node_id, stream) ,
1031
+ )
1032
+ . await ??;
1033
+ Ok ( ( ) )
1034
+ }
1035
+
1036
+ let ep1_nodeid = ep1. node_id ( ) ;
1037
+ let ep2_nodeid = ep2. node_id ( ) ;
1038
+
1039
+ let ep1_nodeaddr = ep1. my_addr ( ) . await . unwrap ( ) ;
1040
+ tracing:: info!(
1041
+ "node id 1 {ep1_nodeid}, relay URL {:?}" ,
1042
+ ep1_nodeaddr. relay_url( )
1043
+ ) ;
1044
+ tracing:: info!( "node id 2 {ep2_nodeid}" ) ;
1045
+
1046
+ let res_ep1 = tokio:: spawn ( handle_direct_conn ( ep1. clone ( ) , ep2_nodeid) ) ;
1047
+
1048
+ let ep1_abort_handle = res_ep1. abort_handle ( ) ;
1049
+ let _ep1_guard = CallOnDrop :: new ( move || {
1050
+ ep1_abort_handle. abort ( ) ;
1051
+ } ) ;
1052
+
1053
+ let res_ep2 = tokio:: spawn ( handle_direct_conn ( ep2. clone ( ) , ep1_nodeid) ) ;
1054
+ let ep2_abort_handle = res_ep2. abort_handle ( ) ;
1055
+ let _ep2_guard = CallOnDrop :: new ( move || {
1056
+ ep2_abort_handle. abort ( ) ;
1057
+ } ) ;
1058
+ async fn accept ( ep : MagicEndpoint ) -> ( PublicKey , String , quinn:: Connection ) {
1059
+ let incoming = ep. accept ( ) . await . unwrap ( ) ;
1060
+ accept_conn ( incoming) . await . unwrap ( )
1061
+ }
1062
+
1063
+ // create a node addr with no direct connections
1064
+ let ep1_nodeaddr = NodeAddr :: from_parts ( ep1_nodeid, Some ( relay_url) , vec ! [ ] ) ;
1065
+
1066
+ let accept_res = tokio:: spawn ( accept ( ep1. clone ( ) ) ) ;
1067
+ let accept_abort_handle = accept_res. abort_handle ( ) ;
1068
+ let _accept_guard = CallOnDrop :: new ( move || {
1069
+ accept_abort_handle. abort ( ) ;
1070
+ } ) ;
1071
+
1072
+ let _conn_2 = ep2. connect ( ep1_nodeaddr, TEST_ALPN ) . await . unwrap ( ) ;
1073
+
1074
+ let ( got_id, _, _conn) = accept_res. await . unwrap ( ) ;
1075
+ assert_eq ! ( ep2_nodeid, got_id) ;
1076
+
1077
+ res_ep1. await . unwrap ( ) . unwrap ( ) ;
1078
+ res_ep2. await . unwrap ( ) . unwrap ( ) ;
1079
+ }
974
1080
}
0 commit comments