@@ -51,7 +51,10 @@ use n0_future::{
51
51
time:: { self , Duration , Instant , MissedTickBehavior } ,
52
52
FuturesUnorderedBounded , SinkExt , StreamExt ,
53
53
} ;
54
- use tokio:: sync:: { mpsc, oneshot} ;
54
+ use tokio:: sync:: {
55
+ mpsc:: { self , OwnedPermit } ,
56
+ oneshot,
57
+ } ;
55
58
use tokio_util:: sync:: CancellationToken ;
56
59
use tracing:: { debug, error, event, info_span, instrument, trace, warn, Instrument , Level } ;
57
60
use url:: Url ;
@@ -159,6 +162,20 @@ struct ActiveRelayActor {
159
162
/// Token indicating the [`ActiveRelayActor`] should stop.
160
163
stop_token : CancellationToken ,
161
164
metrics : Arc < MagicsockMetrics > ,
165
+ /// Received relay packets that could not yet be forwarded to the magicsocket.
166
+ pending_received : Option < PendingRecv > ,
167
+ }
168
+
169
+ #[ derive( Debug ) ]
170
+ struct PendingRecv {
171
+ packet_iter : PacketSplitIter ,
172
+ blocked_on : RecvPath ,
173
+ }
174
+
175
+ #[ derive( Debug ) ]
176
+ enum RecvPath {
177
+ Data ,
178
+ Disco ,
162
179
}
163
180
164
181
#[ derive( Debug ) ]
@@ -263,6 +280,7 @@ impl ActiveRelayActor {
263
280
inactive_timeout : Box :: pin ( time:: sleep ( RELAY_INACTIVE_CLEANUP_TIME ) ) ,
264
281
stop_token,
265
282
metrics,
283
+ pending_received : None ,
266
284
}
267
285
}
268
286
@@ -612,7 +630,8 @@ impl ActiveRelayActor {
612
630
let fut = client_sink. send_all( & mut packet_stream) ;
613
631
self . run_sending( fut, & mut state, & mut client_stream) . await ?;
614
632
}
615
- msg = client_stream. next( ) => {
633
+ _ = forward_pending( & mut self . pending_received, & self . relay_datagrams_recv, & mut self . relay_disco_recv) , if self . pending_received. is_some( ) => { }
634
+ msg = client_stream. next( ) , if self . pending_received. is_none( ) => {
616
635
let Some ( msg) = msg else {
617
636
break Err ( anyhow!( "Stream closed by server." ) ) ;
618
637
} ;
@@ -659,33 +678,14 @@ impl ActiveRelayActor {
659
678
state. last_packet_src = Some ( remote_node_id) ;
660
679
state. nodes_present . insert ( remote_node_id) ;
661
680
}
662
- for datagram in PacketSplitIter :: new ( self . url . clone ( ) , remote_node_id, data) {
663
- let Ok ( datagram) = datagram else {
664
- warn ! ( "Invalid packet split" ) ;
665
- break ;
666
- } ;
667
- match crate :: disco:: source_and_box_bytes ( & datagram. buf ) {
668
- Some ( ( source, sealed_box) ) => {
669
- if remote_node_id != source {
670
- // TODO: return here?
671
- warn ! ( "Received relay disco message from connection for {}, but with message from {}" , remote_node_id. fmt_short( ) , source. fmt_short( ) ) ;
672
- }
673
- let message = RelayDiscoMessage {
674
- source,
675
- sealed_box,
676
- relay_url : datagram. url . clone ( ) ,
677
- relay_remote_node_id : datagram. src ,
678
- } ;
679
- if let Err ( err) = self . relay_disco_recv . try_send ( message) {
680
- warn ! ( "Dropping received relay disco packet: {err:#}" ) ;
681
- }
682
- }
683
- None => {
684
- if let Err ( err) = self . relay_datagrams_recv . try_send ( datagram) {
685
- warn ! ( "Dropping received relay data packet: {err:#}" ) ;
686
- }
687
- }
688
- }
681
+ let packet_iter = PacketSplitIter :: new ( self . url . clone ( ) , remote_node_id, data) ;
682
+ if let Some ( pending) = handle_received_packet_iter (
683
+ packet_iter,
684
+ None ,
685
+ & self . relay_datagrams_recv ,
686
+ & mut self . relay_disco_recv ,
687
+ ) {
688
+ self . pending_received = Some ( pending) ;
689
689
}
690
690
}
691
691
ReceivedMessage :: NodeGone ( node_id) => {
@@ -769,7 +769,8 @@ impl ActiveRelayActor {
769
769
break Err ( anyhow!( "Ping timeout" ) ) ;
770
770
}
771
771
// No need to read the inbox or datagrams to send.
772
- msg = client_stream. next( ) => {
772
+ _ = forward_pending( & mut self . pending_received, & self . relay_datagrams_recv, & mut self . relay_disco_recv) , if self . pending_received. is_some( ) => { }
773
+ msg = client_stream. next( ) , if self . pending_received. is_none( ) => {
773
774
let Some ( msg) = msg else {
774
775
break Err ( anyhow!( "Stream closed by server." ) ) ;
775
776
} ;
@@ -788,6 +789,99 @@ impl ActiveRelayActor {
788
789
}
789
790
}
790
791
792
+ /// Forward pending received packets to their queues.
793
+ ///
794
+ /// If `maybe_pending` is not empty, this will wait for the path the last received item
795
+ /// is blocked on (via [`PendingRecv::blocked_on`]) to become unblocked. It will then forward
796
+ /// the pending items, until a queue is blocked again. In that case, the remaining items will
797
+ /// be put back into `maybe_pending`. If all items could be sent, `maybe_pending` will be set
798
+ /// to `None`.
799
+ ///
800
+ /// This function is cancellation-safe: If the future is dropped at any point, all items are guaranteed
801
+ /// to either be sent into their respective queues, or are still in `maybe_pending`.
802
+ async fn forward_pending (
803
+ maybe_pending : & mut Option < PendingRecv > ,
804
+ relay_datagrams_recv : & RelayDatagramRecvQueue ,
805
+ relay_disco_recv : & mut mpsc:: Sender < RelayDiscoMessage > ,
806
+ ) {
807
+ let Some ( ref mut pending) = maybe_pending else {
808
+ return ;
809
+ } ;
810
+ let disco_permit = match pending. blocked_on {
811
+ RecvPath :: Data => {
812
+ std:: future:: poll_fn ( |cx| relay_datagrams_recv. poll_send_ready ( cx) )
813
+ . await
814
+ . ok ( ) ;
815
+ None
816
+ }
817
+ RecvPath :: Disco => {
818
+ let Ok ( permit) = relay_disco_recv. clone ( ) . reserve_owned ( ) . await else {
819
+ return ;
820
+ } ;
821
+ Some ( permit)
822
+ }
823
+ } ;
824
+ let pending = maybe_pending. take ( ) . unwrap ( ) ;
825
+ if let Some ( pending) = handle_received_packet_iter (
826
+ pending. packet_iter ,
827
+ disco_permit,
828
+ relay_datagrams_recv,
829
+ relay_disco_recv,
830
+ ) {
831
+ * maybe_pending = Some ( pending) ;
832
+ }
833
+ }
834
+
835
+ fn handle_received_packet_iter (
836
+ mut packet_iter : PacketSplitIter ,
837
+ mut disco_permit : Option < OwnedPermit < RelayDiscoMessage > > ,
838
+ relay_datagrams_recv : & RelayDatagramRecvQueue ,
839
+ relay_disco_recv : & mut mpsc:: Sender < RelayDiscoMessage > ,
840
+ ) -> Option < PendingRecv > {
841
+ let remote_node_id = packet_iter. remote_node_id ( ) ;
842
+ for datagram in & mut packet_iter {
843
+ let Ok ( datagram) = datagram else {
844
+ warn ! ( "Invalid packet split" ) ;
845
+ return None ;
846
+ } ;
847
+ match crate :: disco:: source_and_box_bytes ( & datagram. buf ) {
848
+ Some ( ( source, sealed_box) ) => {
849
+ if remote_node_id != source {
850
+ // TODO: return here?
851
+ warn ! ( "Received relay disco message from connection for {}, but with message from {}" , remote_node_id. fmt_short( ) , source. fmt_short( ) ) ;
852
+ }
853
+ let message = RelayDiscoMessage {
854
+ source,
855
+ sealed_box,
856
+ relay_url : datagram. url . clone ( ) ,
857
+ relay_remote_node_id : datagram. src ,
858
+ } ;
859
+ if let Some ( permit) = disco_permit. take ( ) {
860
+ permit. send ( message) ;
861
+ } else if let Err ( err) = relay_disco_recv. try_send ( message) {
862
+ warn ! ( "Dropping received relay disco packet: {err:#}" ) ;
863
+ packet_iter. push_front ( datagram) ;
864
+ return Some ( PendingRecv {
865
+ packet_iter,
866
+ blocked_on : RecvPath :: Disco ,
867
+ } ) ;
868
+ }
869
+ }
870
+ None => {
871
+ if let Err ( err) = relay_datagrams_recv. try_send ( datagram) {
872
+ warn ! ( "Dropping received relay data packet: {err:#}" ) ;
873
+ packet_iter. push_front ( err. into_inner ( ) ) ;
874
+ return Some ( PendingRecv {
875
+ packet_iter,
876
+ blocked_on : RecvPath :: Data ,
877
+ } ) ;
878
+ }
879
+ }
880
+ }
881
+ }
882
+ None
883
+ }
884
+
791
885
/// Shared state when the [`ActiveRelayActor`] is connected to a relay server.
792
886
///
793
887
/// Common state between [`ActiveRelayActor::run_connected`] and
@@ -1270,12 +1364,22 @@ struct PacketSplitIter {
1270
1364
url : RelayUrl ,
1271
1365
src : NodeId ,
1272
1366
bytes : Bytes ,
1367
+ next : Option < RelayRecvDatagram > ,
1273
1368
}
1274
1369
1275
1370
impl PacketSplitIter {
1276
1371
/// Create a new PacketSplitIter from a packet.
1277
1372
fn new ( url : RelayUrl , src : NodeId , bytes : Bytes ) -> Self {
1278
- Self { url, src, bytes }
1373
+ Self {
1374
+ url,
1375
+ src,
1376
+ bytes,
1377
+ next : None ,
1378
+ }
1379
+ }
1380
+
1381
+ fn remote_node_id ( & self ) -> NodeId {
1382
+ self . src
1279
1383
}
1280
1384
1281
1385
fn fail ( & mut self ) -> Option < std:: io:: Result < RelayRecvDatagram > > {
@@ -1285,13 +1389,20 @@ impl PacketSplitIter {
1285
1389
"" ,
1286
1390
) ) )
1287
1391
}
1392
+
1393
+ fn push_front ( & mut self , item : RelayRecvDatagram ) {
1394
+ self . next = Some ( item) ;
1395
+ }
1288
1396
}
1289
1397
1290
1398
impl Iterator for PacketSplitIter {
1291
1399
type Item = std:: io:: Result < RelayRecvDatagram > ;
1292
1400
1293
1401
fn next ( & mut self ) -> Option < Self :: Item > {
1294
1402
use bytes:: Buf ;
1403
+ if let Some ( item) = self . next . take ( ) {
1404
+ return Some ( Ok ( item) ) ;
1405
+ }
1295
1406
if self . bytes . has_remaining ( ) {
1296
1407
if self . bytes . remaining ( ) < 2 {
1297
1408
return self . fail ( ) ;
0 commit comments