Skip to content

Commit

Permalink
Fix url encoding bug of info hash in tracker requests
Browse files Browse the repository at this point in the history
  • Loading branch information
vimpunk committed Dec 5, 2020
1 parent edf250d commit 64c4554
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 69 deletions.
1 change: 1 addition & 0 deletions cratetorrent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ futures = "0.3"
hex = "0.4"
log = "0.4"
nix = "0.17"
percent-encoding = "2.1"
reqwest = "0.10"
serde = "1.0"
serde_bencode = "0.2"
Expand Down
32 changes: 23 additions & 9 deletions cratetorrent/src/metainfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,21 +166,34 @@ impl Metainfo {
return Err(MetainfoError::InvalidMetainfo);
};

let mut trackers = Vec::with_capacity(
metainfo
let mut trackers = Vec::new();
if !metainfo.announce_list.is_empty() {
let tracker_count = metainfo
.announce_list
.iter()
.map(|t| t.len())
.sum::<usize>()
+ metainfo.announce.as_ref().map(|_| 1).unwrap_or_default(),
);
for tier in metainfo.announce_list.iter() {
for tracker in tier.iter() {
trackers.push(Url::parse(&tracker)?);
+ metainfo.announce.as_ref().map(|_| 1).unwrap_or_default();
trackers.reserve(tracker_count);

for tier in metainfo.announce_list.iter() {
for tracker in tier.iter() {
let url = Url::parse(&tracker)?;
// the tracker may be over UDP, which we don't support (yet)
if url.scheme() == "http" || url.scheme() == "https" {
trackers.push(url);
}
}
}
} else if let Some(tracker) = &metainfo.announce {
let url = Url::parse(&tracker)?;
if url.scheme() == "http" || url.scheme() == "https" {
trackers.push(url);
}
}
if let Some(tracker) = &metainfo.announce {
trackers.push(Url::parse(tracker)?);

if trackers.is_empty() {
log::warn!("No HTTP trackers in metainfo");
}

// create info hash as a last step
Expand Down Expand Up @@ -229,6 +242,7 @@ mod raw {
pub struct Metainfo {
pub info: Info,
pub announce: Option<String>,
#[serde(rename = "announce-list")]
pub announce_list: Vec<Vec<String>>,
}

Expand Down
42 changes: 30 additions & 12 deletions cratetorrent/src/peer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ impl PeerSession {
// update status
self.state.tick(&self.torrent.stats);

peer_info!(
peer_trace!(
self,
"Info: download rate: {} b/s (peak: {} b/s, total: {} b) \
queue: {}, rtt: {} ms (~{} s)",
Expand Down Expand Up @@ -443,6 +443,7 @@ impl PeerSession {
bitfield.resize(self.torrent.storage.piece_count, false);

// register peer's pieces with piece picker and determine interest in it
let was_interested = self.state.is_interested;
self.state.is_interested = self
.torrent
.piece_picker
Expand All @@ -455,15 +456,7 @@ impl PeerSession {
}

// we may have become interested in peer
if self.state.is_interested {
// send interested message to peer
peer_info!(self, "Interested in peer");
sink.send(Message::Interested).await?;
self.state.uploaded_protocol_counter +=
MessageId::Interested.header_len();
}

Ok(())
self.check_interest(sink, was_interested).await
}

/// Handles messages from peer that are expected in the `Connected` state.
Expand Down Expand Up @@ -547,7 +540,7 @@ impl PeerSession {
self.handle_request_msg(block_info).await?;
}
Message::Have { piece_index } => {
self.handle_have_msg(piece_index).await?;
self.handle_have_msg(sink, piece_index).await?;
}
Message::Cancel(block_info) => {
peer_info!(
Expand Down Expand Up @@ -839,7 +832,11 @@ impl PeerSession {

/// Handles the announcement of a new piece that peer has. This may cause us
/// to become interested in peer and start making requests.
async fn handle_have_msg(&mut self, piece_index: PieceIndex) -> Result<()> {
async fn handle_have_msg(
&mut self,
sink: &mut SplitSink<Framed<TcpStream, PeerCodec>, Message>,
piece_index: PieceIndex,
) -> Result<()> {
peer_info!(self, "Received 'have' message for piece {}", piece_index);

// validate piece index
Expand All @@ -864,12 +861,33 @@ impl PeerSession {
}

// need to recalculate interest with each received piece
let was_interested = self.state.is_interested;
self.state.is_interested = self
.torrent
.piece_picker
.write()
.await
.register_piece_availability(piece_index)?;

// we may have become interested in peer
self.check_interest(sink, was_interested).await
}

/// Checks whether we have become interested in the peer.
async fn check_interest(
&mut self,
sink: &mut SplitSink<Framed<TcpStream, PeerCodec>, Message>,
was_interested: bool,
) -> Result<()> {
// we may have become interested in peer
if !was_interested && self.state.is_interested {
// send interested message to peer
peer_info!(self, "Became interested in peer");
sink.send(Message::Interested).await?;
self.state.uploaded_protocol_counter +=
MessageId::Interested.header_len();
}

Ok(())
}

Expand Down
46 changes: 27 additions & 19 deletions cratetorrent/src/torrent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,7 @@ impl Torrent {
let event = None;
self.announce_to_trackers(now, event).await?;

log::debug!(
"Torrent running for {}s",
self.state.run_duration.as_secs()
);
log::debug!("Info: elapsed: {} s", self.state.run_duration.as_secs());

Ok(())
}
Expand Down Expand Up @@ -271,6 +268,12 @@ impl Torrent {
// future in the event loop select call.
match tracker.client.announce(params).await {
Ok(resp) => {
log::info!(
"Announced to tracker {}, response: {:?}",
tracker.client,
resp
);
tracker.last_announce_time = Some(now);
if let Some(tracker_id) = resp.tracker_id {
tracker.id = Some(tracker_id);
}
Expand All @@ -288,21 +291,21 @@ impl Torrent {
warning_message
);
}
if tracker.interval.is_none() {
if let Some(interval) = resp.interval {
log::info!(
"Tracker {} interval: {} s",
tracker.client,
resp.interval.as_secs()
interval.as_secs()
);
tracker.interval = Some(resp.interval);
tracker.interval = Some(interval);
}
if tracker.min_interval.is_none() {
if let Some(min_interval) = resp.min_interval {
log::info!(
"Tracker {} min interval: {} s",
"Tracker {} min min_interval: {} s",
tracker.client,
resp.min_interval.as_secs()
min_interval.as_secs()
);
tracker.min_interval = Some(resp.min_interval);
tracker.min_interval = Some(min_interval);
}

if let (Some(seeder_count), Some(leecher_count)) =
Expand All @@ -321,14 +324,19 @@ impl Torrent {
tracker.client,
resp.peers
);
for addr in resp.peers.into_iter() {
let (session, chan) = PeerSession::new(
Arc::clone(&self.state.context),
self.disk.clone(),
addr,
);
self.peers
.push(Peer::start_outbound(session, chan))
// FIXME: only connect to a single peer for
// easier debugging purposes
if self.peers.is_empty() {
for addr in resp.peers.into_iter().take(1) {
let (session, chan) = PeerSession::new(
Arc::clone(&self.state.context),
self.disk.clone(),
addr,
);
self.peers.push(Peer::start_outbound(
session, chan,
))
}
}
}
}
Expand Down
Loading

0 comments on commit 64c4554

Please sign in to comment.