@@ -1094,11 +1094,6 @@ impl MagicSock {
1094
1094
return None ;
1095
1095
}
1096
1096
1097
- if self . handle_relay_disco_message ( & dm. buf , & dm. url , dm. src ) {
1098
- // DISCO messages are handled internally in the MagicSock, do not pass to Quinn.
1099
- return None ;
1100
- }
1101
-
1102
1097
let quic_mapped_addr = self . node_map . receive_relay ( & dm. url , dm. src ) ;
1103
1098
1104
1099
// Normalize local_ip
@@ -1119,32 +1114,6 @@ impl MagicSock {
1119
1114
Some ( ( dm. src , meta, dm. buf ) )
1120
1115
}
1121
1116
1122
- fn handle_relay_disco_message (
1123
- & self ,
1124
- msg : & [ u8 ] ,
1125
- url : & RelayUrl ,
1126
- relay_node_src : PublicKey ,
1127
- ) -> bool {
1128
- match disco:: source_and_box ( msg) {
1129
- Some ( ( source, sealed_box) ) => {
1130
- if relay_node_src != source {
1131
- // TODO: return here?
1132
- warn ! ( "Received relay disco message from connection for {}, but with message from {}" , relay_node_src. fmt_short( ) , source. fmt_short( ) ) ;
1133
- }
1134
- self . handle_disco_message (
1135
- source,
1136
- sealed_box,
1137
- DiscoMessageSource :: Relay {
1138
- url : url. clone ( ) ,
1139
- key : relay_node_src,
1140
- } ,
1141
- ) ;
1142
- true
1143
- }
1144
- None => false ,
1145
- }
1146
- }
1147
-
1148
1117
/// Handles a discovery message.
1149
1118
#[ instrument( "disco_in" , skip_all, fields( node = %sender. fmt_short( ) , %src) ) ]
1150
1119
fn handle_disco_message ( & self , sender : PublicKey , sealed_box : & [ u8 ] , src : DiscoMessageSource ) {
@@ -1827,7 +1796,13 @@ impl Handle {
1827
1796
1828
1797
let mut actor_tasks = JoinSet :: default ( ) ;
1829
1798
1830
- let relay_actor = RelayActor :: new ( msock. clone ( ) , relay_datagram_recv_queue, relay_protocol) ;
1799
+ let ( relay_disco_recv_tx, mut relay_disco_recv_rx) = tokio:: sync:: mpsc:: channel ( 1024 ) ;
1800
+ let relay_actor = RelayActor :: new (
1801
+ msock. clone ( ) ,
1802
+ relay_datagram_recv_queue,
1803
+ relay_disco_recv_tx,
1804
+ relay_protocol,
1805
+ ) ;
1831
1806
let relay_actor_cancel_token = relay_actor. cancel_token ( ) ;
1832
1807
actor_tasks. spawn (
1833
1808
async move {
@@ -1837,6 +1812,23 @@ impl Handle {
1837
1812
}
1838
1813
. instrument ( info_span ! ( "relay-actor" ) ) ,
1839
1814
) ;
1815
+ actor_tasks. spawn ( {
1816
+ let msock = msock. clone ( ) ;
1817
+ async move {
1818
+ while let Some ( message) = relay_disco_recv_rx. recv ( ) . await {
1819
+ msock. handle_disco_message (
1820
+ message. source ,
1821
+ & message. sealed_box ,
1822
+ DiscoMessageSource :: Relay {
1823
+ url : message. relay_url ,
1824
+ key : message. relay_remote_node_id ,
1825
+ } ,
1826
+ ) ;
1827
+ }
1828
+ debug ! ( "relay-disco-recv actor closed" ) ;
1829
+ }
1830
+ . instrument ( info_span ! ( "relay-disco-recv" ) )
1831
+ } ) ;
1840
1832
1841
1833
#[ cfg( not( wasm_browser) ) ]
1842
1834
let _ = actor_tasks. spawn ( {
@@ -2123,15 +2115,17 @@ impl RelayDatagramSendChannelReceiver {
2123
2115
#[ derive( Debug ) ]
2124
2116
struct RelayDatagramRecvQueue {
2125
2117
queue : ConcurrentQueue < RelayRecvDatagram > ,
2126
- waker : AtomicWaker ,
2118
+ recv_waker : AtomicWaker ,
2119
+ send_wakers : ConcurrentQueue < Waker > ,
2127
2120
}
2128
2121
2129
2122
impl RelayDatagramRecvQueue {
2130
2123
/// Creates a new, empty queue with a fixed size bound of 512 items.
2131
2124
fn new ( ) -> Self {
2132
2125
Self {
2133
2126
queue : ConcurrentQueue :: bounded ( 512 ) ,
2134
- waker : AtomicWaker :: new ( ) ,
2127
+ recv_waker : AtomicWaker :: new ( ) ,
2128
+ send_wakers : ConcurrentQueue :: unbounded ( ) ,
2135
2129
}
2136
2130
}
2137
2131
@@ -2144,10 +2138,49 @@ impl RelayDatagramRecvQueue {
2144
2138
item : RelayRecvDatagram ,
2145
2139
) -> Result < ( ) , concurrent_queue:: PushError < RelayRecvDatagram > > {
2146
2140
self . queue . push ( item) . inspect ( |_| {
2147
- self . waker . wake ( ) ;
2141
+ self . recv_waker . wake ( ) ;
2148
2142
} )
2149
2143
}
2150
2144
2145
+ /// Polls for whether the queue has free slots for sending items.
2146
+ ///
2147
+ /// If the queue has free slots, this returns [`Poll::Ready`].
2148
+ /// If the queue is full, [`Poll::Pending`] is returned and the waker
2149
+ /// is stored and woken once the queue has free slots.
2150
+ ///
2151
+ /// This can be called from multiple tasks concurrently. If a slot becomes
2152
+ /// available, all stored wakers will be woken simultaneously.
2153
+ /// This also means that even if [`Poll::Ready`] is returned, it is not
2154
+ /// guaranteed that [`Self::try_send`] will return `Ok` on the next call,
2155
+ /// because another send task could have used the slot already.
2156
+ fn poll_send_ready ( & self , cx : & mut Context < ' _ > ) -> Poll < Result < ( ) > > {
2157
+ if self . queue . is_closed ( ) {
2158
+ Poll :: Ready ( Err ( anyhow ! ( "Queue closed" ) ) )
2159
+ } else if !self . queue . is_full ( ) {
2160
+ Poll :: Ready ( Ok ( ( ) ) )
2161
+ } else {
2162
+ match self . send_wakers . push ( cx. waker ( ) . clone ( ) ) {
2163
+ Ok ( ( ) ) => Poll :: Pending ,
2164
+ Err ( concurrent_queue:: PushError :: Full ( _) ) => {
2165
+ unreachable ! ( "Send waker queue is unbounded" )
2166
+ }
2167
+ Err ( concurrent_queue:: PushError :: Closed ( _) ) => {
2168
+ Poll :: Ready ( Err ( anyhow ! ( "Queue closed" ) ) )
2169
+ }
2170
+ }
2171
+ }
2172
+ }
2173
+
2174
+ async fn send_ready ( & self ) -> Result < ( ) > {
2175
+ std:: future:: poll_fn ( |cx| self . poll_send_ready ( cx) ) . await
2176
+ }
2177
+
2178
+ fn wake_senders ( & self ) {
2179
+ while let Ok ( waker) = self . send_wakers . pop ( ) {
2180
+ waker. wake ( ) ;
2181
+ }
2182
+ }
2183
+
2151
2184
/// Polls for new items in the queue.
2152
2185
///
2153
2186
/// Although this method is available from `&self`, it must not be
@@ -2162,23 +2195,31 @@ impl RelayDatagramRecvQueue {
2162
2195
/// to be able to poll from `&self`.
2163
2196
fn poll_recv ( & self , cx : & mut Context ) -> Poll < Result < RelayRecvDatagram > > {
2164
2197
match self . queue . pop ( ) {
2165
- Ok ( value) => Poll :: Ready ( Ok ( value) ) ,
2198
+ Ok ( value) => {
2199
+ self . wake_senders ( ) ;
2200
+ Poll :: Ready ( Ok ( value) )
2201
+ }
2166
2202
Err ( concurrent_queue:: PopError :: Empty ) => {
2167
- self . waker . register ( cx. waker ( ) ) ;
2203
+ self . recv_waker . register ( cx. waker ( ) ) ;
2168
2204
2169
2205
match self . queue . pop ( ) {
2170
2206
Ok ( value) => {
2171
- self . waker . take ( ) ;
2207
+ self . recv_waker . take ( ) ;
2208
+ self . wake_senders ( ) ;
2172
2209
Poll :: Ready ( Ok ( value) )
2173
2210
}
2174
2211
Err ( concurrent_queue:: PopError :: Empty ) => Poll :: Pending ,
2175
2212
Err ( concurrent_queue:: PopError :: Closed ) => {
2176
- self . waker . take ( ) ;
2213
+ self . recv_waker . take ( ) ;
2214
+ self . wake_senders ( ) ;
2177
2215
Poll :: Ready ( Err ( anyhow ! ( "Queue closed" ) ) )
2178
2216
}
2179
2217
}
2180
2218
}
2181
- Err ( concurrent_queue:: PopError :: Closed ) => Poll :: Ready ( Err ( anyhow ! ( "Queue closed" ) ) ) ,
2219
+ Err ( concurrent_queue:: PopError :: Closed ) => {
2220
+ self . wake_senders ( ) ;
2221
+ Poll :: Ready ( Err ( anyhow ! ( "Queue closed" ) ) )
2222
+ }
2182
2223
}
2183
2224
}
2184
2225
}
0 commit comments