20
20
use std:: io:: Cursor ;
21
21
use std:: net:: SocketAddr ;
22
22
use std:: sync:: Arc ;
23
- use std:: time:: Duration ;
24
23
25
24
use aquatic_udp_protocol:: Response ;
26
25
use derive_more:: Constructor ;
27
- use futures:: pin_mut;
28
- use log:: { debug, error, info} ;
26
+ use log:: { debug, error, info, trace} ;
27
+ use ringbuf:: storage:: Static ;
28
+ use ringbuf:: traits:: { Consumer , Observer , RingBuffer } ;
29
+ use ringbuf:: LocalRb ;
29
30
use tokio:: net:: UdpSocket ;
30
- use tokio:: sync:: oneshot:: { Receiver , Sender } ;
31
- use tokio:: task:: JoinHandle ;
31
+ use tokio:: sync:: oneshot;
32
+ use tokio:: task:: { AbortHandle , JoinHandle } ;
33
+ use tokio:: { select, task} ;
32
34
35
+ use super :: UdpRequest ;
33
36
use crate :: bootstrap:: jobs:: Started ;
34
37
use crate :: core:: Tracker ;
35
38
use crate :: servers:: registar:: { ServiceHealthCheckJob , ServiceRegistration , ServiceRegistrationForm } ;
36
39
use crate :: servers:: signals:: { shutdown_signal_with_message, Halted } ;
37
- use crate :: servers:: udp:: handlers:: handle_packet ;
40
+ use crate :: servers:: udp:: handlers;
38
41
use crate :: shared:: bit_torrent:: tracker:: udp:: client:: check;
39
42
use crate :: shared:: bit_torrent:: tracker:: udp:: MAX_PACKET_SIZE ;
40
43
@@ -125,17 +128,8 @@ impl UdpServer<Stopped> {
125
128
126
129
assert ! ( !tx_halt. is_closed( ) , "Halt channel for UDP tracker should be open" ) ;
127
130
128
- let launcher = self . state . launcher ;
129
-
130
- let task = tokio:: spawn ( async move {
131
- debug ! ( target: "UDP Tracker" , "Launcher starting ..." ) ;
132
-
133
- let starting = launcher. start ( tracker, tx_start, rx_halt) . await ;
134
-
135
- starting. await . expect ( "UDP server should have started running" ) ;
136
-
137
- launcher
138
- } ) ;
131
+ // May need to wrap in a task to about a tokio bug.
132
+ let task = self . state . launcher . start ( tracker, tx_start, rx_halt) ;
139
133
140
134
let binding = rx_start. await . expect ( "it should be able to start the service" ) . address ;
141
135
@@ -150,6 +144,8 @@ impl UdpServer<Stopped> {
150
144
} ,
151
145
} ;
152
146
147
+ trace ! ( "Running UDP Tracker on Socket: {}" , running_udp_server. state. binding) ;
148
+
153
149
Ok ( running_udp_server)
154
150
}
155
151
}
@@ -182,7 +178,7 @@ impl UdpServer<Running> {
182
178
}
183
179
}
184
180
185
- #[ derive( Constructor , Debug ) ]
181
+ #[ derive( Constructor , Copy , Clone , Debug ) ]
186
182
pub struct Launcher {
187
183
bind_to : SocketAddr ,
188
184
}
@@ -193,8 +189,40 @@ impl Launcher {
193
189
/// # Panics
194
190
///
195
191
/// It would panic if unable to resolve the `local_addr` from the supplied ´socket´.
196
- pub async fn start ( & self , tracker : Arc < Tracker > , tx_start : Sender < Started > , rx_halt : Receiver < Halted > ) -> JoinHandle < ( ) > {
197
- Udp :: start_with_graceful_shutdown ( tracker, self . bind_to , tx_start, rx_halt) . await
192
+ pub fn start (
193
+ & self ,
194
+ tracker : Arc < Tracker > ,
195
+ tx_start : oneshot:: Sender < Started > ,
196
+ rx_halt : oneshot:: Receiver < Halted > ,
197
+ ) -> JoinHandle < Launcher > {
198
+ let launcher = Launcher :: new ( self . bind_to ) ;
199
+ tokio:: spawn ( async move {
200
+ Udp :: run_with_graceful_shutdown ( tracker, launcher. bind_to , tx_start, rx_halt) . await ;
201
+ launcher
202
+ } )
203
+ }
204
+ }
205
+
206
+ #[ derive( Default ) ]
207
+ struct ActiveRequests {
208
+ rb : LocalRb < Static < AbortHandle , 50 > > , // the number of requests we handle at the same time.
209
+ }
210
+
211
+ impl std:: fmt:: Debug for ActiveRequests {
212
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
213
+ let ( left, right) = & self . rb . as_slices ( ) ;
214
+ let dbg = format ! ( "capacity: {}, left: {left:?}, right: {right:?}" , & self . rb. capacity( ) ) ;
215
+ f. debug_struct ( "ActiveRequests" ) . field ( "rb" , & dbg) . finish ( )
216
+ }
217
+ }
218
+
219
+ impl Drop for ActiveRequests {
220
+ fn drop ( & mut self ) {
221
+ for h in self . rb . pop_iter ( ) {
222
+ if !h. is_finished ( ) {
223
+ h. abort ( ) ;
224
+ }
225
+ }
198
226
}
199
227
}
200
228
@@ -209,80 +237,103 @@ impl Udp {
209
237
///
210
238
/// It panics if unable to bind to udp socket, and get the address from the udp socket.
211
239
/// It also panics if unable to send address of socket.
212
- async fn start_with_graceful_shutdown (
240
+ async fn run_with_graceful_shutdown (
213
241
tracker : Arc < Tracker > ,
214
242
bind_to : SocketAddr ,
215
- tx_start : Sender < Started > ,
216
- rx_halt : Receiver < Halted > ,
217
- ) -> JoinHandle < ( ) > {
243
+ tx_start : oneshot :: Sender < Started > ,
244
+ rx_halt : oneshot :: Receiver < Halted > ,
245
+ ) {
218
246
let socket = Arc :: new ( UdpSocket :: bind ( bind_to) . await . expect ( "Could not bind to {self.socket}." ) ) ;
219
247
let address = socket. local_addr ( ) . expect ( "Could not get local_addr from {binding}." ) ;
248
+ let halt = shutdown_signal_with_message ( rx_halt, format ! ( "Halting Http Service Bound to Socket: {address}" ) ) ;
220
249
221
250
info ! ( target: "UDP Tracker" , "Starting on: udp://{}" , address) ;
222
251
223
252
let running = tokio:: task:: spawn ( async move {
224
- let halt = tokio:: task:: spawn ( async move {
225
- debug ! ( target: "UDP Tracker" , "Waiting for halt signal for socket address: udp://{address} ..." ) ;
226
-
227
- shutdown_signal_with_message (
228
- rx_halt,
229
- format ! ( "Shutting down UDP server on socket address: udp://{address}" ) ,
230
- )
231
- . await ;
232
- } ) ;
233
-
234
- let listen = async move {
235
- debug ! ( target: "UDP Tracker" , "Waiting for packets on socket address: udp://{address} ..." ) ;
236
-
237
- loop {
238
- let mut data = [ 0 ; MAX_PACKET_SIZE ] ;
239
- let socket_clone = socket. clone ( ) ;
240
-
241
- match socket_clone. recv_from ( & mut data) . await {
242
- Ok ( ( valid_bytes, remote_addr) ) => {
243
- let payload = data[ ..valid_bytes] . to_vec ( ) ;
244
-
245
- debug ! ( target: "UDP Tracker" , "Received {} bytes" , payload. len( ) ) ;
246
- debug ! ( target: "UDP Tracker" , "From: {}" , & remote_addr) ;
247
- debug ! ( target: "UDP Tracker" , "Payload: {:?}" , payload) ;
248
-
249
- let response_fut = handle_packet ( remote_addr, payload, & tracker) ;
250
-
251
- match tokio:: time:: timeout ( Duration :: from_secs ( 5 ) , response_fut) . await {
252
- Ok ( response) => {
253
- Udp :: send_response ( socket_clone, remote_addr, response) . await ;
254
- }
255
- Err ( _) => {
256
- error ! ( "Timeout occurred while processing the UDP request." ) ;
257
- }
258
- }
259
- }
260
- Err ( err) => {
261
- error ! ( "Error reading UDP datagram from socket. Error: {:?}" , err) ;
262
- }
253
+ debug ! ( target: "UDP Tracker" , "Started: Waiting for packets on socket address: udp://{address} ..." ) ;
254
+
255
+ let tracker = tracker. clone ( ) ;
256
+ let socket = socket. clone ( ) ;
257
+
258
+ let reqs = & mut ActiveRequests :: default ( ) ;
259
+
260
+ // Main Waiting Loop, awaits on async [`receive_request`].
261
+ loop {
262
+ if let Some ( h) = reqs. rb . push_overwrite (
263
+ Self :: do_request ( Self :: receive_request ( socket. clone ( ) ) . await , tracker. clone ( ) , socket. clone ( ) ) . abort_handle ( ) ,
264
+ ) {
265
+ if !h. is_finished ( ) {
266
+ // the task is still running, lets yield and give it a chance to flush.
267
+ tokio:: task:: yield_now ( ) . await ;
268
+ h. abort ( ) ;
263
269
}
264
270
}
265
- } ;
271
+ }
272
+ } ) ;
273
+
274
+ tx_start
275
+ . send ( Started { address } )
276
+ . expect ( "the UDP Tracker service should not be dropped" ) ;
277
+
278
+ debug ! ( target: "UDP Tracker" , "Started on: udp://{}" , address) ;
266
279
267
- pin_mut ! ( halt) ;
268
- pin_mut ! ( listen) ;
280
+ let stop = running. abort_handle ( ) ;
269
281
270
- tx_start
271
- . send ( Started { address } )
272
- . expect ( "the UDP Tracker service should not be dropped" ) ;
282
+ select ! {
283
+ _ = running => { debug!( target: "UDP Tracker" , "Socket listener stopped on address: udp://{address}" ) ; } ,
284
+ ( ) = halt => { debug!( target: "UDP Tracker" , "Halt signal spawned task stopped on address: udp://{address}" ) ; }
285
+ }
286
+ stop. abort ( ) ;
287
+
288
+ task:: yield_now ( ) . await ; // lets allow the other threads to complete.
289
+ }
273
290
274
- tokio:: select! {
275
- _ = & mut halt => { debug!( target: "UDP Tracker" , "Halt signal spawned task stopped on address: udp://{address}" ) ; } ,
276
- ( ) = & mut listen => { debug!( target: "UDP Tracker" , "Socket listener stopped on address: udp://{address}" ) ; } ,
291
+ async fn receive_request ( socket : Arc < UdpSocket > ) -> Result < UdpRequest , Box < std:: io:: Error > > {
292
+ // Wait for the socket to be readable
293
+ socket. readable ( ) . await ?;
294
+
295
+ let mut buf = Vec :: with_capacity ( MAX_PACKET_SIZE ) ;
296
+
297
+ match socket. recv_buf_from ( & mut buf) . await {
298
+ Ok ( ( n, from) ) => {
299
+ Vec :: truncate ( & mut buf, n) ;
300
+ trace ! ( "GOT {buf:?}" ) ;
301
+ Ok ( UdpRequest { payload : buf, from } )
277
302
}
278
- } ) ;
279
303
280
- info ! ( target: "UDP Tracker" , "Started on: udp://{}" , address) ;
304
+ Err ( e) => Err ( Box :: new ( e) ) ,
305
+ }
306
+ }
281
307
282
- running
308
+ fn do_request (
309
+ result : Result < UdpRequest , Box < std:: io:: Error > > ,
310
+ tracker : Arc < Tracker > ,
311
+ socket : Arc < UdpSocket > ,
312
+ ) -> JoinHandle < ( ) > {
313
+ // timeout not needed, as udp is non-blocking.
314
+ tokio:: task:: spawn ( async move {
315
+ match result {
316
+ Ok ( udp_request) => {
317
+ trace ! ( "Received Request from: {}" , udp_request. from) ;
318
+ Self :: make_response ( tracker. clone ( ) , socket. clone ( ) , udp_request) . await ;
319
+ }
320
+ Err ( error) => {
321
+ debug ! ( "error: {error}" ) ;
322
+ }
323
+ }
324
+ } )
283
325
}
284
326
285
- async fn send_response ( socket : Arc < UdpSocket > , remote_addr : SocketAddr , response : Response ) {
327
+ async fn make_response ( tracker : Arc < Tracker > , socket : Arc < UdpSocket > , udp_request : UdpRequest ) {
328
+ trace ! ( "Making Response to {udp_request:?}" ) ;
329
+ let from = udp_request. from ;
330
+ let response = handlers:: handle_packet ( udp_request, & tracker. clone ( ) ) . await ;
331
+ Self :: send_response ( & socket. clone ( ) , from, response) . await ;
332
+ }
333
+
334
+ async fn send_response ( socket : & Arc < UdpSocket > , to : SocketAddr , response : Response ) {
335
+ trace ! ( "Sending Response: {response:?} to: {to:?}" ) ;
336
+
286
337
let buffer = vec ! [ 0u8 ; MAX_PACKET_SIZE ] ;
287
338
let mut cursor = Cursor :: new ( buffer) ;
288
339
@@ -293,10 +344,10 @@ impl Udp {
293
344
let inner = cursor. get_ref ( ) ;
294
345
295
346
debug ! ( "Sending {} bytes ..." , & inner[ ..position] . len( ) ) ;
296
- debug ! ( "To: {:?}" , & remote_addr ) ;
347
+ debug ! ( "To: {:?}" , & to ) ;
297
348
debug ! ( "Payload: {:?}" , & inner[ ..position] ) ;
298
349
299
- Udp :: send_packet ( socket, & remote_addr , & inner[ ..position] ) . await ;
350
+ Self :: send_packet ( socket, & to , & inner[ ..position] ) . await ;
300
351
301
352
debug ! ( "{} bytes sent" , & inner[ ..position] . len( ) ) ;
302
353
}
@@ -306,7 +357,9 @@ impl Udp {
306
357
}
307
358
}
308
359
309
- async fn send_packet ( socket : Arc < UdpSocket > , remote_addr : & SocketAddr , payload : & [ u8 ] ) {
360
+ async fn send_packet ( socket : & Arc < UdpSocket > , remote_addr : & SocketAddr , payload : & [ u8 ] ) {
361
+ trace ! ( "Sending Packets: {payload:?} to: {remote_addr:?}" ) ;
362
+
310
363
// doesn't matter if it reaches or not
311
364
drop ( socket. send_to ( payload, remote_addr) . await ) ;
312
365
}
@@ -324,7 +377,9 @@ impl Udp {
324
377
#[ cfg( test) ]
325
378
mod tests {
326
379
use std:: sync:: Arc ;
380
+ use std:: time:: Duration ;
327
381
382
+ use tokio:: time:: sleep;
328
383
use torrust_tracker_test_helpers:: configuration:: ephemeral_mode_public;
329
384
330
385
use crate :: bootstrap:: app:: initialize_with_configuration;
@@ -351,6 +406,8 @@ mod tests {
351
406
. expect ( "it should start the server" ) ;
352
407
let stopped = started. stop ( ) . await . expect ( "it should stop the server" ) ;
353
408
409
+ sleep ( Duration :: from_secs ( 1 ) ) . await ;
410
+
354
411
assert_eq ! ( stopped. state. launcher. bind_to, bind_to) ;
355
412
}
356
413
}
0 commit comments