Skip to content

Announce#466

Closed
atomgardner wants to merge 15 commits intocasey:masterfrom
atomgardner:announce
Closed

Announce#466
atomgardner wants to merge 15 commits intocasey:masterfrom
atomgardner:announce

Conversation

@atomgardner
Copy link
Copy Markdown
Collaborator

@atomgardner atomgardner commented Sep 6, 2020

Here's some alpha quality work towards #255

Please take note of the "popular repository" indelibly front and centre on my Microsoft Github profile page.

@casey
Copy link
Copy Markdown
Owner

casey commented Sep 7, 2020

Currently every top-level item is in its own file, and I'd like to keep doing that. It use fzf-vim to navigate around the project, and it makes it very easy to jump between structs by filename, and not have to search within a file.

What do you think about creating a tracker submodule in tracker.rs, and then renaming UdpTrackerConn to Client and putting it into src/tracker/client.rs? There might be an HTTP tracker in the future, or there might not be, so it seems unnecessary to plan in advance for it.

It makes sense to put request/response pairs in the the same file, so, for example, AnnounceRequest and AnnounceResponse can both go in src/tracker/announce.rs.

State can go in src/tracker/state.rs.

More comments in a second, but I wanted to start with that high level thought.

Copy link
Copy Markdown
Owner

@casey casey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't get to reviewing the meat of the code, but it's getting late so I'm going to leave it at this for now.

If you check continuous integration, there are a bunch of clippy lints, you can see them locally if your run cargo clippy --all or just clippy.

Comment thread src/common.rs Outdated
Comment thread src/error.rs Outdated
Comment thread src/error.rs Outdated
Comment thread src/error.rs Outdated
Comment thread src/error.rs Outdated
Comment thread src/subcommand/torrent/announce.rs Outdated
Comment thread src/subcommand/torrent/announce.rs Outdated
Comment thread src/subcommand/torrent/announce.rs Outdated
Comment thread src/subcommand/torrent/announce.rs Outdated
Comment thread src/udp_tracker.rs Outdated
@casey
Copy link
Copy Markdown
Owner

casey commented Sep 7, 2020

I also updated this branch with new commits from master, which I shouldn't have done, since it creates nasty merge commits. Feel free to rebase and force push.

@atomgardner
Copy link
Copy Markdown
Collaborator Author

The only problem I see with your high level thought: all of the big Linux distros use https trackers.

Comment thread src/udp_tracker.rs Outdated
@casey
Copy link
Copy Markdown
Owner

casey commented Sep 8, 2020

The only problem I see with your high level thought: all of the big Linux distros use https trackers.

Sorry, I don't follow. If we add an HTTPS tracker later, can't the code be reorganized then?

@atomgardner
Copy link
Copy Markdown
Collaborator Author

Sorry, I don't follow. If we add an HTTPS tracker later, can't the code be reorganized then?

It totally can. I was stating the obvious fact that if imdl is to become super serious software, loved by users everywhere, an http tracker client must be included.

@casey
Copy link
Copy Markdown
Owner

casey commented Sep 9, 2020

It totally can. I was stating the obvious fact that if imdl is to become super serious software, loved by users everywhere, an http tracker client must be included.

100%!

@atomgardner atomgardner force-pushed the announce branch 4 times, most recently from 360ac58 to d0f5b7d Compare September 14, 2020 11:08
@atomgardner
Copy link
Copy Markdown
Collaborator Author

This build pipeline is fastidious. Let's see if I can fix the book building.

@casey
Copy link
Copy Markdown
Owner

casey commented Sep 14, 2020

There's a lot of generated documentation, and a lot of checks that make sure that all the documentation is consistent and/or up-to-date.

I think in this case it's complaining that imdl torrent announce doesn't have an entry in bin/gen/config.yaml:

https://github.com/casey/intermodal/blob/master/bin/gen/config.yaml#L5

@atomgardner atomgardner force-pushed the announce branch 2 times, most recently from 8e3e73b to b9ef0a3 Compare September 15, 2020 00:23
@atomgardner
Copy link
Copy Markdown
Collaborator Author

Interesting failure on the Windows machine. You totally saw it coming

@casey
Copy link
Copy Markdown
Owner

casey commented Oct 2, 2020

That's interesting! I'm surpised it would work on macos/linux, but fail on Windows.

@atomgardner atomgardner force-pushed the announce branch 2 times, most recently from 885f949 to 6673c2b Compare October 11, 2020 07:09
@atomgardner
Copy link
Copy Markdown
Collaborator Author

I think Window is right to send back the error. Binding to 0.0.0.0:0 was definitely the wrong address.

@casey
Copy link
Copy Markdown
Owner

casey commented Oct 11, 2020

Ahh, yeah, I guess the tests should bind to 127.0.0.1?

@atomgardner atomgardner force-pushed the announce branch 2 times, most recently from 670c69a to 4b00703 Compare October 17, 2020 01:37
Comment thread bin/gen/config.yaml
Copy link
Copy Markdown
Owner

@casey casey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made a bunch of comments, let me know what you think. Have you tried this with different tracker implementations, both OpenTracker, and anything else out there that's popular.

Comment thread src/error.rs Outdated
Comment thread src/error.rs
Comment thread src/error.rs
Comment thread src/tracker/client.rs Outdated
Comment thread src/error.rs Outdated
SymlinkRoot { root: PathBuf },
#[snafu(display("Failed to retrieve system time: {}", source))]
SystemTime { source: SystemTimeError },
#[snafu(display("The UDP tracker connection id has expired."))]
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hypothetically, shouldn't this not be a user-facing error, since the client is supposed to get a new connection ID if the old one expires?

For simplicity, I propose we deviate from the spec a little bit for now, instead of worrying about handling getting a new connection ID. For every request, let's do 4 attempts every 15 seconds, and if we don't get a response by the last attempt, we give up and return a TrackerTimeout error. This keeps us under the 60 second limit for our connection ID, and later we can implement exponential backoff and re-requesting new connection IDs.

Comment thread src/subcommand/torrent/announce.rs
Comment thread src/tracker/client.rs Outdated
self.parse_compact_peer_list(&buf[mem::size_of::<announce::Response>()..len])
}

fn roundtrip<T: Request>(&self, req: &T, rxbuf: &mut [u8]) -> Result<(T::Response, usize)> {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I like fn exchange a little better than roundtrip, round trip sounds to me like the same thing going in both directions.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of returning a usize, can send_and_retry_with_backoff and roundtrip return a &[u8], which is the written-to portion of the rxbuf? This would avoid needing to index into the rxbuf correctly.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do a little research on this. But it looks like I left myself a little comment about this:

src/client/response.rs:

pub(crate) trait Response {
  // We leak the response length so that payloads can be parsed. This should be
  // cleaner when associated types within traits can specify named lifetime
  // parameters.
  fn deserialize(buf: &[u8]) -> Result<(Self, &[u8])>

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woah—looks like this is easily doable now!!

Comment thread src/tracker/client.rs Outdated
Comment thread src/tracker/client.rs Outdated
Comment thread src/tracker/client.rs Outdated
@atomgardner
Copy link
Copy Markdown
Collaborator Author

atomgardner commented Dec 27, 2020

Yo!! I've had a bunch of changes queued up for a while now, and I think this is getting closer to usable. Let me know how it's looking.

I'm also planning to push the Peer Protocol stuff up in the next few days.

@casey
Copy link
Copy Markdown
Owner

casey commented Dec 28, 2020

Awesome! It might take me a little bit, but I'll definitely get to this within the next few days.

Copy link
Copy Markdown
Owner

@casey casey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10 days is a few, right 😅 Sorry for taking so long! I did some initial review, just really minor stuff, because I realized that I don't remember where we were in the feature.

What's new that I should be focusing on?

Comment thread bin/gen/config.yaml Outdated
code: "imdl torrent --help"

- command: imdl torrent announce
text: "Announce a torrent to its trackers and print all peers returned:"
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor reword: "Announce a torrent to trackers and print returned peers:"

Comment thread src/error.rs Outdated
Comment thread src/error.rs
Comment thread src/error.rs Outdated
Comment thread src/error.rs
#[snafu(display("UDP tracker connection id has expired."))]
TrackerConnectionExpired,
#[snafu(display("UDP tracker resolved `{}` to no useable addresses.", host_port))]
TrackerNoHosts { host_port: HostPort },
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you happen to know under what circumstances this could happen? It isn't obvious to me why to_socket_addrs would return an empty iterator, even though the stdlib docs say that it could.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding of the DNS protocol is too shallow to know whether this behaviour is possible. It seems reasonable that whoever hatched to_socket_addrs probably spent some serious time thinking it all through.

Comment thread src/error.rs
Comment thread src/error.rs Outdated
Comment thread src/host_port.rs Outdated
Comment thread src/lib.rs
clippy::map_unwrap_or,
clippy::missing_docs_in_private_items,
clippy::missing_inline_in_public_items,
clippy::needless_lifetimes,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this in a diff I just merged, so there'll be a conflict here.

@atomgardner atomgardner force-pushed the announce branch 2 times, most recently from 91a5ff8 to c4237c0 Compare January 7, 2021 08:28
@atomgardner
Copy link
Copy Markdown
Collaborator Author

Heya heya---when 10 days is a few days plus holidays, you don't count the holidays.

I've pushed up your copy changes, but, I think, the "integration test" needs a look. And you should also try the command and confirm that it works.

Copy link
Copy Markdown
Owner

@casey casey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made a bunch of comments! Almost all of them requesting things that aren't tests. I created #490, to track things that don't belong in the initial PR.

I'm changing the tests to remove the one that generates the changelog, which means you also don't have to worry about adding a commit type to commits anymore. It was good for keeping the changelog up to date, but ultimately, I think, more annoying that it was worth.

If possible, could you push diffs instead of force pushing? This makes it easier to see what's changed since I last took a look. I think I might have said something about force pushing being preferable, but I take it all back.

Comment thread src/subcommand/torrent/announce.rs Outdated
None => continue,
};

let client = tracker::Client::connect(&hostport);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be:

let client = match tracker::Client::connect(&hostport) {
  Err(e) => {
    errln!(env, "Couldn't connect to tracker: {}", e)?;
    continue;
  }
  Ok(client) => client,
};

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I wish Rust had let = … else { … } statements like swift.)

Comment thread src/subcommand/torrent/announce.rs Outdated
continue;
}

let hostport = match HostPort::from_url(&tracker) {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a URL in the torrent is malformed, we should print a warning.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, there should be a test that such URLs are skipped.

for result in metainfo.trackers() {
match result {
Ok(tracker) => trackers.push(tracker),
Err(err) => errln!(env, "Skipping malformed tracker URL: {}", err)?,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a test that malformed tracker URLs are skipped.

}

if trackers.is_empty() {
return Err(Error::MetainfoMissingTrackers);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a test that elicits this error.

}

for tracker in trackers {
if tracker.scheme() != "udp" {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a test that non-UDP tracker URLs are skipped.

Comment thread src/tracker/announce.rs
impl super::Request for Request {
type Response = Response;

fn serialize(&self) -> Vec<u8> {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could use a test. Just had a thought: Request/response pairs should all have tests that round trip a struct, where the struct is serialized, deserialized, and the output asserted to be equal to the input.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome.

Comment thread src/tracker/announce.rs Outdated

impl super::Response for Request {
#[allow(dead_code)]
fn deserialize(buf: &[u8]) -> Result<(Self, usize)> {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could use a test, and also one that elicits the error condition.

Comment thread src/tracker/announce.rs Outdated
}

impl super::Response for Response {
fn deserialize(buf: &[u8]) -> Result<(Self, usize)> {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could use a test, including one for the error condition.

Comment thread src/tracker/announce.rs
type Response = Request;

#[allow(dead_code)]
fn serialize(&self) -> Vec<u8> {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be tested.

Comment thread src/tracker/client.rs
@@ -0,0 +1,298 @@
use super::*;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be tests that elicit all of the error conditions that are possible.

This command makes use of a partially-implemented UDP tracker client to
announce an infohash and list the response.

type: added
Switch `Into<X> for Y` to `From<Y> for X`.
Tidy up out-of-vogue `to_string()` usage.
Please MacOS by binding to `0.0.0.0`.
Tidy up exchange signature
Keep futzing with IP addresses in timeout tests.
Run `cargo +nightly fmt --all`
announce: print a warning when tracker URLs are malformed
announce: attempt to get a peer list from all trackers in the metainfo
Fix up bad diff from bad rebase.
@casey
Copy link
Copy Markdown
Owner

casey commented Nov 19, 2022

I think this has gone stale 😅

@casey casey closed this Nov 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants