Monday, February 2, 2009

Progress - Torrents to Disk

New - Choosing where to save
I've taken the path of least resistance in choosing how to save to disk. After opening a torrent file, I've used the nsIFilePicker for selecting a folder (use the constant Components.interfaces.nsIFilePicker.modeGetFolder when calling init), and then stored the returned nsILocalFile in a central location. Initially, only the PieceManager was informed of this nsILocalFile, however it's of greater value if the folder is known to all the components: the original .torrent is saved into the folder, and any tracker responses are also saved into the folder. This has made debugging easier, with the help of GHex, the Gnome Hex Editor.

Changes to Tracker
The tracker is the first port of call after a .torrent file is opened (hohoho). Trackers communicate via HTTP, responding to a well formed URI with a bencoded (Bittorrent specific encoding) data structure detailing various things about the tracker and other peers.
When I first started testing using the latest Ubuntu ISO, I ran into my first compatibility problem. There are a couple of ways of encoding the information on other peers, let's call them 'original' and 'compact'. Compact is specified by an optional query string parameter in the request to the tracker, and I wasn't providing that setting. As a result, the tracker didn't fall back to original, it instead rejected the request with a plain text reply, along the lines of get a new client. Unexpected, particularly when users won't see that response, and also being terribly useless for developers. Fixed by adding compact=1 and handling the compact encoded peers.
The latest change was for friendliness. The tracker provides minimum timeouts on tracker requests, which were being ignored.

Little Things
Saving files sucks. There's all the checking for paths existing, checking if a file can be created, etc. Saving with nsILocalFile rocks. The create method for nsIFile (the interface nsILocalFile extends) automatically creates paths. What if you've been told to save in a folder, but it already has a file with the same name? The createUnique method means you don't have to write the associated conflict resolution logic (unless the intention was to replace that file - the nsIFilePicker modeSave automates the asking of that question if you need it). Additionally, a .torrent file lists the download files with their paths. Recreating that folder structure can be error prone - if there were ".." components, it's possible the saving could end up somewhere it shouldn't (eg. writing into a folder mentioned in PATH environment var in Windows). Though I need to test to confirm, I use appendWithRelativePath on nsILocalFile to build the path from the initial save directory to the specified file . This should, I need to test, remove the unintended path exploitation. If it doesn't, oh well, we'll fix that.

Next: Early 3rd Release - with Saving goodness!

No comments:

Post a Comment