7
7
use std:: net:: SocketAddr ;
8
8
use std:: {
9
9
collections:: { BTreeMap , BTreeSet } ,
10
+ future:: Future ,
10
11
net:: IpAddr ,
11
12
sync:: {
12
13
atomic:: { AtomicBool , Ordering } ,
@@ -53,7 +54,7 @@ struct ActiveRelayActor {
53
54
/// Queue to send received relay datagrams on.
54
55
relay_datagrams_recv : Arc < RelayDatagramRecvQueue > ,
55
56
/// Channel on which we receive packets to send to the relay.
56
- relay_datagrams_send : mpsc:: Receiver < RelaySendPacket > ,
57
+ relay_datagrams_send : mpsc:: Receiver < RelaySendItem > ,
57
58
url : RelayUrl ,
58
59
/// Whether or not this is the home relay connection.
59
60
is_home_relay : bool ,
@@ -96,7 +97,7 @@ enum ActiveRelayMessage {
96
97
#[ derive( Debug ) ]
97
98
struct ActiveRelayActorOptions {
98
99
url : RelayUrl ,
99
- relay_datagrams_send : mpsc:: Receiver < RelaySendPacket > ,
100
+ relay_datagrams_send : mpsc:: Receiver < RelaySendItem > ,
100
101
relay_datagrams_recv : Arc < RelayDatagramRecvQueue > ,
101
102
connection_opts : RelayConnectionOptions ,
102
103
}
@@ -205,11 +206,9 @@ impl ActiveRelayActor {
205
206
relay_send_fut. as_mut( ) . set_none( ) ;
206
207
}
207
208
// Only poll for new datagrams if relay_send_fut is not busy.
208
- Some ( msg) = self . relay_datagrams_send. recv( ) , if relay_send_fut. is_none( ) => {
209
- let relay_client = self . relay_client. clone( ) ;
210
- let fut = async move {
211
- relay_client. send( msg. node_id, msg. packet) . await
212
- } ;
209
+ Some ( item) = self . relay_datagrams_send. recv( ) , if relay_send_fut. is_none( ) => {
210
+ debug_assert_eq!( item. url, self . url) ;
211
+ let fut = Self :: send_relay( self . relay_client. clone( ) , item) ;
213
212
relay_send_fut. as_mut( ) . set_future( fut) ;
214
213
inactive_timeout. reset( ) ;
215
214
@@ -299,6 +298,24 @@ impl ActiveRelayActor {
299
298
}
300
299
}
301
300
301
+ async fn send_relay ( relay_client : relay:: client:: Client , item : RelaySendItem ) {
302
+ // When Quinn sends a GSO Transmit magicsock::split_packets will make us receive
303
+ // more than one packet to send in a single call. We join all packets back together
304
+ // and prefix them with a u16 packet size. They then get sent as a single DISCO
305
+ // frame. However this might still be multiple packets when otherwise the maximum
306
+ // packet size for the relay protocol would be exceeded.
307
+ for packet in PacketizeIter :: < _ , MAX_PAYLOAD_SIZE > :: new ( item. remote_node , item. datagrams ) {
308
+ let len = packet. len ( ) ;
309
+ match relay_client. send ( packet. node_id , packet. payload ) . await {
310
+ Ok ( _) => inc_by ! ( MagicsockMetrics , send_relay, len as _) ,
311
+ Err ( err) => {
312
+ warn ! ( "send failed: {err:#}" ) ;
313
+ inc ! ( MagicsockMetrics , send_relay_error) ;
314
+ }
315
+ }
316
+ }
317
+ }
318
+
302
319
async fn handle_relay_msg ( & mut self , msg : Result < ReceivedMessage , ClientError > ) -> ReadResult {
303
320
match msg {
304
321
Err ( err) => {
@@ -407,6 +424,7 @@ pub(super) enum RelayActorMessage {
407
424
SetHome { url : RelayUrl } ,
408
425
}
409
426
427
+ #[ derive( Debug , Clone ) ]
410
428
pub ( super ) struct RelaySendItem {
411
429
/// The destination for the datagrams.
412
430
pub ( super ) remote_node : NodeId ,
@@ -458,6 +476,10 @@ impl RelayActor {
458
476
mut receiver : mpsc:: Receiver < RelayActorMessage > ,
459
477
mut datagram_send_channel : RelayDatagramSendChannelReceiver ,
460
478
) {
479
+ // When this future is present, it is sending pending datagrams to an
480
+ // ActiveRelayActor. We can not process further datagrams during this time.
481
+ let mut datagram_send_fut = std:: pin:: pin!( MaybeFuture :: none( ) ) ;
482
+
461
483
loop {
462
484
tokio:: select! {
463
485
biased;
@@ -482,14 +504,21 @@ impl RelayActor {
482
504
let cancel_token = self . cancel_token. child_token( ) ;
483
505
cancel_token. run_until_cancelled( self . handle_msg( msg) ) . await ;
484
506
}
485
- item = datagram_send_channel. recv( ) => {
507
+ // Only poll for new datagrams if we are not blocked on sending them.
508
+ item = datagram_send_channel. recv( ) , if datagram_send_fut. is_none( ) => {
486
509
let Some ( item) = item else {
487
510
debug!( "Datagram send channel dropped, shutting down." ) ;
488
511
break ;
489
512
} ;
490
- let cancel_token = self . cancel_token. child_token( ) ;
491
- cancel_token. run_until_cancelled( self . send_relay( item) ) . await ;
513
+ let token = self . cancel_token. child_token( ) ;
514
+ if let Some ( Some ( fut) ) = token. run_until_cancelled(
515
+ self . try_send_datagram( item)
516
+ ) . await {
517
+ datagram_send_fut. as_mut( ) . set_future( fut) ;
518
+ }
492
519
}
520
+ // Only poll this future if it is in use.
521
+ _ = & mut datagram_send_fut, if datagram_send_fut. is_some( ) => { }
493
522
}
494
523
}
495
524
@@ -513,34 +542,30 @@ impl RelayActor {
513
542
}
514
543
}
515
544
516
- async fn send_relay ( & mut self , item : RelaySendItem ) {
517
- let RelaySendItem {
518
- remote_node,
519
- url,
520
- datagrams,
521
- } = item;
522
- let total_bytes = datagrams. iter ( ) . map ( |c| c. len ( ) as u64 ) . sum :: < u64 > ( ) ;
523
- trace ! (
524
- %url,
525
- remote_node = %remote_node. fmt_short( ) ,
526
- len = total_bytes,
527
- "sending over relay" ,
528
- ) ;
529
- let handle = self . active_relay_handle_for_node ( & url, & remote_node) . await ;
530
-
531
- // When Quinn sends a GSO Transmit magicsock::split_packets will make us receive
532
- // more than one packet to send in a single call. We join all packets back together
533
- // and prefix them with a u16 packet size. They then get sent as a single DISCO
534
- // frame. However this might still be multiple packets when otherwise the maximum
535
- // packet size for the relay protocol would be exceeded.
536
- for packet in PacketizeIter :: < _ , MAX_PAYLOAD_SIZE > :: new ( remote_node, datagrams) {
537
- let len = packet. len ( ) ;
538
- match handle. datagrams_send_queue . send ( packet) . await {
539
- Ok ( _) => inc_by ! ( MagicsockMetrics , send_relay, len as _) ,
540
- Err ( err) => {
541
- warn ! ( ?url, "send failed: {err:#}" ) ;
542
- inc ! ( MagicsockMetrics , send_relay_error) ;
543
- }
545
+ /// Sends datagrams to the correct [`ActiveRelayActor`], or returns a future.
546
+ ///
547
+ /// If the datagram can not be sent immediately, because the destination channel is
548
+ /// full, a future is returned that will complete once the datagrams have been sent to
549
+ /// the [`ActiveRelayActor`].
550
+ async fn try_send_datagram ( & mut self , item : RelaySendItem ) -> Option < impl Future < Output = ( ) > > {
551
+ let url = item. url . clone ( ) ;
552
+ let handle = self
553
+ . active_relay_handle_for_node ( & item. url , & item. remote_node )
554
+ . await ;
555
+ match handle. datagrams_send_queue . try_send ( item) {
556
+ Ok ( ( ) ) => None ,
557
+ Err ( mpsc:: error:: TrySendError :: Closed ( _) ) => {
558
+ warn ! ( ?url, "Dropped datagram(s): ActiveRelayActor closed." ) ;
559
+ None
560
+ }
561
+ Err ( mpsc:: error:: TrySendError :: Full ( item) ) => {
562
+ let sender = handle. datagrams_send_queue . clone ( ) ;
563
+ let fut = async move {
564
+ if sender. send ( item) . await . is_err ( ) {
565
+ warn ! ( ?url, "Dropped datagram(s): ActiveRelayActor closed." ) ;
566
+ }
567
+ } ;
568
+ Some ( fut)
544
569
}
545
570
}
546
571
}
@@ -740,7 +765,7 @@ impl RelayActor {
740
765
#[ derive( Debug , Clone ) ]
741
766
struct ActiveRelayHandle {
742
767
inbox_addr : mpsc:: Sender < ActiveRelayMessage > ,
743
- datagrams_send_queue : mpsc:: Sender < RelaySendPacket > ,
768
+ datagrams_send_queue : mpsc:: Sender < RelaySendItem > ,
744
769
}
745
770
746
771
/// A packet to send over the relay.
@@ -752,12 +777,12 @@ struct ActiveRelayHandle {
752
777
#[ derive( Debug , PartialEq , Eq ) ]
753
778
struct RelaySendPacket {
754
779
node_id : NodeId ,
755
- packet : Bytes ,
780
+ payload : Bytes ,
756
781
}
757
782
758
783
impl RelaySendPacket {
759
784
fn len ( & self ) -> usize {
760
- self . packet . len ( )
785
+ self . payload . len ( )
761
786
}
762
787
}
763
788
@@ -826,7 +851,7 @@ where
826
851
if !self . buffer . is_empty ( ) {
827
852
Some ( RelaySendPacket {
828
853
node_id : self . node_id ,
829
- packet : self . buffer . split ( ) . freeze ( ) ,
854
+ payload : self . buffer . split ( ) . freeze ( ) ,
830
855
} )
831
856
} else {
832
857
None
@@ -889,6 +914,7 @@ impl Iterator for PacketSplitIter {
889
914
mod tests {
890
915
use futures_lite:: future;
891
916
use iroh_base:: SecretKey ;
917
+ use smallvec:: smallvec;
892
918
use testresult:: TestResult ;
893
919
use tokio_util:: task:: AbortOnDropHandle ;
894
920
@@ -906,7 +932,10 @@ mod tests {
906
932
let iter = PacketizeIter :: < _ , MAX_PACKET_SIZE > :: new ( node_id, single_vec) ;
907
933
let result = iter. collect :: < Vec < _ > > ( ) ;
908
934
assert_eq ! ( 1 , result. len( ) ) ;
909
- assert_eq ! ( & [ 5 , 0 , b'H' , b'e' , b'l' , b'l' , b'o' ] , & result[ 0 ] . packet[ ..] ) ;
935
+ assert_eq ! (
936
+ & [ 5 , 0 , b'H' , b'e' , b'l' , b'l' , b'o' ] ,
937
+ & result[ 0 ] . payload[ ..]
938
+ ) ;
910
939
911
940
let spacer = vec ! [ 0u8 ; MAX_PACKET_SIZE - 10 ] ;
912
941
let multiple_vec = vec ! [ & b"Hello" [ ..] , & spacer, & b"World" [ ..] ] ;
@@ -915,17 +944,20 @@ mod tests {
915
944
assert_eq ! ( 2 , result. len( ) ) ;
916
945
assert_eq ! (
917
946
& [ 5 , 0 , b'H' , b'e' , b'l' , b'l' , b'o' ] ,
918
- & result[ 0 ] . packet[ ..7 ]
947
+ & result[ 0 ] . payload[ ..7 ]
948
+ ) ;
949
+ assert_eq ! (
950
+ & [ 5 , 0 , b'W' , b'o' , b'r' , b'l' , b'd' ] ,
951
+ & result[ 1 ] . payload[ ..]
919
952
) ;
920
- assert_eq ! ( & [ 5 , 0 , b'W' , b'o' , b'r' , b'l' , b'd' ] , & result[ 1 ] . packet[ ..] ) ;
921
953
}
922
954
923
955
/// Starts a new [`ActiveRelayActor`].
924
956
fn start_active_relay_actor (
925
957
secret_key : SecretKey ,
926
958
url : RelayUrl ,
927
959
inbox_rx : mpsc:: Receiver < ActiveRelayMessage > ,
928
- relay_datagrams_send : mpsc:: Receiver < RelaySendPacket > ,
960
+ relay_datagrams_send : mpsc:: Receiver < RelaySendItem > ,
929
961
relay_datagrams_recv : Arc < RelayDatagramRecvQueue > ,
930
962
) -> AbortOnDropHandle < anyhow:: Result < ( ) > > {
931
963
let opts = ActiveRelayActorOptions {
@@ -962,27 +994,30 @@ mod tests {
962
994
let ( inbox_tx, inbox_rx) = mpsc:: channel ( 16 ) ;
963
995
let actor_task = start_active_relay_actor (
964
996
secret_key. clone ( ) ,
965
- relay_url,
997
+ relay_url. clone ( ) ,
966
998
inbox_rx,
967
999
send_datagram_rx,
968
1000
recv_datagram_queue. clone ( ) ,
969
1001
) ;
970
- let echo_task = tokio:: spawn (
1002
+ let echo_task = tokio:: spawn ( {
1003
+ let relay_url = relay_url. clone ( ) ;
971
1004
async move {
972
1005
loop {
973
1006
let datagram = future:: poll_fn ( |cx| recv_datagram_queue. poll_recv ( cx) ) . await ;
974
1007
if let Ok ( recv) = datagram {
975
1008
let RelayRecvDatagram { url : _, src, buf } = recv;
976
1009
info ! ( from = src. fmt_short( ) , "Received datagram" ) ;
977
- let send = PacketizeIter :: < _ , MAX_PAYLOAD_SIZE > :: new ( src, [ buf] )
978
- . next ( )
979
- . unwrap ( ) ;
1010
+ let send = RelaySendItem {
1011
+ remote_node : src,
1012
+ url : relay_url. clone ( ) ,
1013
+ datagrams : smallvec ! [ buf] ,
1014
+ } ;
980
1015
send_datagram_tx. send ( send) . await . ok ( ) ;
981
1016
}
982
1017
}
983
1018
}
984
- . instrument ( info_span ! ( "echo-task" ) ) ,
985
- ) ;
1019
+ . instrument ( info_span ! ( "echo-task" ) )
1020
+ } ) ;
986
1021
let echo_task = AbortOnDropHandle :: new ( echo_task) ;
987
1022
let supervisor_task = tokio:: spawn ( async move {
988
1023
// move the inbox_tx here so it is not dropped, as this stops the actor.
@@ -1009,18 +1044,20 @@ mod tests {
1009
1044
let ( inbox_tx, inbox_rx) = mpsc:: channel ( 16 ) ;
1010
1045
let task = start_active_relay_actor (
1011
1046
secret_key,
1012
- relay_url,
1047
+ relay_url. clone ( ) ,
1013
1048
inbox_rx,
1014
1049
send_datagram_rx,
1015
1050
datagram_recv_queue. clone ( ) ,
1016
1051
) ;
1017
1052
1018
1053
// Send a datagram to our echo node.
1019
1054
info ! ( "first echo" ) ;
1020
- let packet = PacketizeIter :: < _ , MAX_PAYLOAD_SIZE > :: new ( peer_node, [ b"hello" ] )
1021
- . next ( )
1022
- . context ( "no packet" ) ?;
1023
- send_datagram_tx. send ( packet) . await ?;
1055
+ let hello_send_item = RelaySendItem {
1056
+ remote_node : peer_node,
1057
+ url : relay_url. clone ( ) ,
1058
+ datagrams : smallvec ! [ Bytes :: from_static( b"hello" ) ] ,
1059
+ } ;
1060
+ send_datagram_tx. send ( hello_send_item. clone ( ) ) . await ?;
1024
1061
1025
1062
// Check we get it back
1026
1063
let RelayRecvDatagram {
@@ -1047,10 +1084,7 @@ mod tests {
1047
1084
1048
1085
// Echo should still work.
1049
1086
info ! ( "second echo" ) ;
1050
- let packet = PacketizeIter :: < _ , MAX_PAYLOAD_SIZE > :: new ( peer_node, [ b"hello" ] )
1051
- . next ( )
1052
- . context ( "no packet" ) ?;
1053
- send_datagram_tx. send ( packet) . await ?;
1087
+ send_datagram_tx. send ( hello_send_item. clone ( ) ) . await ?;
1054
1088
let recv = future:: poll_fn ( |cx| datagram_recv_queue. poll_recv ( cx) ) . await ?;
1055
1089
assert_eq ! ( recv. buf. as_ref( ) , b"hello" ) ;
1056
1090
@@ -1066,10 +1100,7 @@ mod tests {
1066
1100
1067
1101
// Echo should still work.
1068
1102
info ! ( "third echo" ) ;
1069
- let packet = PacketizeIter :: < _ , MAX_PAYLOAD_SIZE > :: new ( peer_node, [ b"hello" ] )
1070
- . next ( )
1071
- . context ( "no packet" ) ?;
1072
- send_datagram_tx. send ( packet) . await ?;
1103
+ send_datagram_tx. send ( hello_send_item) . await ?;
1073
1104
let recv = future:: poll_fn ( |cx| datagram_recv_queue. poll_recv ( cx) ) . await ?;
1074
1105
assert_eq ! ( recv. buf. as_ref( ) , b"hello" ) ;
1075
1106
0 commit comments