diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 511e52281..eae609ac7 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -52,10 +52,10 @@ First, let's extend the example to print out messages from the bittorrent engine about progress and events happening under the hood. libtorrent has a mechanism referred to as *alerts* to communicate back information to the client application. -Clients can poll libtorrents for new alerts via the `pop_alerts()`_ call on the -session object. This call fills in a vector of alert pointers with all new -alerts since the last call to this function. The pointers are owned by the -session object at will become invalidated by the next call to `pop_alerts()`_. +Clients can poll a session for new alerts via the `pop_alerts()`_ call. This +function fills in a vector of alert pointers with all new alerts since the last +call to this function. The pointers are owned by the session object at will +become invalidated by the next call to `pop_alerts()`_. The alerts form a class hierarchy with alert_ as the root class. Each specific kind of alert may include additional state, specific to the kind of message. All @@ -183,10 +183,10 @@ resuming torrents Since bittorrent downloads pieces of files in random order, it's not trivial to resume a partial download. When resuming a download, the bittorrent engine must -restore the state of the downloading torrent, specifically, which parts of the +restore the state of the downloading torrent, specifically which parts of the file(s) are downloaded. There are two approaches to doing this: -1. read every piece of the downloaded files from disk and compare it against the +1. read every piece of the downloaded files from disk and compare it against its expected hash. 2. save to disk the state of which pieces (and partial pieces) are downloaded, and load it back in again when resuming. @@ -197,8 +197,14 @@ employ (1) by default. To save resume data, call `save_resume_data()`_ on the torrent_handle_ object. This will ask libtorrent to generate the resume data and post it back in a save_resume_data_alert_. If generating the resume data fails for any reason, -a save_resume_data_failed_alert_ is posted instead. Exactly one of those alerts -will be posted for every call to `save_resume_data()`_. +a save_resume_data_failed_alert_ is posted instead. + +Exactly one of those alerts will be posted for every call to +`save_resume_data()`_. This is an important property when shutting down a +session with multiple torrents, every resume alert must be handled before +resuming with shut down. Any torrent may fail to save resume data, so the client +would need to keep a count of the outstanding resume files, decremented on +either save_resume_data_alert_ or save_resume_data_failed_alert_. The save_resume_data_alert_ looks something like this: @@ -212,10 +218,13 @@ The save_resume_data_alert_ looks something like this: boost::shared_ptr resume_data; }; -``resume_data`` points to an entry_ object. This represents a node or a tree -of nodes in a bencoded_ structure, which is the native encoding scheme in +``resume_data`` points to an entry_ object. This represents a node or a tree of +nodes in a bencoded_ structure, which is the native encoding scheme in bittorrent. It can be encoded into a byte buffer or file using `bencode()`_. +When adding a torrent with resume data, set the `add_torrent_params::resume_data`_ +to contain the bencoded buffer of the resume data. + example ------- @@ -230,6 +239,41 @@ Here's an updated version of the above example with the following updates: :tab-width: 2 :start-after: */ +torrent files +------------- + +To add torrent files to a session (as opposed to a magnet link), it must first +be loaded into a torrent_info_ object. + +The torrent_info_ object can be created either by filename a buffer or a +bencoded structure. When adding by filename, there's a sanity check limit on the +size of the file, for adding arbitrarily large torrents, load the file outside +of the constructor. + +The torrent_info_ object provides an opportunity to query information about the +.torrent file as well as mutating it before adding it to the session. + +bencoding +--------- + +bencoded_ structures is the default data storage format used by bittorrent, such +as .torrent files, tracker announce and scrape responses and some wire protocol +extensions. libtorrent provides an efficient framework for decoding bencoded +data through `bdecode()`_ function. + +There are two separate mechanisms for *encoding* and *decoding*. When decoding, +use the `bdecode()`_ function that returns a bdecode_node_. When encoding, use +`bencode()`_ taking an entry_ object. + +The key property of `bdecode()`_ is that it does not copy any data out of the +buffer that was parsed. It builds the tree structures of references pointing +into the buffer. The buffer must stay alive and valid for as long as the +bdecode_node_ is in use. + +For performance details on `bdecode()`_, see the `blog post about it`__. + +__ http://blog.libtorrent.org/2015/03/bdecode-parsers/ + .. _session: reference-Core.html#session .. _session_handle: reference-Core.html#session_handle .. _add_torrent_params: reference-Core.html#add_torrent_params @@ -258,4 +302,9 @@ Here's an updated version of the above example with the following updates: .. _bencoded: https://en.wikipedia.org/wiki/Bencode .. _entry: reference-Bencoding.html#entry .. _`bencode()`: reference-Bencoding.html#bencode() +.. _torrent_info: reference-Core.html#torrent_info +.. _`add_torrent_params::resume_data`: reference-Core.html#resume_data +.. _`bdecode()`: reference-Bdecoding.html#bdecode() +.. _bdecode_node: reference-Bdecoding.html#bdecode-node + diff --git a/examples/bt-get2.cpp b/examples/bt-get2.cpp index ab0873747..f8db4db04 100644 --- a/examples/bt-get2.cpp +++ b/examples/bt-get2.cpp @@ -43,12 +43,12 @@ POSSIBILITY OF SUCH DAMAGE. #include namespace lt = libtorrent; +using clock_t = std::chrono::monotonic_clock; // return the name of a torrent status enum char const* state(lt::torrent_status::state_t s) { - switch(s) - { + switch(s) { case lt::torrent_status::checking_files: return "checking"; case lt::torrent_status::downloading_metadata: return "dl metadata"; case lt::torrent_status::downloading: return "downloading"; @@ -74,8 +74,8 @@ int main(int argc, char const* argv[]) | lt::alert::status_notification); lt::session ses(pack); - lt::add_torrent_params atp; + std::chrono::time_point last_save_resume = clock_t::now(); // load resume data from disk and pass it in as we add the magnet link std::ifstream ifs(".resume_file", std::ios_base::binary); @@ -134,9 +134,15 @@ int main(int argc, char const* argv[]) // state output for the torrent ses.post_torrent_updates(); - // TODO: 3 call save_resume_data() once every 30 seconds or so + // save resume data once every 30 seconds + if (clock_t::now() - last_save_resume > seconds(30)) { + h.save_resume_data(); + } } - done: + + // TODO: ideally we should save resume data here + +done: std::cout << "\ndone, shutting down" << std::endl; } diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 87fcb83cf..79e092155 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -2182,7 +2182,7 @@ int main(int argc, char* argv[]) std::vector file_progress; h.file_progress(file_progress); std::vector file_status; - h.file_status(file_status); + h.file_status(file_status); std::vector file_prio = h.file_priorities(); std::vector::iterator f = file_status.begin(); boost::shared_ptr ti = h.torrent_file(); @@ -2295,7 +2295,7 @@ int main(int argc, char* argv[]) ses.pause(); printf("saving resume data\n"); std::vector temp; - ses.get_torrent_status(&temp, &yes, 0); + ses.get_torrent_status(&temp, &yes, 0); for (std::vector::iterator i = temp.begin(); i != temp.end(); ++i) {