|
| 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 | +} |
0 commit comments