Skip to content

Commit 592c0dd

Browse files
committed
fix: add timeouts to UdpClient operations
The generic UDP client does not have timeouts. When the server is down it waits forever for responses. This client has been using only for testing where the server was always up, but now it's using in production code by the Tracker Checker. For the time being, I keep the panicking behavior of the UdpClient when something is wrong. However we should return an error when the operation times out. For the Tracker Checker, it means that when the checker can't connect to a UDP server the checker is going to panic after 5 seconds. That is not the intended behavior for the checker. It should always return a full reprot of all checks. In order to implement that behavior we need to change the UdpClient to return errors. Since that's a bug refactor I open a new issue.
1 parent 6b74c66 commit 592c0dd

File tree

1 file changed

+39
-5
lines changed

1 file changed

+39
-5
lines changed

src/shared/bit_torrent/tracker/udp/client.rs

+39-5
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,18 @@ use tokio::time;
1010

1111
use crate::shared::bit_torrent::tracker::udp::{source_address, MAX_PACKET_SIZE};
1212

13+
/// Default timeout for sending and receiving packets. And waiting for sockets
14+
/// to be readable and writable.
15+
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5);
16+
1317
#[allow(clippy::module_name_repetitions)]
1418
#[derive(Debug)]
1519
pub struct UdpClient {
20+
/// The socket to connect to
1621
pub socket: Arc<UdpSocket>,
22+
23+
/// Timeout for sending and receiving packets
24+
pub timeout: Duration,
1725
}
1826

1927
impl UdpClient {
@@ -29,6 +37,7 @@ impl UdpClient {
2937

3038
Self {
3139
socket: Arc::new(socket),
40+
timeout: DEFAULT_TIMEOUT,
3241
}
3342
}
3443

@@ -53,10 +62,23 @@ impl UdpClient {
5362
/// - Can't write to the socket.
5463
/// - Can't send data.
5564
pub async fn send(&self, bytes: &[u8]) -> usize {
56-
debug!(target: "UDP client", "send {bytes:?}");
65+
debug!(target: "UDP client", "sending {bytes:?} ...");
66+
67+
match time::timeout(self.timeout, self.socket.writable()).await {
68+
Ok(writable_result) => match writable_result {
69+
Ok(()) => (),
70+
Err(e) => panic!("{}", format!("IO error waiting for the socket to become readable: {e:?}")),
71+
},
72+
Err(e) => panic!("{}", format!("Timeout waiting for the socket to become readable: {e:?}")),
73+
};
5774

58-
self.socket.writable().await.unwrap();
59-
self.socket.send(bytes).await.unwrap()
75+
match time::timeout(self.timeout, self.socket.send(bytes)).await {
76+
Ok(send_result) => match send_result {
77+
Ok(size) => size,
78+
Err(e) => panic!("{}", format!("IO error during send: {e:?}")),
79+
},
80+
Err(e) => panic!("{}", format!("Send operation timed out: {e:?}")),
81+
}
6082
}
6183

6284
/// # Panics
@@ -68,9 +90,21 @@ impl UdpClient {
6890
pub async fn receive(&self, bytes: &mut [u8]) -> usize {
6991
debug!(target: "UDP client", "receiving ...");
7092

71-
self.socket.readable().await.unwrap();
93+
match time::timeout(self.timeout, self.socket.readable()).await {
94+
Ok(readable_result) => match readable_result {
95+
Ok(()) => (),
96+
Err(e) => panic!("{}", format!("IO error waiting for the socket to become readable: {e:?}")),
97+
},
98+
Err(e) => panic!("{}", format!("Timeout waiting for the socket to become readable: {e:?}")),
99+
};
72100

73-
let size = self.socket.recv(bytes).await.unwrap();
101+
let size = match time::timeout(self.timeout, self.socket.recv(bytes)).await {
102+
Ok(recv_result) => match recv_result {
103+
Ok(size) => size,
104+
Err(e) => panic!("{}", format!("IO error during send: {e:?}")),
105+
},
106+
Err(e) => panic!("{}", format!("Receive operation timed out: {e:?}")),
107+
};
74108

75109
debug!(target: "UDP client", "{size} bytes received {bytes:?}");
76110

0 commit comments

Comments
 (0)