mirror of
https://github.com/YGGverse/aquatic.git
synced 2026-04-01 10:15:31 +00:00
use zerocopy in udp protocol, easy running transfer CI locally
This commit is contained in:
parent
af16a9e682
commit
0e12dd1b13
24 changed files with 783 additions and 652 deletions
|
|
@ -195,6 +195,8 @@ impl SocketWorker {
|
|||
|
||||
let src = CanonicalSocketAddr::new(src);
|
||||
|
||||
::log::trace!("received request bytes: {}", hex_slice(&self.buffer[..bytes_read]));
|
||||
|
||||
let request_parsable = match Request::from_bytes(
|
||||
&self.buffer[..bytes_read],
|
||||
self.config.protocol.max_scrape_torrents,
|
||||
|
|
@ -221,7 +223,7 @@ impl SocketWorker {
|
|||
if self.validator.connection_id_valid(src, connection_id) {
|
||||
let response = ErrorResponse {
|
||||
transaction_id,
|
||||
message: err.right_or("Parse error").into(),
|
||||
message: err.into(),
|
||||
};
|
||||
|
||||
local_responses.push((response.into(), src));
|
||||
|
|
@ -285,6 +287,8 @@ impl SocketWorker {
|
|||
|
||||
match request {
|
||||
Request::Connect(request) => {
|
||||
::log::trace!("received {:?} from {:?}", request, src);
|
||||
|
||||
let connection_id = self.validator.create_connection_id(src);
|
||||
|
||||
let response = Response::Connect(ConnectResponse {
|
||||
|
|
@ -295,6 +299,8 @@ impl SocketWorker {
|
|||
local_responses.push((response, src))
|
||||
}
|
||||
Request::Announce(request) => {
|
||||
::log::trace!("received {:?} from {:?}", request, src);
|
||||
|
||||
if self
|
||||
.validator
|
||||
.connection_id_valid(src, request.connection_id)
|
||||
|
|
@ -323,6 +329,8 @@ impl SocketWorker {
|
|||
}
|
||||
}
|
||||
Request::Scrape(request) => {
|
||||
::log::trace!("received {:?} from {:?}", request, src);
|
||||
|
||||
if self
|
||||
.validator
|
||||
.connection_id_valid(src, request.connection_id)
|
||||
|
|
@ -372,6 +380,8 @@ impl SocketWorker {
|
|||
canonical_addr.get_ipv6_mapped()
|
||||
};
|
||||
|
||||
::log::trace!("sending {:?} to {}, bytes: {}", response, addr, hex_slice(&cursor.get_ref()[..bytes_written]));
|
||||
|
||||
match socket.send_to(&cursor.get_ref()[..bytes_written], addr) {
|
||||
Ok(amt) if config.statistics.active() => {
|
||||
let stats = if canonical_addr.is_ipv4() {
|
||||
|
|
@ -430,3 +440,14 @@ impl SocketWorker {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn hex_slice(bytes: &[u8]) -> String {
|
||||
let mut output = String::with_capacity(bytes.len() * 3);
|
||||
|
||||
for chunk in bytes.chunks(4) {
|
||||
output.push_str(&hex::encode(chunk));
|
||||
output.push(' ');
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
|
@ -156,8 +156,8 @@ mod tests {
|
|||
}
|
||||
|
||||
let request = ScrapeRequest {
|
||||
transaction_id: TransactionId(t),
|
||||
connection_id: ConnectionId(c),
|
||||
transaction_id: TransactionId::new(t),
|
||||
connection_id: ConnectionId::new(c),
|
||||
info_hashes,
|
||||
};
|
||||
|
||||
|
|
@ -192,9 +192,9 @@ mod tests {
|
|||
(
|
||||
i,
|
||||
TorrentScrapeStatistics {
|
||||
seeders: NumberOfPeers((info_hash.0[0]) as i32),
|
||||
leechers: NumberOfPeers(0),
|
||||
completed: NumberOfDownloads(0),
|
||||
seeders: NumberOfPeers::new((info_hash.0[0]) as i32),
|
||||
leechers: NumberOfPeers::new(0),
|
||||
completed: NumberOfDownloads::new(0),
|
||||
},
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -393,7 +393,7 @@ impl SocketWorker {
|
|||
if self.validator.connection_id_valid(addr, connection_id) {
|
||||
let response = ErrorResponse {
|
||||
transaction_id,
|
||||
message: err.right_or("Parse error").into(),
|
||||
message: err.into(),
|
||||
};
|
||||
|
||||
self.local_responses.push_back((response.into(), addr));
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ impl ConnectionValidator {
|
|||
(&mut connection_id_bytes[..4]).copy_from_slice(&valid_until);
|
||||
(&mut connection_id_bytes[4..]).copy_from_slice(&hash);
|
||||
|
||||
ConnectionId(i64::from_ne_bytes(connection_id_bytes))
|
||||
ConnectionId::new(i64::from_ne_bytes(connection_id_bytes))
|
||||
}
|
||||
|
||||
pub fn connection_id_valid(
|
||||
|
|
@ -67,7 +67,7 @@ impl ConnectionValidator {
|
|||
source_addr: CanonicalSocketAddr,
|
||||
connection_id: ConnectionId,
|
||||
) -> bool {
|
||||
let bytes = connection_id.0.to_ne_bytes();
|
||||
let bytes = connection_id.0.get().to_ne_bytes();
|
||||
let (valid_until, hash) = bytes.split_at(4);
|
||||
let valid_until: [u8; 4] = valid_until.try_into().unwrap();
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ pub fn run_swarm_worker(
|
|||
&statistics_sender,
|
||||
&mut torrents.ipv4,
|
||||
request,
|
||||
ip,
|
||||
ip.into(),
|
||||
peer_valid_until,
|
||||
);
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ pub fn run_swarm_worker(
|
|||
&statistics_sender,
|
||||
&mut torrents.ipv6,
|
||||
request,
|
||||
ip,
|
||||
ip.into(),
|
||||
peer_valid_until,
|
||||
);
|
||||
|
||||
|
|
@ -126,18 +126,19 @@ fn handle_announce_request<I: Ip>(
|
|||
peer_ip: I,
|
||||
peer_valid_until: ValidUntil,
|
||||
) -> AnnounceResponse<I> {
|
||||
let max_num_peers_to_take: usize = if request.peers_wanted.0 <= 0 {
|
||||
let max_num_peers_to_take: usize = if request.peers_wanted.0.get() <= 0 {
|
||||
config.protocol.max_response_peers
|
||||
} else {
|
||||
::std::cmp::min(
|
||||
config.protocol.max_response_peers,
|
||||
request.peers_wanted.0.try_into().unwrap(),
|
||||
request.peers_wanted.0.get().try_into().unwrap(),
|
||||
)
|
||||
};
|
||||
|
||||
let torrent_data = torrents.0.entry(request.info_hash).or_default();
|
||||
|
||||
let peer_status = PeerStatus::from_event_and_bytes_left(request.event, request.bytes_left);
|
||||
let peer_status =
|
||||
PeerStatus::from_event_and_bytes_left(request.event.into(), request.bytes_left);
|
||||
|
||||
torrent_data.update_peer(
|
||||
config,
|
||||
|
|
@ -156,10 +157,14 @@ fn handle_announce_request<I: Ip>(
|
|||
};
|
||||
|
||||
AnnounceResponse {
|
||||
transaction_id: request.transaction_id,
|
||||
announce_interval: AnnounceInterval(config.protocol.peer_announce_interval),
|
||||
leechers: NumberOfPeers(torrent_data.num_leechers().try_into().unwrap_or(i32::MAX)),
|
||||
seeders: NumberOfPeers(torrent_data.num_seeders().try_into().unwrap_or(i32::MAX)),
|
||||
fixed: AnnounceResponseFixedData {
|
||||
transaction_id: request.transaction_id,
|
||||
announce_interval: AnnounceInterval::new(config.protocol.peer_announce_interval),
|
||||
leechers: NumberOfPeers::new(
|
||||
torrent_data.num_leechers().try_into().unwrap_or(i32::MAX),
|
||||
),
|
||||
seeders: NumberOfPeers::new(torrent_data.num_seeders().try_into().unwrap_or(i32::MAX)),
|
||||
},
|
||||
peers: response_peers,
|
||||
}
|
||||
}
|
||||
|
|
@ -168,8 +173,6 @@ fn handle_scrape_request<I: Ip>(
|
|||
torrents: &mut TorrentMap<I>,
|
||||
request: PendingScrapeRequest,
|
||||
) -> PendingScrapeResponse {
|
||||
const EMPTY_STATS: TorrentScrapeStatistics = create_torrent_scrape_statistics(0, 0);
|
||||
|
||||
let torrent_stats = request
|
||||
.info_hashes
|
||||
.into_iter()
|
||||
|
|
@ -178,7 +181,7 @@ fn handle_scrape_request<I: Ip>(
|
|||
.0
|
||||
.get(&info_hash)
|
||||
.map(|torrent_data| torrent_data.scrape_statistics())
|
||||
.unwrap_or(EMPTY_STATS);
|
||||
.unwrap_or_else(|| create_torrent_scrape_statistics(0, 0));
|
||||
|
||||
(i, stats)
|
||||
})
|
||||
|
|
@ -191,10 +194,10 @@ fn handle_scrape_request<I: Ip>(
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
const fn create_torrent_scrape_statistics(seeders: i32, leechers: i32) -> TorrentScrapeStatistics {
|
||||
fn create_torrent_scrape_statistics(seeders: i32, leechers: i32) -> TorrentScrapeStatistics {
|
||||
TorrentScrapeStatistics {
|
||||
seeders: NumberOfPeers(seeders),
|
||||
completed: NumberOfDownloads(0), // No implementation planned
|
||||
leechers: NumberOfPeers(leechers),
|
||||
seeders: NumberOfPeers::new(seeders),
|
||||
completed: NumberOfDownloads::new(0), // No implementation planned
|
||||
leechers: NumberOfPeers::new(leechers),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
use std::net::Ipv4Addr;
|
||||
use std::net::Ipv6Addr;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
@ -256,8 +254,8 @@ impl<I: Ip> TorrentMap<I> {
|
|||
}
|
||||
|
||||
pub struct TorrentMaps {
|
||||
pub ipv4: TorrentMap<Ipv4Addr>,
|
||||
pub ipv6: TorrentMap<Ipv6Addr>,
|
||||
pub ipv4: TorrentMap<Ipv4AddrBytes>,
|
||||
pub ipv6: TorrentMap<Ipv6AddrBytes>,
|
||||
}
|
||||
|
||||
impl Default for TorrentMaps {
|
||||
|
|
@ -312,7 +310,6 @@ impl TorrentMaps {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashSet;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use quickcheck::{quickcheck, TestResult};
|
||||
use rand::thread_rng;
|
||||
|
|
@ -326,10 +323,10 @@ mod tests {
|
|||
|
||||
peer_id
|
||||
}
|
||||
fn gen_peer(i: u32) -> Peer<Ipv4Addr> {
|
||||
fn gen_peer(i: u32) -> Peer<Ipv4AddrBytes> {
|
||||
Peer {
|
||||
ip_address: Ipv4Addr::from(i.to_be_bytes()),
|
||||
port: Port(1),
|
||||
ip_address: Ipv4AddrBytes(i.to_be_bytes()),
|
||||
port: Port::new(1),
|
||||
is_seeder: false,
|
||||
valid_until: ValidUntil::new(ServerStartInstant::new(), 0),
|
||||
}
|
||||
|
|
@ -341,7 +338,7 @@ mod tests {
|
|||
let gen_num_peers = data.0 as u32;
|
||||
let req_num_peers = data.1 as usize;
|
||||
|
||||
let mut peer_map: PeerMap<Ipv4Addr> = Default::default();
|
||||
let mut peer_map: PeerMap<Ipv4AddrBytes> = Default::default();
|
||||
|
||||
let mut opt_sender_key = None;
|
||||
let mut opt_sender_peer = None;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue