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