1+ //! Announce handler.
2+ //!
3+ //! Handling `announce` requests is the most important task for a `BitTorrent`
4+ //! tracker.
5+ //!
6+ //! A `BitTorrent` swarm is a network of peers that are all trying to download
7+ //! the same torrent. When a peer wants to find other peers it announces itself
8+ //! to the swarm via the tracker. The peer sends its data to the tracker so that
9+ //! the tracker can add it to the swarm. The tracker responds to the peer with
10+ //! the list of other peers in the swarm so that the peer can contact them to
11+ //! start downloading pieces of the file from them.
12+ //!
13+ //! Once you have instantiated the `AnnounceHandler` you can `announce` a new [`peer::Peer`](torrust_tracker_primitives) with:
14+ //!
15+ //! ```rust,no_run
16+ //! use std::net::SocketAddr;
17+ //! use std::net::IpAddr;
18+ //! use std::net::Ipv4Addr;
19+ //! use std::str::FromStr;
20+ //!
21+ //! use aquatic_udp_protocol::{AnnounceEvent, NumberOfBytes, PeerId};
22+ //! use torrust_tracker_primitives::DurationSinceUnixEpoch;
23+ //! use torrust_tracker_primitives::peer;
24+ //! use bittorrent_primitives::info_hash::InfoHash;
25+ //!
26+ //! let info_hash = InfoHash::from_str("3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0").unwrap();
27+ //!
28+ //! let peer = peer::Peer {
29+ //! peer_id: PeerId(*b"-qB00000000000000001"),
30+ //! peer_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1)), 8081),
31+ //! updated: DurationSinceUnixEpoch::new(1_669_397_478_934, 0),
32+ //! uploaded: NumberOfBytes::new(0),
33+ //! downloaded: NumberOfBytes::new(0),
34+ //! left: NumberOfBytes::new(0),
35+ //! event: AnnounceEvent::Completed,
36+ //! };
37+ //!
38+ //! let peer_ip = IpAddr::V4(Ipv4Addr::from_str("126.0.0.1").unwrap());
39+ //! ```
40+ //!
41+ //! ```text
42+ //! let announce_data = announce_handler.announce(&info_hash, &mut peer, &peer_ip).await;
43+ //! ```
44+ //!
45+ //! The handler returns the list of peers for the torrent with the infohash
46+ //! `3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0`, filtering out the peer that is
47+ //! making the `announce` request.
48+ //!
49+ //! > **NOTICE**: that the peer argument is mutable because the handler can
50+ //! > change the peer IP if the peer is using a loopback IP.
51+ //!
52+ //! The `peer_ip` argument is the resolved peer ip. It's a common practice that
53+ //! trackers ignore the peer ip in the `announce` request params, and resolve
54+ //! the peer ip using the IP of the client making the request. As the tracker is
55+ //! a domain service, the peer IP must be provided for the handler user, which
56+ //! is usually a higher component with access the the request metadata, for
57+ //! example, connection data, proxy headers, etcetera.
58+ //!
59+ //! The returned struct is:
60+ //!
61+ //! ```rust,no_run
62+ //! use torrust_tracker_primitives::peer;
63+ //! use torrust_tracker_configuration::AnnouncePolicy;
64+ //!
65+ //! pub struct AnnounceData {
66+ //! pub peers: Vec<peer::Peer>,
67+ //! pub swarm_stats: SwarmMetadata,
68+ //! pub policy: AnnouncePolicy, // the tracker announce policy.
69+ //! }
70+ //!
71+ //! pub struct SwarmMetadata {
72+ //! pub completed: u32, // The number of peers that have ever completed downloading
73+ //! pub seeders: u32, // The number of active peers that have completed downloading (seeders)
74+ //! pub leechers: u32, // The number of active peers that have not completed downloading (leechers)
75+ //! }
76+ //!
77+ //! // Core tracker configuration
78+ //! pub struct AnnounceInterval {
79+ //! // ...
80+ //! pub interval: u32, // Interval in seconds that the client should wait between sending regular announce requests to the tracker
81+ //! pub interval_min: u32, // Minimum announce interval. Clients must not reannounce more frequently than this
82+ //! // ...
83+ //! }
84+ //! ```
85+ //!
86+ //! ## Related BEPs:
87+ //!
88+ //! Refer to `BitTorrent` BEPs and other sites for more information about the `announce` request:
89+ //!
90+ //! - [BEP 3. The `BitTorrent` Protocol Specification](https://www.bittorrent.org/beps/bep_0003.html)
91+ //! - [BEP 23. Tracker Returns Compact Peer Lists](https://www.bittorrent.org/beps/bep_0023.html)
92+ //! - [Vuze docs](https://wiki.vuze.com/w/Announce)
193use std:: net:: IpAddr ;
294use std:: sync:: Arc ;
395
@@ -10,18 +102,20 @@ use torrust_tracker_primitives::swarm_metadata::SwarmMetadata;
10102use super :: torrent:: repository:: in_memory:: InMemoryTorrentRepository ;
11103use super :: torrent:: repository:: persisted:: DatabasePersistentTorrentRepository ;
12104
105+ /// Handles `announce` requests from `BitTorrent` clients.
13106pub struct AnnounceHandler {
14107 /// The tracker configuration.
15108 config : Core ,
16109
17- /// The in-memory torrents repository .
110+ /// Repository for in-memory torrent data .
18111 in_memory_torrent_repository : Arc < InMemoryTorrentRepository > ,
19112
20- /// The persistent torrents repository .
113+ /// Repository for persistent torrent data (database) .
21114 db_torrent_repository : Arc < DatabasePersistentTorrentRepository > ,
22115}
23116
24117impl AnnounceHandler {
118+ /// Creates a new `AnnounceHandler`.
25119 #[ must_use]
26120 pub fn new (
27121 config : & Core ,
@@ -35,9 +129,20 @@ impl AnnounceHandler {
35129 }
36130 }
37131
38- /// It handles an announce request.
132+ /// Processes an announce request from a peer .
39133 ///
40134 /// BEP 03: [The `BitTorrent` Protocol Specification](https://www.bittorrent.org/beps/bep_0003.html).
135+ ///
136+ /// # Parameters
137+ ///
138+ /// - `info_hash`: The unique identifier of the torrent.
139+ /// - `peer`: The peer announcing itself (may be updated if IP is adjusted).
140+ /// - `remote_client_ip`: The IP address of the client making the request.
141+ /// - `peers_wanted`: Specifies how many peers the client wants in the response.
142+ ///
143+ /// # Returns
144+ ///
145+ /// An `AnnounceData` struct containing the list of peers, swarm statistics, and tracker policy.
41146 pub fn announce (
42147 & self ,
43148 info_hash : & InfoHash ,
@@ -77,9 +182,8 @@ impl AnnounceHandler {
77182 }
78183 }
79184
80- /// It updates the torrent entry in memory, it also stores in the database
81- /// the torrent info data which is persistent, and finally return the data
82- /// needed for a `announce` request response.
185+ /// Updates the torrent data in memory, persists statistics if needed, and
186+ /// returns the updated swarm stats.
83187 #[ must_use]
84188 fn upsert_peer_and_get_stats ( & self , info_hash : & InfoHash , peer : & peer:: Peer ) -> SwarmMetadata {
85189 let swarm_metadata_before = self . in_memory_torrent_repository . get_swarm_metadata ( info_hash) ;
@@ -95,7 +199,7 @@ impl AnnounceHandler {
95199 swarm_metadata_after
96200 }
97201
98- /// It stores the torrents stats into the database ( if persistency is enabled) .
202+ /// Persists torrent statistics to the database if persistence is enabled.
99203 fn persist_stats ( & self , info_hash : & InfoHash , swarm_metadata : & SwarmMetadata ) {
100204 if self . config . tracker_policy . persistent_torrent_completed_stat {
101205 let completed = swarm_metadata. downloaded ;
@@ -106,22 +210,25 @@ impl AnnounceHandler {
106210 }
107211}
108212
109- /// How many peers the peer announcing wants in the announce response.
213+ /// Specifies how many peers a client wants in the announce response.
110214#[ derive( Clone , Debug , PartialEq , Default ) ]
111215pub enum PeersWanted {
112- /// The peer wants as many peers as possible in the announce response .
216+ /// Request as many peers as possible (default behavior) .
113217 #[ default]
114218 AsManyAsPossible ,
115- /// The peer only wants a certain amount of peers in the announce response.
219+
220+ /// Request a specific number of peers.
116221 Only { amount : usize } ,
117222}
118223
119224impl PeersWanted {
225+ /// Request a specific number of peers.
120226 #[ must_use]
121227 pub fn only ( limit : u32 ) -> Self {
122228 limit. into ( )
123229 }
124230
231+ /// Returns the maximum number of peers allowed based on the request and tracker limit.
125232 fn limit ( & self ) -> usize {
126233 match self {
127234 PeersWanted :: AsManyAsPossible => TORRENT_PEERS_LIMIT ,
@@ -159,6 +266,10 @@ impl From<u32> for PeersWanted {
159266 }
160267}
161268
269+ /// Assigns the correct IP address to a peer based on tracker settings.
270+ ///
271+ /// If the client IP is a loopback address and the tracker has an external IP
272+ /// configured, the external IP will be assigned to the peer.
162273#[ must_use]
163274fn assign_ip_address_to_peer ( remote_client_ip : & IpAddr , tracker_external_ip : Option < IpAddr > ) -> IpAddr {
164275 if let Some ( host_ip) = tracker_external_ip. filter ( |_| remote_client_ip. is_loopback ( ) ) {
0 commit comments