Skip to content

Commit fdc2543

Browse files
committed
refactor: extract UDP connect service
1 parent 4618f70 commit fdc2543

File tree

3 files changed

+180
-24
lines changed

3 files changed

+180
-24
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
//! The `connect` service.
2+
//!
3+
//! The service is responsible for handling the `connect` requests.
4+
use std::net::SocketAddr;
5+
use std::sync::Arc;
6+
7+
use aquatic_udp_protocol::ConnectionId;
8+
9+
use crate::packages::udp_tracker_core;
10+
use crate::packages::udp_tracker_core::connection_cookie::{gen_remote_fingerprint, make};
11+
12+
/// # Panics
13+
///
14+
/// IT will panic if there was an error making the connection cookie.
15+
pub async fn handle_connect(
16+
remote_addr: SocketAddr,
17+
opt_udp_stats_event_sender: &Arc<Option<Box<dyn udp_tracker_core::statistics::event::sender::Sender>>>,
18+
cookie_issue_time: f64,
19+
) -> ConnectionId {
20+
// todo: return a UDP response like the HTTP tracker instead of raw ConnectionId.
21+
22+
let connection_id = make(gen_remote_fingerprint(&remote_addr), cookie_issue_time).expect("it should be a normal value");
23+
24+
if let Some(udp_stats_event_sender) = opt_udp_stats_event_sender.as_deref() {
25+
match remote_addr {
26+
SocketAddr::V4(_) => {
27+
udp_stats_event_sender
28+
.send_event(udp_tracker_core::statistics::event::Event::Udp4Connect)
29+
.await;
30+
}
31+
SocketAddr::V6(_) => {
32+
udp_stats_event_sender
33+
.send_event(udp_tracker_core::statistics::event::Event::Udp6Connect)
34+
.await;
35+
}
36+
}
37+
}
38+
39+
connection_id
40+
}
41+
42+
#[cfg(test)]
43+
mod tests {
44+
45+
mod connect_request {
46+
47+
use std::future;
48+
use std::sync::Arc;
49+
50+
use mockall::predicate::eq;
51+
52+
use crate::packages::udp_tracker_core::connection_cookie::make;
53+
use crate::packages::udp_tracker_core::services::connect::handle_connect;
54+
use crate::packages::udp_tracker_core::services::tests::{
55+
sample_ipv4_remote_addr, sample_ipv4_remote_addr_fingerprint, sample_ipv4_socket_address, sample_ipv6_remote_addr,
56+
sample_ipv6_remote_addr_fingerprint, sample_issue_time, MockUdpStatsEventSender,
57+
};
58+
use crate::packages::{self, udp_tracker_core};
59+
60+
#[tokio::test]
61+
async fn a_connect_response_should_contain_the_same_transaction_id_as_the_connect_request() {
62+
let (udp_stats_event_sender, _udp_stats_repository) = packages::udp_tracker_core::statistics::setup::factory(false);
63+
let udp_stats_event_sender = Arc::new(udp_stats_event_sender);
64+
65+
let response = handle_connect(sample_ipv4_remote_addr(), &udp_stats_event_sender, sample_issue_time()).await;
66+
67+
assert_eq!(
68+
response,
69+
make(sample_ipv4_remote_addr_fingerprint(), sample_issue_time()).unwrap()
70+
);
71+
}
72+
73+
#[tokio::test]
74+
async fn a_connect_response_should_contain_a_new_connection_id() {
75+
let (udp_stats_event_sender, _udp_stats_repository) = packages::udp_tracker_core::statistics::setup::factory(false);
76+
let udp_stats_event_sender = Arc::new(udp_stats_event_sender);
77+
78+
let response = handle_connect(sample_ipv4_remote_addr(), &udp_stats_event_sender, sample_issue_time()).await;
79+
80+
assert_eq!(
81+
response,
82+
make(sample_ipv4_remote_addr_fingerprint(), sample_issue_time()).unwrap(),
83+
);
84+
}
85+
86+
#[tokio::test]
87+
async fn a_connect_response_should_contain_a_new_connection_id_ipv6() {
88+
let (udp_stats_event_sender, _udp_stats_repository) = packages::udp_tracker_core::statistics::setup::factory(false);
89+
let udp_stats_event_sender = Arc::new(udp_stats_event_sender);
90+
91+
let response = handle_connect(sample_ipv6_remote_addr(), &udp_stats_event_sender, sample_issue_time()).await;
92+
93+
assert_eq!(
94+
response,
95+
make(sample_ipv6_remote_addr_fingerprint(), sample_issue_time()).unwrap(),
96+
);
97+
}
98+
99+
#[tokio::test]
100+
async fn it_should_send_the_upd4_connect_event_when_a_client_tries_to_connect_using_a_ip4_socket_address() {
101+
let mut udp_stats_event_sender_mock = MockUdpStatsEventSender::new();
102+
udp_stats_event_sender_mock
103+
.expect_send_event()
104+
.with(eq(udp_tracker_core::statistics::event::Event::Udp4Connect))
105+
.times(1)
106+
.returning(|_| Box::pin(future::ready(Some(Ok(())))));
107+
let udp_stats_event_sender: Arc<Option<Box<dyn udp_tracker_core::statistics::event::sender::Sender>>> =
108+
Arc::new(Some(Box::new(udp_stats_event_sender_mock)));
109+
110+
let client_socket_address = sample_ipv4_socket_address();
111+
112+
handle_connect(client_socket_address, &udp_stats_event_sender, sample_issue_time()).await;
113+
}
114+
115+
#[tokio::test]
116+
async fn it_should_send_the_upd6_connect_event_when_a_client_tries_to_connect_using_a_ip6_socket_address() {
117+
let mut udp_stats_event_sender_mock = MockUdpStatsEventSender::new();
118+
udp_stats_event_sender_mock
119+
.expect_send_event()
120+
.with(eq(udp_tracker_core::statistics::event::Event::Udp6Connect))
121+
.times(1)
122+
.returning(|_| Box::pin(future::ready(Some(Ok(())))));
123+
let udp_stats_event_sender: Arc<Option<Box<dyn udp_tracker_core::statistics::event::sender::Sender>>> =
124+
Arc::new(Some(Box::new(udp_stats_event_sender_mock)));
125+
126+
handle_connect(sample_ipv6_remote_addr(), &udp_stats_event_sender, sample_issue_time()).await;
127+
}
128+
}
129+
}
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,51 @@
11
pub mod announce;
2+
pub mod connect;
23
pub mod scrape;
4+
5+
#[cfg(test)]
6+
pub(crate) mod tests {
7+
8+
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
9+
10+
use futures::future::BoxFuture;
11+
use mockall::mock;
12+
use tokio::sync::mpsc::error::SendError;
13+
14+
use crate::packages::udp_tracker_core;
15+
use crate::packages::udp_tracker_core::connection_cookie::gen_remote_fingerprint;
16+
17+
pub(crate) fn sample_ipv4_remote_addr() -> SocketAddr {
18+
sample_ipv4_socket_address()
19+
}
20+
21+
pub(crate) fn sample_ipv4_remote_addr_fingerprint() -> u64 {
22+
gen_remote_fingerprint(&sample_ipv4_socket_address())
23+
}
24+
25+
pub(crate) fn sample_ipv6_remote_addr() -> SocketAddr {
26+
sample_ipv6_socket_address()
27+
}
28+
29+
pub(crate) fn sample_ipv6_remote_addr_fingerprint() -> u64 {
30+
gen_remote_fingerprint(&sample_ipv6_socket_address())
31+
}
32+
33+
pub(crate) fn sample_ipv4_socket_address() -> SocketAddr {
34+
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080)
35+
}
36+
37+
fn sample_ipv6_socket_address() -> SocketAddr {
38+
SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 8080)
39+
}
40+
41+
pub(crate) fn sample_issue_time() -> f64 {
42+
1_000_000_000_f64
43+
}
44+
45+
mock! {
46+
pub(crate) UdpStatsEventSender {}
47+
impl udp_tracker_core::statistics::event::sender::Sender for UdpStatsEventSender {
48+
fn send_event(&self, event: udp_tracker_core::statistics::event::Event) -> BoxFuture<'static,Option<Result<(),SendError<udp_tracker_core::statistics::event::Event> > > > ;
49+
}
50+
}
51+
}

src/servers/udp/handlers/connect.rs

+2-24
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,9 @@ use aquatic_udp_protocol::{ConnectRequest, ConnectResponse, ConnectionId, Respon
66
use tracing::{instrument, Level};
77

88
use crate::packages::udp_tracker_core;
9-
use crate::packages::udp_tracker_core::connection_cookie::{gen_remote_fingerprint, make};
109

1110
/// It handles the `Connect` request. Refer to [`Connect`](crate::servers::udp#connect)
1211
/// request for more information.
13-
///
14-
/// # Errors
15-
///
16-
/// This function does not ever return an error.
1712
#[instrument(fields(transaction_id), skip(opt_udp_stats_event_sender), ret(level = Level::TRACE))]
1813
pub async fn handle_connect(
1914
remote_addr: SocketAddr,
@@ -22,27 +17,10 @@ pub async fn handle_connect(
2217
cookie_issue_time: f64,
2318
) -> Response {
2419
tracing::Span::current().record("transaction_id", request.transaction_id.0.to_string());
25-
2620
tracing::trace!("handle connect");
2721

28-
// todo: move to connect service in udp_tracker_core
29-
30-
let connection_id = make(gen_remote_fingerprint(&remote_addr), cookie_issue_time).expect("it should be a normal value");
31-
32-
if let Some(udp_stats_event_sender) = opt_udp_stats_event_sender.as_deref() {
33-
match remote_addr {
34-
SocketAddr::V4(_) => {
35-
udp_stats_event_sender
36-
.send_event(udp_tracker_core::statistics::event::Event::Udp4Connect)
37-
.await;
38-
}
39-
SocketAddr::V6(_) => {
40-
udp_stats_event_sender
41-
.send_event(udp_tracker_core::statistics::event::Event::Udp6Connect)
42-
.await;
43-
}
44-
}
45-
}
22+
let connection_id =
23+
udp_tracker_core::services::connect::handle_connect(remote_addr, opt_udp_stats_event_sender, cookie_issue_time).await;
4624

4725
build_response(*request, connection_id)
4826
}

0 commit comments

Comments
 (0)