Skip to content

Commit 578057b

Browse files
committed
Merge #1552: Refactor UDP error event logic before adding new metrics
a8f3a97 refactor: [#1551] extract event handler for each udp event (Jose Celano) 89ac87c refactor: [#1551] extract methods in udp event handler" (Jose Celano) 07c6e89 refactor: rename UDP tracker server error variants (Jose Celano) 21bea5b refactor: [#1456] increase ban counters asyncronously (Jose Celano) ad1b19a feat: trigger UDP error event when there is no transaction ID too (Jose Celano) 525ab73 refactor: [#1456] extract methods (Jose Celano) f485501 refactor: [#1456 clean code (Jose Celano) 0108c26 fix: test. Error message changed (Jose Celano) d7902f1 refactor: [#1456] remove unused enum variant in udp server error (Jose Celano) 8f3c22a feat: [#1456] expose error kind in the UdpError event (Jose Celano) 52b9660 feat: [#1456] wrapper over aquatic RequestParseError to make it sendable (Jose Celano) Pull request description: I will add a new metric to count which client's software is used when a UDP error is produced (only for connection ID errors, for now). This PR make some changes before adding the new metric. ### Subtasks - [x] Wrapper for aquatic parse error. It's not sendable. - [x] Add the error to the `Event::UdpError` event. - [x] Move logic to increase the number of wrong connection IDs per IP to the event listener. - [x] Rename errors. - [x] Refactor event handler. ACKs for top commit: josecelano: ACK a8f3a97 Tree-SHA512: faa185a8050ef9e45f317ef06aa74e52bb385c31167fa0f199411bb1a47a573429daa31b2cccdd024f8fd75c91227618350d10e41d12e8b4062fb1e8d7f7bfdc
2 parents 059d2b6 + a8f3a97 commit 578057b

File tree

20 files changed

+987
-743
lines changed

20 files changed

+987
-743
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/tracker-core/src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub enum ScrapeError {
8484
///
8585
/// This error is returned when an operation involves a torrent that is not
8686
/// present in the whitelist.
87-
#[derive(thiserror::Error, Debug, Clone)]
87+
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
8888
pub enum WhitelistError {
8989
/// Indicates that the torrent identified by `info_hash` is not whitelisted.
9090
#[error("The torrent: {info_hash}, is not whitelisted, {location}")]

packages/udp-tracker-core/src/connection_cookie.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ use zerocopy::AsBytes;
8686
use crate::crypto::keys::CipherArrayBlowfish;
8787

8888
/// Error returned when there was an error with the connection cookie.
89-
#[derive(Error, Debug, Clone)]
89+
#[derive(Error, Debug, Clone, PartialEq)]
9090
pub enum ConnectionCookieError {
9191
#[error("cookie value is not normal: {not_normal_value}")]
9292
ValueNotNormal { not_normal_value: f64 },

packages/udp-tracker-server/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ torrust-server-lib = { version = "3.0.0-develop", path = "../server-lib" }
3030
torrust-tracker-clock = { version = "3.0.0-develop", path = "../clock" }
3131
torrust-tracker-configuration = { version = "3.0.0-develop", path = "../configuration" }
3232
torrust-tracker-events = { version = "3.0.0-develop", path = "../events" }
33-
torrust-tracker-located-error = { version = "3.0.0-develop", path = "../located-error" }
3433
torrust-tracker-metrics = { version = "3.0.0-develop", path = "../metrics" }
3534
torrust-tracker-primitives = { version = "3.0.0-develop", path = "../primitives" }
3635
torrust-tracker-swarm-coordination-registry = { version = "3.0.0-develop", path = "../swarm-coordination-registry" }

packages/udp-tracker-server/src/environment.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ impl Environment<Stopped> {
8282
let udp_server_event_listener_job = Some(crate::statistics::event::listener::run_event_listener(
8383
self.container.udp_tracker_server_container.event_bus.receiver(),
8484
&self.container.udp_tracker_server_container.stats_repository,
85+
&self.container.udp_tracker_core_container.ban_service,
8586
));
8687

8788
// Start the UDP tracker server
Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,100 @@
11
//! Error types for the UDP server.
2+
use std::fmt::Display;
23
use std::panic::Location;
34

4-
use aquatic_udp_protocol::{ConnectionId, RequestParseError};
5+
use aquatic_udp_protocol::{ConnectionId, RequestParseError, TransactionId};
56
use bittorrent_udp_tracker_core::services::announce::UdpAnnounceError;
67
use bittorrent_udp_tracker_core::services::scrape::UdpScrapeError;
78
use derive_more::derive::Display;
89
use thiserror::Error;
9-
use torrust_tracker_located_error::LocatedError;
1010

1111
#[derive(Display, Debug)]
1212
#[display(":?")]
1313
pub struct ConnectionCookie(pub ConnectionId);
1414

1515
/// Error returned by the UDP server.
16-
#[derive(Error, Debug)]
16+
#[derive(Error, Debug, Clone)]
1717
pub enum Error {
1818
/// Error returned when the request is invalid.
19-
#[error("error when phrasing request: {request_parse_error:?}")]
20-
RequestParseError { request_parse_error: RequestParseError },
19+
#[error("error parsing request: {request_parse_error:?}")]
20+
InvalidRequest { request_parse_error: SendableRequestParseError },
2121

2222
/// Error returned when the domain tracker returns an announce error.
2323
#[error("tracker announce error: {source}")]
24-
UdpAnnounceError { source: UdpAnnounceError },
24+
AnnounceFailed { source: UdpAnnounceError },
2525

2626
/// Error returned when the domain tracker returns an scrape error.
2727
#[error("tracker scrape error: {source}")]
28-
UdpScrapeError { source: UdpScrapeError },
28+
ScrapeFailed { source: UdpScrapeError },
2929

3030
/// Error returned from a third-party library (`aquatic_udp_protocol`).
3131
#[error("internal server error: {message}, {location}")]
32-
InternalServer {
32+
Internal {
3333
location: &'static Location<'static>,
3434
message: String,
3535
},
3636

37-
/// Error returned when the request is invalid.
38-
#[error("bad request: {source}")]
39-
BadRequest {
40-
source: LocatedError<'static, dyn std::error::Error + Send + Sync>,
41-
},
42-
4337
/// Error returned when tracker requires authentication.
4438
#[error("domain tracker requires authentication but is not supported in current UDP implementation. Location: {location}")]
45-
TrackerAuthenticationRequired { location: &'static Location<'static> },
39+
AuthRequired { location: &'static Location<'static> },
4640
}
4741

4842
impl From<RequestParseError> for Error {
4943
fn from(request_parse_error: RequestParseError) -> Self {
50-
Self::RequestParseError { request_parse_error }
44+
Self::InvalidRequest {
45+
request_parse_error: request_parse_error.into(),
46+
}
5147
}
5248
}
5349

5450
impl From<UdpAnnounceError> for Error {
5551
fn from(udp_announce_error: UdpAnnounceError) -> Self {
56-
Self::UdpAnnounceError {
52+
Self::AnnounceFailed {
5753
source: udp_announce_error,
5854
}
5955
}
6056
}
6157

6258
impl From<UdpScrapeError> for Error {
6359
fn from(udp_scrape_error: UdpScrapeError) -> Self {
64-
Self::UdpScrapeError {
60+
Self::ScrapeFailed {
6561
source: udp_scrape_error,
6662
}
6763
}
6864
}
65+
66+
#[derive(Debug, PartialEq, Eq, Clone)]
67+
pub struct SendableRequestParseError {
68+
pub message: String,
69+
pub opt_connection_id: Option<ConnectionId>,
70+
pub opt_transaction_id: Option<TransactionId>,
71+
}
72+
73+
impl Display for SendableRequestParseError {
74+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75+
write!(
76+
f,
77+
"SendableRequestParseError: message: {}, connection_id: {:?}, transaction_id: {:?}",
78+
self.message, self.opt_connection_id, self.opt_transaction_id
79+
)
80+
}
81+
}
82+
83+
impl From<RequestParseError> for SendableRequestParseError {
84+
fn from(request_parse_error: RequestParseError) -> Self {
85+
let (message, opt_connection_id, opt_transaction_id) = match request_parse_error {
86+
RequestParseError::Sendable {
87+
connection_id,
88+
transaction_id,
89+
err,
90+
} => ((*err).to_string(), Some(connection_id), Some(transaction_id)),
91+
RequestParseError::Unsendable { err } => (err.to_string(), None, None),
92+
};
93+
94+
Self {
95+
message,
96+
opt_connection_id,
97+
opt_transaction_id,
98+
}
99+
}
100+
}

packages/udp-tracker-server/src/event.rs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@ use std::fmt;
22
use std::net::SocketAddr;
33
use std::time::Duration;
44

5+
use bittorrent_tracker_core::error::{AnnounceError, ScrapeError};
6+
use bittorrent_udp_tracker_core::services::announce::UdpAnnounceError;
7+
use bittorrent_udp_tracker_core::services::scrape::UdpScrapeError;
58
use torrust_tracker_metrics::label::{LabelSet, LabelValue};
69
use torrust_tracker_metrics::label_name;
710
use torrust_tracker_primitives::service_binding::ServiceBinding;
811

12+
use crate::error::Error;
13+
914
/// A UDP server event.
10-
#[derive(Debug, PartialEq, Eq, Clone)]
15+
#[derive(Debug, Clone, PartialEq)]
1116
pub enum Event {
1217
UdpRequestReceived {
1318
context: ConnectionContext,
@@ -30,6 +35,7 @@ pub enum Event {
3035
UdpError {
3136
context: ConnectionContext,
3237
kind: Option<UdpRequestKind>,
38+
error: ErrorKind,
3339
},
3440
}
3541

@@ -109,6 +115,42 @@ impl From<ConnectionContext> for LabelSet {
109115
}
110116
}
111117

118+
#[derive(Debug, Clone, PartialEq)]
119+
pub enum ErrorKind {
120+
RequestParse(String),
121+
ConnectionCookie(String),
122+
Whitelist(String),
123+
Database(String),
124+
InternalServer(String),
125+
BadRequest(String),
126+
TrackerAuthentication(String),
127+
}
128+
129+
impl From<Error> for ErrorKind {
130+
fn from(error: Error) -> Self {
131+
match error {
132+
Error::InvalidRequest { request_parse_error } => Self::RequestParse(request_parse_error.to_string()),
133+
Error::AnnounceFailed { source } => match source {
134+
UdpAnnounceError::ConnectionCookieError { source } => Self::ConnectionCookie(source.to_string()),
135+
UdpAnnounceError::TrackerCoreAnnounceError { source } => match source {
136+
AnnounceError::Whitelist(whitelist_error) => Self::Whitelist(whitelist_error.to_string()),
137+
AnnounceError::Database(error) => Self::Database(error.to_string()),
138+
},
139+
UdpAnnounceError::TrackerCoreWhitelistError { source } => Self::Whitelist(source.to_string()),
140+
},
141+
Error::ScrapeFailed { source } => match source {
142+
UdpScrapeError::ConnectionCookieError { source } => Self::ConnectionCookie(source.to_string()),
143+
UdpScrapeError::TrackerCoreScrapeError { source } => match source {
144+
ScrapeError::Whitelist(whitelist_error) => Self::Whitelist(whitelist_error.to_string()),
145+
},
146+
UdpScrapeError::TrackerCoreWhitelistError { source } => Self::Whitelist(source.to_string()),
147+
},
148+
Error::Internal { location: _, message } => Self::InternalServer(message.to_string()),
149+
Error::AuthRequired { location } => Self::TrackerAuthentication(location.to_string()),
150+
}
151+
}
152+
}
153+
112154
pub mod sender {
113155
use std::sync::Arc;
114156

packages/udp-tracker-server/src/handlers/error.rs

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
use std::net::SocketAddr;
33
use std::ops::Range;
44

5-
use aquatic_udp_protocol::{ErrorResponse, RequestParseError, Response, TransactionId};
6-
use bittorrent_udp_tracker_core::connection_cookie::{check, gen_remote_fingerprint};
5+
use aquatic_udp_protocol::{ErrorResponse, Response, TransactionId};
76
use bittorrent_udp_tracker_core::{self, UDP_TRACKER_LOG_TARGET};
87
use torrust_tracker_primitives::service_binding::ServiceBinding;
98
use tracing::{instrument, Level};
@@ -22,55 +21,62 @@ pub async fn handle_error(
2221
request_id: Uuid,
2322
opt_udp_server_stats_event_sender: &crate::event::sender::Sender,
2423
cookie_valid_range: Range<f64>,
25-
e: &Error,
26-
transaction_id: Option<TransactionId>,
24+
error: &Error,
25+
opt_transaction_id: Option<TransactionId>,
2726
) -> Response {
2827
tracing::trace!("handle error");
2928

3029
let server_socket_addr = server_service_binding.bind_address();
3130

32-
match transaction_id {
31+
log_error(error, client_socket_addr, server_socket_addr, opt_transaction_id, request_id);
32+
33+
trigger_udp_error_event(
34+
error,
35+
client_socket_addr,
36+
server_service_binding,
37+
opt_udp_server_stats_event_sender,
38+
req_kind,
39+
)
40+
.await;
41+
42+
Response::from(ErrorResponse {
43+
transaction_id: opt_transaction_id.unwrap_or(TransactionId(I32::new(0))),
44+
message: error.to_string().into(),
45+
})
46+
}
47+
48+
fn log_error(
49+
error: &Error,
50+
client_socket_addr: SocketAddr,
51+
server_socket_addr: SocketAddr,
52+
opt_transaction_id: Option<TransactionId>,
53+
request_id: Uuid,
54+
) {
55+
match opt_transaction_id {
3356
Some(transaction_id) => {
3457
let transaction_id = transaction_id.0.to_string();
35-
tracing::error!(target: UDP_TRACKER_LOG_TARGET, error = %e, %client_socket_addr, %server_socket_addr, %request_id, %transaction_id, "response error");
58+
tracing::error!(target: UDP_TRACKER_LOG_TARGET, error = %error, %client_socket_addr, %server_socket_addr, %request_id, %transaction_id, "response error");
3659
}
3760
None => {
38-
tracing::error!(target: UDP_TRACKER_LOG_TARGET, error = %e, %client_socket_addr, %server_socket_addr, %request_id, "response error");
61+
tracing::error!(target: UDP_TRACKER_LOG_TARGET, error = %error, %client_socket_addr, %server_socket_addr, %request_id, "response error");
3962
}
4063
}
64+
}
4165

42-
let e = if let Error::RequestParseError { request_parse_error } = e {
43-
match request_parse_error {
44-
RequestParseError::Sendable {
45-
connection_id,
46-
transaction_id,
47-
err,
48-
} => {
49-
if let Err(e) = check(connection_id, gen_remote_fingerprint(&client_socket_addr), cookie_valid_range) {
50-
(e.to_string(), Some(*transaction_id))
51-
} else {
52-
((*err).to_string(), Some(*transaction_id))
53-
}
54-
}
55-
RequestParseError::Unsendable { err } => (err.to_string(), transaction_id),
56-
}
57-
} else {
58-
(e.to_string(), transaction_id)
59-
};
60-
61-
if e.1.is_some() {
62-
if let Some(udp_server_stats_event_sender) = opt_udp_server_stats_event_sender.as_deref() {
63-
udp_server_stats_event_sender
64-
.send(Event::UdpError {
65-
context: ConnectionContext::new(client_socket_addr, server_service_binding),
66-
kind: req_kind,
67-
})
68-
.await;
69-
}
66+
async fn trigger_udp_error_event(
67+
error: &Error,
68+
client_socket_addr: SocketAddr,
69+
server_service_binding: ServiceBinding,
70+
opt_udp_server_stats_event_sender: &crate::event::sender::Sender,
71+
req_kind: Option<UdpRequestKind>,
72+
) {
73+
if let Some(udp_server_stats_event_sender) = opt_udp_server_stats_event_sender.as_deref() {
74+
udp_server_stats_event_sender
75+
.send(Event::UdpError {
76+
context: ConnectionContext::new(client_socket_addr, server_service_binding),
77+
kind: req_kind,
78+
error: error.clone().into(),
79+
})
80+
.await;
7081
}
71-
72-
Response::from(ErrorResponse {
73-
transaction_id: e.1.unwrap_or(TransactionId(I32::new(0))),
74-
message: e.0.into(),
75-
})
7682
}

packages/udp-tracker-server/src/handlers/mod.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use announce::handle_announce;
1313
use aquatic_udp_protocol::{Request, Response, TransactionId};
1414
use bittorrent_tracker_core::MAX_SCRAPE_TORRENTS;
1515
use bittorrent_udp_tracker_core::container::UdpTrackerCoreContainer;
16-
use bittorrent_udp_tracker_core::services::announce::UdpAnnounceError;
1716
use connect::handle_connect;
1817
use error::handle_error;
1918
use scrape::handle_scrape;
@@ -84,15 +83,6 @@ pub(crate) async fn handle_packet(
8483
{
8584
Ok((response, req_kid)) => return (response, Some(req_kid)),
8685
Err((error, transaction_id, req_kind)) => {
87-
if let Error::UdpAnnounceError {
88-
source: UdpAnnounceError::ConnectionCookieError { .. },
89-
} = error
90-
{
91-
// code-review: should we include `RequestParseError` and `BadRequest`?
92-
let mut ban_service = udp_tracker_core_container.ban_service.write().await;
93-
ban_service.increase_counter(&udp_request.from.ip());
94-
}
95-
9686
let response = handle_error(
9787
Some(req_kind.clone()),
9888
udp_request.from,
@@ -109,6 +99,14 @@ pub(crate) async fn handle_packet(
10999
}
110100
},
111101
Err(e) => {
102+
// The request payload could not be parsed, so we handle it as an error.
103+
104+
let opt_transaction_id = if let Error::InvalidRequest { request_parse_error } = e.clone() {
105+
request_parse_error.opt_transaction_id
106+
} else {
107+
None
108+
};
109+
112110
let response = handle_error(
113111
None,
114112
udp_request.from,
@@ -117,7 +115,7 @@ pub(crate) async fn handle_packet(
117115
&udp_tracker_server_container.stats_event_sender,
118116
cookie_time_values.valid_range.clone(),
119117
&e,
120-
None,
118+
opt_transaction_id,
121119
)
122120
.await;
123121

0 commit comments

Comments
 (0)