added new session functions to more efficiently query torrent status

This commit is contained in:
Arvid Norberg 2011-02-01 09:48:28 +00:00
parent 6692f05655
commit b842815710
15 changed files with 1089 additions and 716 deletions

View File

@ -1,3 +1,4 @@
* added new session functions to more efficiently query torrent status
* added alerts for added and removed torrents
* expanded plugin interface to support session wide states
* made the metadata block requesting algorithm more robust against hash check failures

View File

@ -62,16 +62,17 @@
</ul>
</li>
<li><a class="reference internal" href="#plugin-interface" id="id3">plugin interface</a></li>
<li><a class="reference internal" href="#torrent-plugin" id="id4">torrent_plugin</a><ul>
<li><a class="reference internal" href="#new-connection" id="id5">new_connection()</a></li>
<li><a class="reference internal" href="#on-piece-pass-on-piece-fail" id="id6">on_piece_pass() on_piece_fail()</a></li>
<li><a class="reference internal" href="#tick" id="id7">tick()</a></li>
<li><a class="reference internal" href="#on-pause-on-resume" id="id8">on_pause() on_resume()</a></li>
<li><a class="reference internal" href="#on-files-checked" id="id9">on_files_checked()</a></li>
<li><a class="reference internal" href="#plugin" id="id4">plugin</a></li>
<li><a class="reference internal" href="#torrent-plugin" id="id5">torrent_plugin</a><ul>
<li><a class="reference internal" href="#new-connection" id="id6">new_connection()</a></li>
<li><a class="reference internal" href="#on-piece-pass-on-piece-fail" id="id7">on_piece_pass() on_piece_fail()</a></li>
<li><a class="reference internal" href="#tick" id="id8">tick()</a></li>
<li><a class="reference internal" href="#on-pause-on-resume" id="id9">on_pause() on_resume()</a></li>
<li><a class="reference internal" href="#on-files-checked" id="id10">on_files_checked()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#peer-plugin" id="id10">peer_plugin</a></li>
<li><a class="reference internal" href="#disk-buffer-holder" id="id11">disk_buffer_holder</a></li>
<li><a class="reference internal" href="#peer-plugin" id="id11">peer_plugin</a></li>
<li><a class="reference internal" href="#disk-buffer-holder" id="id12">disk_buffer_holder</a></li>
</ul>
</div>
<p>libtorrent has a plugin interface for implementing extensions to the protocol.
@ -85,6 +86,8 @@ to fit a particular (closed) network.</p>
<li>add data and parse data from the extension handshake.</li>
<li>send extension messages and standard bittorrent messages.</li>
<li>override or block the handling of standard bittorrent messages.</li>
<li>save and restore state via the session state</li>
<li>see all alerts that are posted</li>
</ul>
<div class="section" id="a-word-of-caution">
<h2>a word of caution</h2>
@ -92,24 +95,30 @@ to fit a particular (closed) network.</p>
dead locks and race conditions. Since a plugin has access to internal
structures it is also quite easy to sabotage libtorrent's operation.</p>
<p>All the callbacks in this interface are called with the main libtorrent thread
mutex locked. And they are always called from the libtorrent main thread. In
mutex locked. And they are always called from the libtorrent network thread. In
case portions of your plugin are called from other threads, typically the main
thread, you cannot use any of the member functions on the internal structures
in libtorrent, since those require the mutex to be locked. Futhermore, you would
also need to have a mutex on your own shared data within the plugin, to make
sure it is not accessed at the same time from the libtorrent thread (through a
callback). See <a class="reference external" href="http://www.boost.org/doc/html/mutex.html">boost thread's mutex</a>. If you need to send out a message from
another thread, use an internal queue, and do the actual sending in <tt class="docutils literal"><span class="pre">tick()</span></tt>.</p>
another thread, it is advised to use an internal queue, and do the actual
sending in <tt class="docutils literal"><span class="pre">tick()</span></tt>.</p>
<p>Since the plugin interface gives you easy access to internal structures, it
is not supported as a stable API. Plugins should be considered spcific to a
specific version of libtorrent. Although, in practice the internals mostly
don't change that dramatically.</p>
</div>
</div>
<div class="section" id="plugin-interface">
<h1>plugin interface</h1>
<p>The plugin interface consists of two base classes that the plugin may
implement. These are called <tt class="docutils literal"><span class="pre">torrent_plugin</span></tt> and <tt class="docutils literal"><span class="pre">peer_plugin</span></tt>. They are
both found in the <tt class="docutils literal"><span class="pre">&lt;libtorrent/extensions.hpp&gt;</span></tt> header.</p>
<p>These plugins are instantiated for each torrent and possibly each peer,
<p>The plugin interface consists of three base classes that the plugin may
implement. These are called <tt class="docutils literal"><span class="pre">plugin</span></tt>, <tt class="docutils literal"><span class="pre">torrent_plugin</span></tt> and <tt class="docutils literal"><span class="pre">peer_plugin</span></tt>.
They are found in the <tt class="docutils literal"><span class="pre">&lt;libtorrent/extensions.hpp&gt;</span></tt> header.</p>
<p>These plugins are instantiated for each session, torrent and possibly each peer,
respectively.</p>
<p>This is done by passing in a function or function object to
<p>For plugins that only need per torrent state, it is enough to only implement
<tt class="docutils literal"><span class="pre">torrent_plugin</span></tt> and pass a constructor function or function object to
<tt class="docutils literal"><span class="pre">session::add_extension()</span></tt> or <tt class="docutils literal"><span class="pre">torrent_handle::add_extension()</span></tt> (if the
torrent has already been started and you want to hook in the extension at
run-time).</p>
@ -125,6 +134,25 @@ may or may not be 0. If it is a null pointer, the extension is simply ignored
for this torrent. If it is a valid pointer (to a class inheriting
<tt class="docutils literal"><span class="pre">torrent_plugin</span></tt>), it will be associated with this torrent and callbacks
will be made on torrent events.</p>
<p>For more elaborate plugins which require session wide state, you would
implement <tt class="docutils literal"><span class="pre">plugin</span></tt>, construct an object (in a <tt class="docutils literal"><span class="pre">boost::shared_ptr</span></tt>) and pass
it in to <tt class="docutils literal"><span class="pre">session::add_extension()</span></tt>.</p>
</div>
<div class="section" id="plugin">
<h1>plugin</h1>
<pre class="literal-block">
struct plugin
{
virtual ~plugin();
virtual boost::shared_ptr&lt;torrent_plugin&gt; new_torrent(torrent* t, void* user);
virtual void added(boost::weak_ptr&lt;aux::session_impl&gt; s);
virtual void on_alert(alert const* a);
virtual void on_tick();
virtual void save_state(entry&amp; ent) const;
virtual void load_state(lazy_entry const&amp; ent);
};
</pre>
</div>
<div class="section" id="torrent-plugin">
<h1>torrent_plugin</h1>

View File

@ -69,257 +69,261 @@
<li><a class="reference internal" href="#add-torrent" id="id23">add_torrent()</a></li>
<li><a class="reference internal" href="#remove-torrent" id="id24">remove_torrent()</a></li>
<li><a class="reference internal" href="#find-torrent-get-torrents" id="id25">find_torrent() get_torrents()</a></li>
<li><a class="reference internal" href="#load-asnum-db-load-country-db-as-for-ip" id="id26">load_asnum_db() load_country_db() as_for_ip()</a></li>
<li><a class="reference internal" href="#set-ip-filter" id="id27">set_ip_filter()</a></li>
<li><a class="reference internal" href="#get-ip-filter" id="id28">get_ip_filter()</a></li>
<li><a class="reference internal" href="#status" id="id29">status()</a></li>
<li><a class="reference internal" href="#get-cache-status" id="id30">get_cache_status()</a></li>
<li><a class="reference internal" href="#get-cache-info" id="id31">get_cache_info()</a></li>
<li><a class="reference internal" href="#is-listening-listen-port-listen-on" id="id32">is_listening() listen_port() listen_on()</a></li>
<li><a class="reference internal" href="#set-alert-mask" id="id33">set_alert_mask()</a></li>
<li><a class="reference internal" href="#pop-alert-wait-for-alert-set-alert-queue-size-limit" id="id34">pop_alert() wait_for_alert() set_alert_queue_size_limit()</a></li>
<li><a class="reference internal" href="#add-feed" id="id35">add_feed()</a></li>
<li><a class="reference internal" href="#remove-feed" id="id36">remove_feed()</a></li>
<li><a class="reference internal" href="#get-feeds" id="id37">get_feeds()</a></li>
<li><a class="reference internal" href="#add-extension" id="id38">add_extension()</a></li>
<li><a class="reference internal" href="#set-settings-set-pe-settings" id="id39">set_settings() set_pe_settings()</a></li>
<li><a class="reference internal" href="#set-proxy-proxy" id="id40">set_proxy() proxy()</a></li>
<li><a class="reference internal" href="#set-i2p-proxy-i2p-proxy" id="id41">set_i2p_proxy() i2p_proxy()</a></li>
<li><a class="reference internal" href="#start-dht-stop-dht-set-dht-settings-dht-state-is-dht-running" id="id42">start_dht() stop_dht() set_dht_settings() dht_state() is_dht_running()</a></li>
<li><a class="reference internal" href="#add-dht-node-add-dht-router" id="id43">add_dht_node() add_dht_router()</a></li>
<li><a class="reference internal" href="#start-lsd-stop-lsd" id="id44">start_lsd() stop_lsd()</a></li>
<li><a class="reference internal" href="#start-upnp-stop-upnp" id="id45">start_upnp() stop_upnp()</a></li>
<li><a class="reference internal" href="#start-natpmp-stop-natpmp" id="id46">start_natpmp() stop_natpmp()</a></li>
<li><a class="reference internal" href="#get-torrent-status-refresh-torrent-status" id="id26">get_torrent_status() refresh_torrent_status()</a></li>
<li><a class="reference internal" href="#load-asnum-db-load-country-db-as-for-ip" id="id27">load_asnum_db() load_country_db() as_for_ip()</a></li>
<li><a class="reference internal" href="#set-ip-filter" id="id28">set_ip_filter()</a></li>
<li><a class="reference internal" href="#get-ip-filter" id="id29">get_ip_filter()</a></li>
<li><a class="reference internal" href="#status" id="id30">status()</a></li>
<li><a class="reference internal" href="#get-cache-status" id="id31">get_cache_status()</a></li>
<li><a class="reference internal" href="#get-cache-info" id="id32">get_cache_info()</a></li>
<li><a class="reference internal" href="#is-listening-listen-port-listen-on" id="id33">is_listening() listen_port() listen_on()</a></li>
<li><a class="reference internal" href="#set-alert-mask" id="id34">set_alert_mask()</a></li>
<li><a class="reference internal" href="#pop-alert-wait-for-alert" id="id35">pop_alert() wait_for_alert()</a></li>
<li><a class="reference internal" href="#add-feed" id="id36">add_feed()</a></li>
<li><a class="reference internal" href="#remove-feed" id="id37">remove_feed()</a></li>
<li><a class="reference internal" href="#get-feeds" id="id38">get_feeds()</a></li>
<li><a class="reference internal" href="#add-extension" id="id39">add_extension()</a></li>
<li><a class="reference internal" href="#set-settings-set-pe-settings" id="id40">set_settings() set_pe_settings()</a></li>
<li><a class="reference internal" href="#set-proxy-proxy" id="id41">set_proxy() proxy()</a></li>
<li><a class="reference internal" href="#set-i2p-proxy-i2p-proxy" id="id42">set_i2p_proxy() i2p_proxy()</a></li>
<li><a class="reference internal" href="#start-dht-stop-dht-set-dht-settings-dht-state-is-dht-running" id="id43">start_dht() stop_dht() set_dht_settings() dht_state() is_dht_running()</a></li>
<li><a class="reference internal" href="#add-dht-node-add-dht-router" id="id44">add_dht_node() add_dht_router()</a></li>
<li><a class="reference internal" href="#start-lsd-stop-lsd" id="id45">start_lsd() stop_lsd()</a></li>
<li><a class="reference internal" href="#start-upnp-stop-upnp" id="id46">start_upnp() stop_upnp()</a></li>
<li><a class="reference internal" href="#start-natpmp-stop-natpmp" id="id47">start_natpmp() stop_natpmp()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#entry" id="id47">entry</a><ul>
<li><a class="reference internal" href="#integer-string-list-dict-type" id="id48">integer() string() list() dict() type()</a></li>
<li><a class="reference internal" href="#operator" id="id49">operator[]</a></li>
<li><a class="reference internal" href="#find-key" id="id50">find_key()</a></li>
<li><a class="reference internal" href="#entry" id="id48">entry</a><ul>
<li><a class="reference internal" href="#integer-string-list-dict-type" id="id49">integer() string() list() dict() type()</a></li>
<li><a class="reference internal" href="#operator" id="id50">operator[]</a></li>
<li><a class="reference internal" href="#find-key" id="id51">find_key()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#torrent-info" id="id51">torrent_info</a><ul>
<li><a class="reference internal" href="#id3" id="id52">torrent_info()</a></li>
<li><a class="reference internal" href="#add-tracker" id="id53">add_tracker()</a></li>
<li><a class="reference internal" href="#files-orig-files" id="id54">files() orig_files()</a></li>
<li><a class="reference internal" href="#remap-files" id="id55">remap_files()</a></li>
<li><a class="reference internal" href="#rename-file" id="id56">rename_file()</a></li>
<li><a class="reference internal" href="#begin-files-end-files-rbegin-files-rend-files" id="id57">begin_files() end_files() rbegin_files() rend_files()</a></li>
<li><a class="reference internal" href="#num-files-file-at" id="id58">num_files() file_at()</a></li>
<li><a class="reference internal" href="#map-block" id="id59">map_block()</a></li>
<li><a class="reference internal" href="#map-file" id="id60">map_file()</a></li>
<li><a class="reference internal" href="#add-url-seed-add-http-seed" id="id61">add_url_seed() add_http_seed()</a></li>
<li><a class="reference internal" href="#trackers" id="id62">trackers()</a></li>
<li><a class="reference internal" href="#total-size-piece-length-piece-size-num-pieces" id="id63">total_size() piece_length() piece_size() num_pieces()</a></li>
<li><a class="reference internal" href="#hash-for-piece-hash-for-piece-ptr-info-hash" id="id64">hash_for_piece() hash_for_piece_ptr() info_hash()</a></li>
<li><a class="reference internal" href="#name-comment-creation-date-creator" id="id65">name() comment() creation_date() creator()</a></li>
<li><a class="reference internal" href="#priv" id="id66">priv()</a></li>
<li><a class="reference internal" href="#nodes" id="id67">nodes()</a></li>
<li><a class="reference internal" href="#add-node" id="id68">add_node()</a></li>
<li><a class="reference internal" href="#metadata-metadata-size" id="id69">metadata() metadata_size()</a></li>
<li><a class="reference internal" href="#torrent-info" id="id52">torrent_info</a><ul>
<li><a class="reference internal" href="#id3" id="id53">torrent_info()</a></li>
<li><a class="reference internal" href="#add-tracker" id="id54">add_tracker()</a></li>
<li><a class="reference internal" href="#files-orig-files" id="id55">files() orig_files()</a></li>
<li><a class="reference internal" href="#remap-files" id="id56">remap_files()</a></li>
<li><a class="reference internal" href="#rename-file" id="id57">rename_file()</a></li>
<li><a class="reference internal" href="#begin-files-end-files-rbegin-files-rend-files" id="id58">begin_files() end_files() rbegin_files() rend_files()</a></li>
<li><a class="reference internal" href="#num-files-file-at" id="id59">num_files() file_at()</a></li>
<li><a class="reference internal" href="#map-block" id="id60">map_block()</a></li>
<li><a class="reference internal" href="#map-file" id="id61">map_file()</a></li>
<li><a class="reference internal" href="#add-url-seed-add-http-seed" id="id62">add_url_seed() add_http_seed()</a></li>
<li><a class="reference internal" href="#trackers" id="id63">trackers()</a></li>
<li><a class="reference internal" href="#total-size-piece-length-piece-size-num-pieces" id="id64">total_size() piece_length() piece_size() num_pieces()</a></li>
<li><a class="reference internal" href="#hash-for-piece-hash-for-piece-ptr-info-hash" id="id65">hash_for_piece() hash_for_piece_ptr() info_hash()</a></li>
<li><a class="reference internal" href="#name-comment-creation-date-creator" id="id66">name() comment() creation_date() creator()</a></li>
<li><a class="reference internal" href="#priv" id="id67">priv()</a></li>
<li><a class="reference internal" href="#nodes" id="id68">nodes()</a></li>
<li><a class="reference internal" href="#add-node" id="id69">add_node()</a></li>
<li><a class="reference internal" href="#metadata-metadata-size" id="id70">metadata() metadata_size()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#torrent-handle" id="id70">torrent_handle</a><ul>
<li><a class="reference internal" href="#set-piece-deadline" id="id71">set_piece_deadline()</a></li>
<li><a class="reference internal" href="#piece-availability" id="id72">piece_availability()</a></li>
<li><a class="reference internal" href="#piece-priority-prioritize-pieces-piece-priorities" id="id73">piece_priority() prioritize_pieces() piece_priorities()</a></li>
<li><a class="reference internal" href="#file-priority-prioritize-files-file-priorities" id="id74">file_priority() prioritize_files() file_priorities()</a></li>
<li><a class="reference internal" href="#file-progress" id="id75">file_progress()</a></li>
<li><a class="reference internal" href="#save-path" id="id76">save_path()</a></li>
<li><a class="reference internal" href="#move-storage" id="id77">move_storage()</a></li>
<li><a class="reference internal" href="#id4" id="id78">rename_file()</a></li>
<li><a class="reference internal" href="#get-storage-impl" id="id79">get_storage_impl()</a></li>
<li><a class="reference internal" href="#super-seeding" id="id80">super_seeding()</a></li>
<li><a class="reference internal" href="#add-piece" id="id81">add_piece()</a></li>
<li><a class="reference internal" href="#read-piece" id="id82">read_piece()</a></li>
<li><a class="reference internal" href="#force-reannounce-force-dht-announce" id="id83">force_reannounce() force_dht_announce()</a></li>
<li><a class="reference internal" href="#scrape-tracker" id="id84">scrape_tracker()</a></li>
<li><a class="reference internal" href="#connect-peer" id="id85">connect_peer()</a></li>
<li><a class="reference internal" href="#name" id="id86">name()</a></li>
<li><a class="reference internal" href="#set-ratio" id="id87">set_ratio()</a></li>
<li><a class="reference internal" href="#set-upload-limit-set-download-limit-upload-limit-download-limit" id="id88">set_upload_limit() set_download_limit() upload_limit() download_limit()</a></li>
<li><a class="reference internal" href="#set-sequential-download" id="id89">set_sequential_download()</a></li>
<li><a class="reference internal" href="#get-peer-download-limit-get-peer-upload-limit-set-peer-upload-limit-set-peer-download-limit" id="id90">get_peer_download_limit() get_peer_upload_limit() set_peer_upload_limit() set_peer_download_limit()</a></li>
<li><a class="reference internal" href="#pause-resume" id="id91">pause() resume()</a></li>
<li><a class="reference internal" href="#flush-cache" id="id92">flush_cache()</a></li>
<li><a class="reference internal" href="#force-recheck" id="id93">force_recheck()</a></li>
<li><a class="reference internal" href="#clear-error" id="id94">clear_error()</a></li>
<li><a class="reference internal" href="#set-upload-mode" id="id95">set_upload_mode()</a></li>
<li><a class="reference internal" href="#set-share-mode" id="id96">set_share_mode()</a></li>
<li><a class="reference internal" href="#resolve-countries" id="id97">resolve_countries()</a></li>
<li><a class="reference internal" href="#is-seed" id="id98">is_seed()</a></li>
<li><a class="reference internal" href="#auto-managed" id="id99">auto_managed()</a></li>
<li><a class="reference internal" href="#set-metadata" id="id100">set_metadata()</a></li>
<li><a class="reference internal" href="#set-tracker-login" id="id101">set_tracker_login()</a></li>
<li><a class="reference internal" href="#trackers-replace-trackers-add-tracker" id="id102">trackers() replace_trackers() add_tracker()</a></li>
<li><a class="reference internal" href="#add-url-seed-remove-url-seed-url-seeds" id="id103">add_url_seed() remove_url_seed() url_seeds()</a></li>
<li><a class="reference internal" href="#add-http-seed-remove-http-seed-http-seeds" id="id104">add_http_seed() remove_http_seed() http_seeds()</a></li>
<li><a class="reference internal" href="#queue-position-queue-position-up-queue-position-down-queue-position-top-queue-position-bottom" id="id105">queue_position() queue_position_up() queue_position_down() queue_position_top() queue_position_bottom()</a></li>
<li><a class="reference internal" href="#set-priority" id="id106">set_priority()</a></li>
<li><a class="reference internal" href="#use-interface" id="id107">use_interface()</a></li>
<li><a class="reference internal" href="#info-hash" id="id108">info_hash()</a></li>
<li><a class="reference internal" href="#set-max-uploads-max-uploads" id="id109">set_max_uploads() max_uploads()</a></li>
<li><a class="reference internal" href="#set-max-connections-max-connections" id="id110">set_max_connections() max_connections()</a></li>
<li><a class="reference internal" href="#save-resume-data" id="id111">save_resume_data()</a></li>
<li><a class="reference internal" href="#need-save-resume-data" id="id112">need_save_resume_data()</a></li>
<li><a class="reference internal" href="#id5" id="id113">status()</a></li>
<li><a class="reference internal" href="#get-download-queue" id="id114">get_download_queue()</a></li>
<li><a class="reference internal" href="#get-peer-info" id="id115">get_peer_info()</a></li>
<li><a class="reference internal" href="#get-torrent-info" id="id116">get_torrent_info()</a></li>
<li><a class="reference internal" href="#is-valid" id="id117">is_valid()</a></li>
<li><a class="reference internal" href="#torrent-handle" id="id71">torrent_handle</a><ul>
<li><a class="reference internal" href="#set-piece-deadline" id="id72">set_piece_deadline()</a></li>
<li><a class="reference internal" href="#piece-availability" id="id73">piece_availability()</a></li>
<li><a class="reference internal" href="#piece-priority-prioritize-pieces-piece-priorities" id="id74">piece_priority() prioritize_pieces() piece_priorities()</a></li>
<li><a class="reference internal" href="#file-priority-prioritize-files-file-priorities" id="id75">file_priority() prioritize_files() file_priorities()</a></li>
<li><a class="reference internal" href="#file-progress" id="id76">file_progress()</a></li>
<li><a class="reference internal" href="#save-path" id="id77">save_path()</a></li>
<li><a class="reference internal" href="#move-storage" id="id78">move_storage()</a></li>
<li><a class="reference internal" href="#id4" id="id79">rename_file()</a></li>
<li><a class="reference internal" href="#get-storage-impl" id="id80">get_storage_impl()</a></li>
<li><a class="reference internal" href="#super-seeding" id="id81">super_seeding()</a></li>
<li><a class="reference internal" href="#add-piece" id="id82">add_piece()</a></li>
<li><a class="reference internal" href="#read-piece" id="id83">read_piece()</a></li>
<li><a class="reference internal" href="#force-reannounce-force-dht-announce" id="id84">force_reannounce() force_dht_announce()</a></li>
<li><a class="reference internal" href="#scrape-tracker" id="id85">scrape_tracker()</a></li>
<li><a class="reference internal" href="#connect-peer" id="id86">connect_peer()</a></li>
<li><a class="reference internal" href="#name" id="id87">name()</a></li>
<li><a class="reference internal" href="#set-ratio" id="id88">set_ratio()</a></li>
<li><a class="reference internal" href="#set-upload-limit-set-download-limit-upload-limit-download-limit" id="id89">set_upload_limit() set_download_limit() upload_limit() download_limit()</a></li>
<li><a class="reference internal" href="#set-sequential-download" id="id90">set_sequential_download()</a></li>
<li><a class="reference internal" href="#get-peer-download-limit-get-peer-upload-limit-set-peer-upload-limit-set-peer-download-limit" id="id91">get_peer_download_limit() get_peer_upload_limit() set_peer_upload_limit() set_peer_download_limit()</a></li>
<li><a class="reference internal" href="#pause-resume" id="id92">pause() resume()</a></li>
<li><a class="reference internal" href="#flush-cache" id="id93">flush_cache()</a></li>
<li><a class="reference internal" href="#force-recheck" id="id94">force_recheck()</a></li>
<li><a class="reference internal" href="#clear-error" id="id95">clear_error()</a></li>
<li><a class="reference internal" href="#set-upload-mode" id="id96">set_upload_mode()</a></li>
<li><a class="reference internal" href="#set-share-mode" id="id97">set_share_mode()</a></li>
<li><a class="reference internal" href="#resolve-countries" id="id98">resolve_countries()</a></li>
<li><a class="reference internal" href="#is-seed" id="id99">is_seed()</a></li>
<li><a class="reference internal" href="#auto-managed" id="id100">auto_managed()</a></li>
<li><a class="reference internal" href="#set-metadata" id="id101">set_metadata()</a></li>
<li><a class="reference internal" href="#set-tracker-login" id="id102">set_tracker_login()</a></li>
<li><a class="reference internal" href="#trackers-replace-trackers-add-tracker" id="id103">trackers() replace_trackers() add_tracker()</a></li>
<li><a class="reference internal" href="#add-url-seed-remove-url-seed-url-seeds" id="id104">add_url_seed() remove_url_seed() url_seeds()</a></li>
<li><a class="reference internal" href="#add-http-seed-remove-http-seed-http-seeds" id="id105">add_http_seed() remove_http_seed() http_seeds()</a></li>
<li><a class="reference internal" href="#queue-position-queue-position-up-queue-position-down-queue-position-top-queue-position-bottom" id="id106">queue_position() queue_position_up() queue_position_down() queue_position_top() queue_position_bottom()</a></li>
<li><a class="reference internal" href="#set-priority" id="id107">set_priority()</a></li>
<li><a class="reference internal" href="#use-interface" id="id108">use_interface()</a></li>
<li><a class="reference internal" href="#info-hash" id="id109">info_hash()</a></li>
<li><a class="reference internal" href="#set-max-uploads-max-uploads" id="id110">set_max_uploads() max_uploads()</a></li>
<li><a class="reference internal" href="#set-max-connections-max-connections" id="id111">set_max_connections() max_connections()</a></li>
<li><a class="reference internal" href="#save-resume-data" id="id112">save_resume_data()</a></li>
<li><a class="reference internal" href="#need-save-resume-data" id="id113">need_save_resume_data()</a></li>
<li><a class="reference internal" href="#id5" id="id114">status()</a></li>
<li><a class="reference internal" href="#get-download-queue" id="id115">get_download_queue()</a></li>
<li><a class="reference internal" href="#get-peer-info" id="id116">get_peer_info()</a></li>
<li><a class="reference internal" href="#get-torrent-info" id="id117">get_torrent_info()</a></li>
<li><a class="reference internal" href="#is-valid" id="id118">is_valid()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#torrent-status" id="id118">torrent_status</a></li>
<li><a class="reference internal" href="#peer-info" id="id119">peer_info</a></li>
<li><a class="reference internal" href="#feed-handle" id="id120">feed_handle</a><ul>
<li><a class="reference internal" href="#update-feed" id="id121">update_feed()</a></li>
<li><a class="reference internal" href="#get-feed-status" id="id122">get_feed_status()</a></li>
<li><a class="reference internal" href="#set-settings-settings" id="id123">set_settings() settings()</a></li>
<li><a class="reference internal" href="#torrent-status" id="id119">torrent_status</a></li>
<li><a class="reference internal" href="#peer-info" id="id120">peer_info</a></li>
<li><a class="reference internal" href="#feed-handle" id="id121">feed_handle</a><ul>
<li><a class="reference internal" href="#update-feed" id="id122">update_feed()</a></li>
<li><a class="reference internal" href="#get-feed-status" id="id123">get_feed_status()</a></li>
<li><a class="reference internal" href="#set-settings-settings" id="id124">set_settings() settings()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#feed-item" id="id124">feed_item</a></li>
<li><a class="reference internal" href="#session-customization" id="id125">session customization</a><ul>
<li><a class="reference internal" href="#presets" id="id126">presets</a></li>
<li><a class="reference internal" href="#session-settings" id="id127">session_settings</a></li>
<li><a class="reference internal" href="#feed-item" id="id125">feed_item</a></li>
<li><a class="reference internal" href="#session-customization" id="id126">session customization</a><ul>
<li><a class="reference internal" href="#presets" id="id127">presets</a></li>
<li><a class="reference internal" href="#session-settings" id="id128">session_settings</a></li>
</ul>
</li>
<li><a class="reference internal" href="#pe-settings" id="id128">pe_settings</a></li>
<li><a class="reference internal" href="#proxy-settings" id="id129">proxy_settings</a></li>
<li><a class="reference internal" href="#ip-filter" id="id130">ip_filter</a><ul>
<li><a class="reference internal" href="#id8" id="id131">ip_filter()</a></li>
<li><a class="reference internal" href="#add-rule" id="id132">add_rule()</a></li>
<li><a class="reference internal" href="#access" id="id133">access()</a></li>
<li><a class="reference internal" href="#export-filter" id="id134">export_filter()</a></li>
<li><a class="reference internal" href="#pe-settings" id="id129">pe_settings</a></li>
<li><a class="reference internal" href="#proxy-settings" id="id130">proxy_settings</a></li>
<li><a class="reference internal" href="#ip-filter" id="id131">ip_filter</a><ul>
<li><a class="reference internal" href="#id8" id="id132">ip_filter()</a></li>
<li><a class="reference internal" href="#add-rule" id="id133">add_rule()</a></li>
<li><a class="reference internal" href="#access" id="id134">access()</a></li>
<li><a class="reference internal" href="#export-filter" id="id135">export_filter()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#big-number" id="id135">big_number</a></li>
<li><a class="reference internal" href="#bitfield" id="id136">bitfield</a></li>
<li><a class="reference internal" href="#hasher" id="id137">hasher</a></li>
<li><a class="reference internal" href="#fingerprint" id="id138">fingerprint</a></li>
<li><a class="reference internal" href="#upnp-and-nat-pmp" id="id139">UPnP and NAT-PMP</a><ul>
<li><a class="reference internal" href="#add-mapping" id="id140">add_mapping()</a></li>
<li><a class="reference internal" href="#delete-mapping" id="id141">delete_mapping()</a></li>
<li><a class="reference internal" href="#router-model" id="id142">router_model()</a></li>
<li><a class="reference internal" href="#big-number" id="id136">big_number</a></li>
<li><a class="reference internal" href="#bitfield" id="id137">bitfield</a></li>
<li><a class="reference internal" href="#hasher" id="id138">hasher</a></li>
<li><a class="reference internal" href="#fingerprint" id="id139">fingerprint</a></li>
<li><a class="reference internal" href="#upnp-and-nat-pmp" id="id140">UPnP and NAT-PMP</a><ul>
<li><a class="reference internal" href="#add-mapping" id="id141">add_mapping()</a></li>
<li><a class="reference internal" href="#delete-mapping" id="id142">delete_mapping()</a></li>
<li><a class="reference internal" href="#router-model" id="id143">router_model()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#free-functions" id="id143">free functions</a><ul>
<li><a class="reference internal" href="#identify-client" id="id144">identify_client()</a></li>
<li><a class="reference internal" href="#client-fingerprint" id="id145">client_fingerprint()</a></li>
<li><a class="reference internal" href="#lazy-bdecode" id="id146">lazy_bdecode()</a></li>
<li><a class="reference internal" href="#bdecode-bencode" id="id147">bdecode() bencode()</a></li>
<li><a class="reference internal" href="#add-magnet-uri" id="id148">add_magnet_uri()</a></li>
<li><a class="reference internal" href="#make-magnet-uri" id="id149">make_magnet_uri()</a></li>
<li><a class="reference internal" href="#free-functions" id="id144">free functions</a><ul>
<li><a class="reference internal" href="#identify-client" id="id145">identify_client()</a></li>
<li><a class="reference internal" href="#client-fingerprint" id="id146">client_fingerprint()</a></li>
<li><a class="reference internal" href="#lazy-bdecode" id="id147">lazy_bdecode()</a></li>
<li><a class="reference internal" href="#bdecode-bencode" id="id148">bdecode() bencode()</a></li>
<li><a class="reference internal" href="#add-magnet-uri" id="id149">add_magnet_uri()</a></li>
<li><a class="reference internal" href="#make-magnet-uri" id="id150">make_magnet_uri()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#alerts" id="id150">alerts</a><ul>
<li><a class="reference internal" href="#read-piece-alert" id="id151">read_piece_alert</a></li>
<li><a class="reference internal" href="#external-ip-alert" id="id152">external_ip_alert</a></li>
<li><a class="reference internal" href="#listen-failed-alert" id="id153">listen_failed_alert</a></li>
<li><a class="reference internal" href="#listen-succeeded-alert" id="id154">listen_succeeded_alert</a></li>
<li><a class="reference internal" href="#portmap-error-alert" id="id155">portmap_error_alert</a></li>
<li><a class="reference internal" href="#portmap-alert" id="id156">portmap_alert</a></li>
<li><a class="reference internal" href="#portmap-log-alert" id="id157">portmap_log_alert</a></li>
<li><a class="reference internal" href="#file-error-alert" id="id158">file_error_alert</a></li>
<li><a class="reference internal" href="#file-renamed-alert" id="id159">file_renamed_alert</a></li>
<li><a class="reference internal" href="#file-rename-failed-alert" id="id160">file_rename_failed_alert</a></li>
<li><a class="reference internal" href="#tracker-announce-alert" id="id161">tracker_announce_alert</a></li>
<li><a class="reference internal" href="#tracker-error-alert" id="id162">tracker_error_alert</a></li>
<li><a class="reference internal" href="#tracker-reply-alert" id="id163">tracker_reply_alert</a></li>
<li><a class="reference internal" href="#tracker-warning-alert" id="id164">tracker_warning_alert</a></li>
<li><a class="reference internal" href="#scrape-reply-alert" id="id165">scrape_reply_alert</a></li>
<li><a class="reference internal" href="#scrape-failed-alert" id="id166">scrape_failed_alert</a></li>
<li><a class="reference internal" href="#url-seed-alert" id="id167">url_seed_alert</a></li>
<li><a class="reference internal" href="#hash-failed-alert" id="id168">hash_failed_alert</a></li>
<li><a class="reference internal" href="#peer-alert" id="id169">peer_alert</a></li>
<li><a class="reference internal" href="#peer-connect-alert" id="id170">peer_connect_alert</a></li>
<li><a class="reference internal" href="#peer-ban-alert" id="id171">peer_ban_alert</a></li>
<li><a class="reference internal" href="#peer-snubbed-alert" id="id172">peer_snubbed_alert</a></li>
<li><a class="reference internal" href="#peer-unsnubbed-alert" id="id173">peer_unsnubbed_alert</a></li>
<li><a class="reference internal" href="#peer-error-alert" id="id174">peer_error_alert</a></li>
<li><a class="reference internal" href="#peer-connected-alert" id="id175">peer_connected_alert</a></li>
<li><a class="reference internal" href="#peer-disconnected-alert" id="id176">peer_disconnected_alert</a></li>
<li><a class="reference internal" href="#invalid-request-alert" id="id177">invalid_request_alert</a></li>
<li><a class="reference internal" href="#request-dropped-alert" id="id178">request_dropped_alert</a></li>
<li><a class="reference internal" href="#block-timeout-alert" id="id179">block_timeout_alert</a></li>
<li><a class="reference internal" href="#block-finished-alert" id="id180">block_finished_alert</a></li>
<li><a class="reference internal" href="#lsd-peer-alert" id="id181">lsd_peer_alert</a></li>
<li><a class="reference internal" href="#file-completed-alert" id="id182">file_completed_alert</a></li>
<li><a class="reference internal" href="#block-downloading-alert" id="id183">block_downloading_alert</a></li>
<li><a class="reference internal" href="#unwanted-block-alert" id="id184">unwanted_block_alert</a></li>
<li><a class="reference internal" href="#torrent-delete-failed-alert" id="id185">torrent_delete_failed_alert</a></li>
<li><a class="reference internal" href="#torrent-deleted-alert" id="id186">torrent_deleted_alert</a></li>
<li><a class="reference internal" href="#torrent-finished-alert" id="id187">torrent_finished_alert</a></li>
<li><a class="reference internal" href="#performance-alert" id="id188">performance_alert</a></li>
<li><a class="reference internal" href="#state-changed-alert" id="id189">state_changed_alert</a></li>
<li><a class="reference internal" href="#metadata-failed-alert" id="id190">metadata_failed_alert</a></li>
<li><a class="reference internal" href="#metadata-received-alert" id="id191">metadata_received_alert</a></li>
<li><a class="reference internal" href="#fastresume-rejected-alert" id="id192">fastresume_rejected_alert</a></li>
<li><a class="reference internal" href="#peer-blocked-alert" id="id193">peer_blocked_alert</a></li>
<li><a class="reference internal" href="#storage-moved-alert" id="id194">storage_moved_alert</a></li>
<li><a class="reference internal" href="#storage-moved-failed-alert" id="id195">storage_moved_failed_alert</a></li>
<li><a class="reference internal" href="#torrent-paused-alert" id="id196">torrent_paused_alert</a></li>
<li><a class="reference internal" href="#torrent-resumed-alert" id="id197">torrent_resumed_alert</a></li>
<li><a class="reference internal" href="#save-resume-data-alert" id="id198">save_resume_data_alert</a></li>
<li><a class="reference internal" href="#save-resume-data-failed-alert" id="id199">save_resume_data_failed_alert</a></li>
<li><a class="reference internal" href="#stats-alert" id="id200">stats_alert</a></li>
<li><a class="reference internal" href="#cache-flushed-alert" id="id201">cache_flushed_alert</a></li>
<li><a class="reference internal" href="#dht-announce-alert" id="id202">dht_announce_alert</a></li>
<li><a class="reference internal" href="#dht-get-peers-alert" id="id203">dht_get_peers_alert</a></li>
<li><a class="reference internal" href="#dht-reply-alert" id="id204">dht_reply_alert</a></li>
<li><a class="reference internal" href="#dht-bootstrap-alert" id="id205">dht_bootstrap_alert</a></li>
<li><a class="reference internal" href="#anonymous-mode-alert" id="id206">anonymous_mode_alert</a></li>
<li><a class="reference internal" href="#rss-alert" id="id207">rss_alert</a></li>
<li><a class="reference internal" href="#alerts" id="id151">alerts</a><ul>
<li><a class="reference internal" href="#torrent-added-alert" id="id152">torrent_added_alert</a></li>
<li><a class="reference internal" href="#torrent-removed-alert" id="id153">torrent_removed_alert</a></li>
<li><a class="reference internal" href="#read-piece-alert" id="id154">read_piece_alert</a></li>
<li><a class="reference internal" href="#external-ip-alert" id="id155">external_ip_alert</a></li>
<li><a class="reference internal" href="#listen-failed-alert" id="id156">listen_failed_alert</a></li>
<li><a class="reference internal" href="#listen-succeeded-alert" id="id157">listen_succeeded_alert</a></li>
<li><a class="reference internal" href="#portmap-error-alert" id="id158">portmap_error_alert</a></li>
<li><a class="reference internal" href="#portmap-alert" id="id159">portmap_alert</a></li>
<li><a class="reference internal" href="#portmap-log-alert" id="id160">portmap_log_alert</a></li>
<li><a class="reference internal" href="#file-error-alert" id="id161">file_error_alert</a></li>
<li><a class="reference internal" href="#torrent-error-alert" id="id162">torrent_error_alert</a></li>
<li><a class="reference internal" href="#file-renamed-alert" id="id163">file_renamed_alert</a></li>
<li><a class="reference internal" href="#file-rename-failed-alert" id="id164">file_rename_failed_alert</a></li>
<li><a class="reference internal" href="#tracker-announce-alert" id="id165">tracker_announce_alert</a></li>
<li><a class="reference internal" href="#tracker-error-alert" id="id166">tracker_error_alert</a></li>
<li><a class="reference internal" href="#tracker-reply-alert" id="id167">tracker_reply_alert</a></li>
<li><a class="reference internal" href="#tracker-warning-alert" id="id168">tracker_warning_alert</a></li>
<li><a class="reference internal" href="#scrape-reply-alert" id="id169">scrape_reply_alert</a></li>
<li><a class="reference internal" href="#scrape-failed-alert" id="id170">scrape_failed_alert</a></li>
<li><a class="reference internal" href="#url-seed-alert" id="id171">url_seed_alert</a></li>
<li><a class="reference internal" href="#hash-failed-alert" id="id172">hash_failed_alert</a></li>
<li><a class="reference internal" href="#peer-alert" id="id173">peer_alert</a></li>
<li><a class="reference internal" href="#peer-connect-alert" id="id174">peer_connect_alert</a></li>
<li><a class="reference internal" href="#peer-ban-alert" id="id175">peer_ban_alert</a></li>
<li><a class="reference internal" href="#peer-snubbed-alert" id="id176">peer_snubbed_alert</a></li>
<li><a class="reference internal" href="#peer-unsnubbed-alert" id="id177">peer_unsnubbed_alert</a></li>
<li><a class="reference internal" href="#peer-error-alert" id="id178">peer_error_alert</a></li>
<li><a class="reference internal" href="#peer-connected-alert" id="id179">peer_connected_alert</a></li>
<li><a class="reference internal" href="#peer-disconnected-alert" id="id180">peer_disconnected_alert</a></li>
<li><a class="reference internal" href="#invalid-request-alert" id="id181">invalid_request_alert</a></li>
<li><a class="reference internal" href="#request-dropped-alert" id="id182">request_dropped_alert</a></li>
<li><a class="reference internal" href="#block-timeout-alert" id="id183">block_timeout_alert</a></li>
<li><a class="reference internal" href="#block-finished-alert" id="id184">block_finished_alert</a></li>
<li><a class="reference internal" href="#lsd-peer-alert" id="id185">lsd_peer_alert</a></li>
<li><a class="reference internal" href="#file-completed-alert" id="id186">file_completed_alert</a></li>
<li><a class="reference internal" href="#block-downloading-alert" id="id187">block_downloading_alert</a></li>
<li><a class="reference internal" href="#unwanted-block-alert" id="id188">unwanted_block_alert</a></li>
<li><a class="reference internal" href="#torrent-delete-failed-alert" id="id189">torrent_delete_failed_alert</a></li>
<li><a class="reference internal" href="#torrent-deleted-alert" id="id190">torrent_deleted_alert</a></li>
<li><a class="reference internal" href="#torrent-finished-alert" id="id191">torrent_finished_alert</a></li>
<li><a class="reference internal" href="#performance-alert" id="id192">performance_alert</a></li>
<li><a class="reference internal" href="#state-changed-alert" id="id193">state_changed_alert</a></li>
<li><a class="reference internal" href="#metadata-failed-alert" id="id194">metadata_failed_alert</a></li>
<li><a class="reference internal" href="#metadata-received-alert" id="id195">metadata_received_alert</a></li>
<li><a class="reference internal" href="#fastresume-rejected-alert" id="id196">fastresume_rejected_alert</a></li>
<li><a class="reference internal" href="#peer-blocked-alert" id="id197">peer_blocked_alert</a></li>
<li><a class="reference internal" href="#storage-moved-alert" id="id198">storage_moved_alert</a></li>
<li><a class="reference internal" href="#storage-moved-failed-alert" id="id199">storage_moved_failed_alert</a></li>
<li><a class="reference internal" href="#torrent-paused-alert" id="id200">torrent_paused_alert</a></li>
<li><a class="reference internal" href="#torrent-resumed-alert" id="id201">torrent_resumed_alert</a></li>
<li><a class="reference internal" href="#save-resume-data-alert" id="id202">save_resume_data_alert</a></li>
<li><a class="reference internal" href="#save-resume-data-failed-alert" id="id203">save_resume_data_failed_alert</a></li>
<li><a class="reference internal" href="#stats-alert" id="id204">stats_alert</a></li>
<li><a class="reference internal" href="#cache-flushed-alert" id="id205">cache_flushed_alert</a></li>
<li><a class="reference internal" href="#dht-announce-alert" id="id206">dht_announce_alert</a></li>
<li><a class="reference internal" href="#dht-get-peers-alert" id="id207">dht_get_peers_alert</a></li>
<li><a class="reference internal" href="#dht-reply-alert" id="id208">dht_reply_alert</a></li>
<li><a class="reference internal" href="#dht-bootstrap-alert" id="id209">dht_bootstrap_alert</a></li>
<li><a class="reference internal" href="#anonymous-mode-alert" id="id210">anonymous_mode_alert</a></li>
<li><a class="reference internal" href="#rss-alert" id="id211">rss_alert</a></li>
</ul>
</li>
<li><a class="reference internal" href="#alert-dispatcher" id="id208">alert dispatcher</a></li>
<li><a class="reference internal" href="#exceptions" id="id209">exceptions</a><ul>
<li><a class="reference internal" href="#libtorrent-exception" id="id210">libtorrent_exception</a></li>
<li><a class="reference internal" href="#alert-dispatcher" id="id212">alert dispatcher</a></li>
<li><a class="reference internal" href="#exceptions" id="id213">exceptions</a><ul>
<li><a class="reference internal" href="#libtorrent-exception" id="id214">libtorrent_exception</a></li>
</ul>
</li>
<li><a class="reference internal" href="#error-code" id="id211">error_code</a><ul>
<li><a class="reference internal" href="#translating-error-codes" id="id212">translating error codes</a></li>
<li><a class="reference internal" href="#error-code" id="id215">error_code</a><ul>
<li><a class="reference internal" href="#translating-error-codes" id="id216">translating error codes</a></li>
</ul>
</li>
<li><a class="reference internal" href="#storage-interface" id="id213">storage_interface</a><ul>
<li><a class="reference internal" href="#initialize" id="id214">initialize()</a></li>
<li><a class="reference internal" href="#has-any-file" id="id215">has_any_file()</a></li>
<li><a class="reference internal" href="#readv-writev" id="id216">readv() writev()</a></li>
<li><a class="reference internal" href="#sparse-end" id="id217">sparse_end()</a></li>
<li><a class="reference internal" href="#id10" id="id218">move_storage()</a></li>
<li><a class="reference internal" href="#verify-resume-data" id="id219">verify_resume_data()</a></li>
<li><a class="reference internal" href="#write-resume-data" id="id220">write_resume_data()</a></li>
<li><a class="reference internal" href="#move-slot" id="id221">move_slot()</a></li>
<li><a class="reference internal" href="#swap-slots" id="id222">swap_slots()</a></li>
<li><a class="reference internal" href="#swap-slots3" id="id223">swap_slots3()</a></li>
<li><a class="reference internal" href="#id11" id="id224">rename_file()</a></li>
<li><a class="reference internal" href="#release-files" id="id225">release_files()</a></li>
<li><a class="reference internal" href="#delete-files" id="id226">delete_files()</a></li>
<li><a class="reference internal" href="#finalize-file" id="id227">finalize_file()</a></li>
<li><a class="reference internal" href="#storage-interface" id="id217">storage_interface</a><ul>
<li><a class="reference internal" href="#initialize" id="id218">initialize()</a></li>
<li><a class="reference internal" href="#has-any-file" id="id219">has_any_file()</a></li>
<li><a class="reference internal" href="#readv-writev" id="id220">readv() writev()</a></li>
<li><a class="reference internal" href="#sparse-end" id="id221">sparse_end()</a></li>
<li><a class="reference internal" href="#id10" id="id222">move_storage()</a></li>
<li><a class="reference internal" href="#verify-resume-data" id="id223">verify_resume_data()</a></li>
<li><a class="reference internal" href="#write-resume-data" id="id224">write_resume_data()</a></li>
<li><a class="reference internal" href="#move-slot" id="id225">move_slot()</a></li>
<li><a class="reference internal" href="#swap-slots" id="id226">swap_slots()</a></li>
<li><a class="reference internal" href="#swap-slots3" id="id227">swap_slots3()</a></li>
<li><a class="reference internal" href="#id11" id="id228">rename_file()</a></li>
<li><a class="reference internal" href="#release-files" id="id229">release_files()</a></li>
<li><a class="reference internal" href="#delete-files" id="id230">delete_files()</a></li>
<li><a class="reference internal" href="#finalize-file" id="id231">finalize_file()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#magnet-links" id="id228">magnet links</a></li>
<li><a class="reference internal" href="#queuing" id="id229">queuing</a><ul>
<li><a class="reference internal" href="#downloading" id="id230">downloading</a></li>
<li><a class="reference internal" href="#seeding" id="id231">seeding</a></li>
<li><a class="reference internal" href="#magnet-links" id="id232">magnet links</a></li>
<li><a class="reference internal" href="#queuing" id="id233">queuing</a><ul>
<li><a class="reference internal" href="#downloading" id="id234">downloading</a></li>
<li><a class="reference internal" href="#seeding" id="id235">seeding</a></li>
</ul>
</li>
<li><a class="reference internal" href="#fast-resume" id="id232">fast resume</a><ul>
<li><a class="reference internal" href="#file-format" id="id233">file format</a></li>
<li><a class="reference internal" href="#fast-resume" id="id236">fast resume</a><ul>
<li><a class="reference internal" href="#file-format" id="id237">file format</a></li>
</ul>
</li>
<li><a class="reference internal" href="#threads" id="id234">threads</a></li>
<li><a class="reference internal" href="#storage-allocation" id="id235">storage allocation</a><ul>
<li><a class="reference internal" href="#sparse-allocation" id="id236">sparse allocation</a></li>
<li><a class="reference internal" href="#full-allocation" id="id237">full allocation</a></li>
<li><a class="reference internal" href="#compact-allocation" id="id238">compact allocation</a></li>
<li><a class="reference internal" href="#threads" id="id238">threads</a></li>
<li><a class="reference internal" href="#storage-allocation" id="id239">storage allocation</a><ul>
<li><a class="reference internal" href="#sparse-allocation" id="id240">sparse allocation</a></li>
<li><a class="reference internal" href="#full-allocation" id="id241">full allocation</a></li>
<li><a class="reference internal" href="#compact-allocation" id="id242">compact allocation</a></li>
</ul>
</li>
<li><a class="reference internal" href="#extensions" id="id239">extensions</a><ul>
<li><a class="reference internal" href="#metadata-from-peers" id="id240">metadata from peers</a></li>
<li><a class="reference internal" href="#http-seeding" id="id241">HTTP seeding</a></li>
<li><a class="reference internal" href="#extensions" id="id243">extensions</a><ul>
<li><a class="reference internal" href="#metadata-from-peers" id="id244">metadata from peers</a></li>
<li><a class="reference internal" href="#http-seeding" id="id245">HTTP seeding</a></li>
</ul>
</li>
<li><a class="reference internal" href="#filename-checks" id="id242">filename checks</a></li>
<li><a class="reference internal" href="#filename-checks" id="id246">filename checks</a></li>
</ul>
</div>
<div class="section" id="overview">
@ -466,7 +470,13 @@ class session: public boost::noncopyable
void remove_torrent(torrent_handle const&amp; h
, int options = none);
torrent_handle find_torrent(sha_hash const&amp; ih);
std::vector&lt;torrent_handle&gt; get_torrents() const;
void get_torrent_status(std::vector&lt;torrent_status&gt;* ret
, boost::function&lt;bool(torrent_status const&amp;)&gt; const&amp; pred
, boost::uint32_t flags = 0) const;
void refresh_torrent_status(std::vector&lt;torrent_status&gt;* ret
, boost::uint32_t flags) const;
void set_settings(session_settings const&amp; settings);
session_settings settings() const;
@ -838,6 +848,34 @@ In case the torrent cannot be found, an invalid torrent_handle is returned.</p>
<p><tt class="docutils literal"><span class="pre">get_torrents()</span></tt> returns a vector of torrent_handles to all the torrents
currently in the session.</p>
</div>
<div class="section" id="get-torrent-status-refresh-torrent-status">
<h2>get_torrent_status() refresh_torrent_status()</h2>
<blockquote>
<pre class="literal-block">
void get_torrent_status(std::vector&lt;torrent_status&gt;* ret
, boost::function&lt;bool(torrent_status const&amp;)&gt; const&amp; pred
, boost::uint32_t flags = 0) const;
void refresh_torrent_status(std::vector&lt;torrent_status&gt;* ret
, boost::uint32_t flags = 0) const;
</pre>
</blockquote>
<p><tt class="docutils literal"><span class="pre">get_torrent_status</span></tt> returns a vector of the <tt class="docutils literal"><span class="pre">torrent_status</span></tt> for every
torrent which satisfies <tt class="docutils literal"><span class="pre">pred</span></tt>, which is a predicate function which determines
if a torrent should be included in the returned set or not. Returning true means
it should be included and false means excluded. The <tt class="docutils literal"><span class="pre">flags</span></tt> argument is the same
as to <tt class="docutils literal"><span class="pre">torrent_handle::status()</span></tt>. Since <tt class="docutils literal"><span class="pre">pred</span></tt> is guaranteed to be called for
every torrent, it may be used to count the number of torrents of different categories
as well.</p>
<p><tt class="docutils literal"><span class="pre">refresh_torrent_status</span></tt> takes a vector of <tt class="docutils literal"><span class="pre">torrent_status</span></tt> structs (for instance
the same vector that was returned by <tt class="docutils literal"><span class="pre">get_torrent_status()</span></tt>) and refreshes the
status based on the <tt class="docutils literal"><span class="pre">handle</span></tt> member. It is possible to use this function by
first setting up a vector of default constructed <tt class="docutils literal"><span class="pre">torrent_status</span></tt> objects, only
initializing the <tt class="docutils literal"><span class="pre">handle</span></tt> member, in order to request the torrent status for
multiple torrents in a single call. This can save a significant amount of time
if you have a lot of torrents.</p>
<p>Any <tt class="docutils literal"><span class="pre">torrent_status</span></tt> object whose <tt class="docutils literal"><span class="pre">handle</span></tt> member is not referring to a
valid torrent are ignored.</p>
</div>
<div class="section" id="load-asnum-db-load-country-db-as-for-ip">
<h2>load_asnum_db() load_country_db() as_for_ip()</h2>
<blockquote>
@ -953,9 +991,18 @@ struct session_status
int num_unchoked;
int allowed_upload_slots;
int up_bandwidth_queue;
int down_bandwidth_queue;
int up_bandwidth_bytes_queue;
int down_bandwidth_bytes_queue;
int optimistic_unchoke_counter;
int unchoke_counter;
int disk_write_queue;
int disk_read_queue;
int dht_nodes;
int dht_node_cache;
int dht_torrents;
@ -997,10 +1044,17 @@ than the sum of all peers of all torrents because the incoming connections may n
be assigned a torrent yet.</p>
<p><tt class="docutils literal"><span class="pre">num_unchoked</span></tt> is the current number of unchoked peers.
<tt class="docutils literal"><span class="pre">allowed_upload_slots</span></tt> is the current allowed number of unchoked peers.</p>
<p><tt class="docutils literal"><span class="pre">up_bandwidth_queue</span></tt> and <tt class="docutils literal"><span class="pre">down_bandwidth_queue</span></tt> are the number of peers that are
waiting for more bandwidth quota from the torrent rate limiter.
<tt class="docutils literal"><span class="pre">up_bandwidth_bytes_queue</span></tt> and <tt class="docutils literal"><span class="pre">down_bandwidth_bytes_queue</span></tt> count the number of
bytes the connections are waiting for to be able to send and receive.</p>
<p><tt class="docutils literal"><span class="pre">optimistic_unchoke_counter</span></tt> and <tt class="docutils literal"><span class="pre">unchoke_counter</span></tt> tells the number of
seconds until the next optimistic unchoke change and the start of the next
unchoke interval. These numbers may be reset prematurely if a peer that is
unchoked disconnects or becomes notinterested.</p>
<p><tt class="docutils literal"><span class="pre">disk_write_queue</span></tt> and <tt class="docutils literal"><span class="pre">disk_read_queue</span></tt> are the number of peers currently
waiting on a disk write or disk read to complete before it receives or sends
any more data on the socket. It'a a metric of how disk bound you are.</p>
<p><tt class="docutils literal"><span class="pre">dht_nodes</span></tt>, <tt class="docutils literal"><span class="pre">dht_node_cache</span></tt> and <tt class="docutils literal"><span class="pre">dht_torrents</span></tt> are only available when
built with DHT support. They are all set to 0 if the DHT isn't running. When
the DHT is running, <tt class="docutils literal"><span class="pre">dht_nodes</span></tt> is set to the number of nodes in the routing
@ -1167,13 +1221,12 @@ void set_alert_mask(int m);
<tt class="docutils literal"><span class="pre">m</span></tt> is a bitmask where each bit represents a category of alerts.</p>
<p>See <a class="reference internal" href="#alerts">alerts</a> for mor information on the alert categories.</p>
</div>
<div class="section" id="pop-alert-wait-for-alert-set-alert-queue-size-limit">
<h2>pop_alert() wait_for_alert() set_alert_queue_size_limit()</h2>
<div class="section" id="pop-alert-wait-for-alert">
<h2>pop_alert() wait_for_alert()</h2>
<blockquote>
<pre class="literal-block">
std::auto_ptr&lt;alert&gt; pop_alert();
alert const* wait_for_alert(time_duration max_wait);
size_t set_alert_queue_size_limit(size_t queue_size_limit_);
</pre>
</blockquote>
<p><tt class="docutils literal"><span class="pre">pop_alert()</span></tt> is used to ask the session if any errors or events has occurred. With
@ -1187,9 +1240,8 @@ same pointer until the alert is popped by calling <tt class="docutils literal"><
leaving any alert dispatching mechanism independent of this blocking call, the dispatcher
can be called and it can pop the alert independently.</p>
<p>In the python binding, <tt class="docutils literal"><span class="pre">wait_for_alert</span></tt> takes the number of milliseconds to wait as an integer.</p>
<p><tt class="docutils literal"><span class="pre">set_alert_queue_size_limit()</span></tt> you can specify how many alerts can be awaiting for dispatching.
If this limit is reached, new incoming alerts can not be received until alerts are popped
by calling <tt class="docutils literal"><span class="pre">pop_alert</span></tt>. Default value is 1000.</p>
<p>To control the max number of alerts that's queued by the session, see
<tt class="docutils literal"><span class="pre">session_settings::alert_queue_size</span></tt>.</p>
<p><tt class="docutils literal"><span class="pre">save_resume_data_alert</span></tt> and <tt class="docutils literal"><span class="pre">save_resume_data_failed_alert</span></tt> are always posted, regardelss
of the alert mask.</p>
</div>
@ -3186,6 +3238,8 @@ struct torrent_status
checking_resume_data
};
torrent_handle handle;
state_t state;
bool paused;
bool auto_managed;
@ -3284,6 +3338,7 @@ struct torrent_status
bool need_save_resume;
};
</pre>
<p><tt class="docutils literal"><span class="pre">handle</span></tt> is a handle to the torrent whose status the object represents.</p>
<p><tt class="docutils literal"><span class="pre">progress</span></tt> is a value in the range [0, 1], that represents the progress of the
torrent's current task. It may be checking files or downloading.</p>
<p><tt class="docutils literal"><span class="pre">progress_ppm</span></tt> reflects the same value as <tt class="docutils literal"><span class="pre">progress</span></tt>, but instead in a range
@ -4246,6 +4301,10 @@ struct session_settings
int torrent_connect_boost;
bool seeding_outgoing_connections;
bool no_connect_privileged_ports;
int alert_queue_size;
int max_metadata_size;
};
</pre>
<p><tt class="docutils literal"><span class="pre">version</span></tt> is automatically set to the libtorrent version you're using
@ -4924,6 +4983,14 @@ may be set to false in very specific applications where the cost of making
outgoing connections is high, and there are no or small benefits of doing so.
For instance, if no nodes are behind a firewall or a NAT, seeds don't need to
make outgoing connections.</p>
<p>if <tt class="docutils literal"><span class="pre">no_connect_privileged_ports</span></tt> is true (which is the default), libtorrent
will not connect to any peers on priviliged ports (&lt;= 1023). This can mitigate
using bittorrent swarms for certain DDoS attacks.</p>
<p><tt class="docutils literal"><span class="pre">alert_queue_size</span></tt> is the maximum number of alerts queued up internally. If
alerts are not popped, the queue will eventually fill up to this level. This
defaults to 1000.</p>
<p><tt class="docutils literal"><span class="pre">max_metadata_size</span></tt> is the maximum allowed size (in bytes) to be received
by the metadata extension, i.e. magnet links. It defaults to 1 MiB.</p>
</div>
</div>
<div class="section" id="pe-settings">
@ -5011,6 +5078,7 @@ struct proxy_settings
proxy_type type;
bool proxy_hostnames;
bool proxy_peer_connections;
};
</pre>
</blockquote>
@ -5042,6 +5110,9 @@ user authorization. The username and password will be sent to the proxy.</li>
<p><tt class="docutils literal"><span class="pre">proxy_hostnames</span></tt> defaults to true. It means that hostnames should be
attempted to be resolved through the proxy instead of using the local DNS
service. This is only supported by SOCKS5 and HTTP.</p>
<p><tt class="docutils literal"><span class="pre">proxy_peer_connections</span></tt> determines whether or not to excempt peer and
web seed connections from using the proxy. This defaults to true, i.e. peer
connections are proxied by default.</p>
</div>
<div class="section" id="ip-filter">
<h1>ip_filter</h1>
@ -5630,6 +5701,7 @@ public:
virtual std::string message() const = 0;
virtual char const* what() const = 0;
virtual int category() const = 0;
virtual bool discardable() const;
virtual std::auto_ptr&lt;alert&gt; clone() const = 0;
};
</pre>
@ -5658,6 +5730,9 @@ switch (a-&gt;type())
not include any information that might be bundled with the alert.</p>
<p><tt class="docutils literal"><span class="pre">category()</span></tt> returns a bitmask specifying which categories this alert belong to.</p>
<p><tt class="docutils literal"><span class="pre">clone()</span></tt> returns a pointer to a copy of the alert.</p>
<p><tt class="docutils literal"><span class="pre">discardable()</span></tt> determines whether or not an alert is allowed to be discarded
when the alert queue is full. There are a few alerts which may not be discared,
since they would break the user contract, such as <tt class="docutils literal"><span class="pre">save_resume_data_alert</span></tt>.</p>
<p><tt class="docutils literal"><span class="pre">message()</span></tt> generate a string describing the alert and the information bundled
with it. This is mainly intended for debug and development use. It is not suitable
to use this for applications that may be localized. Instead, handle each alert
@ -5681,6 +5756,33 @@ struct tracker_alert: torrent_alert
};
</pre>
<p>The specific alerts are:</p>
<div class="section" id="torrent-added-alert">
<h2>torrent_added_alert</h2>
<p>The <tt class="docutils literal"><span class="pre">torrent_added_alert</span></tt> is posted once every time a torrent is added.
It doesn't contain any members of its own, but inherits the torrent handle
from its base class.
It's posted when the <tt class="docutils literal"><span class="pre">status_notification</span></tt> bit is set in the alert mask.</p>
<pre class="literal-block">
struct torrent_added_alert: torrent_alert
{
// ...
};
</pre>
</div>
<div class="section" id="torrent-removed-alert">
<h2>torrent_removed_alert</h2>
<p>The <tt class="docutils literal"><span class="pre">torrent_removed_alert</span></tt> is posted whenever a torrent is removed. Since
the torrent handle in its baseclass will always be invalid (since the torrent
is already removed) it has the info hash as a member, to identify it.
It's posted when the <tt class="docutils literal"><span class="pre">status_notification</span></tt> bit is set in the alert mask.</p>
<pre class="literal-block">
struct torrent_removed_alert: torrent_alert
{
// ...
sha1_hash info_hash;
};
</pre>
</div>
<div class="section" id="read-piece-alert">
<h2>read_piece_alert</h2>
<p>This alert is posted when the asynchronous read operation initiated by
@ -5817,6 +5919,18 @@ struct file_error_alert: torrent_alert
};
</pre>
</div>
<div class="section" id="torrent-error-alert">
<h2>torrent_error_alert</h2>
<p>This is posted whenever a torrent is transitioned into the error state.</p>
<pre class="literal-block">
struct torrent_error_alert: torrent_alert
{
// ...
error_code error;
};
</pre>
<p>The <tt class="docutils literal"><span class="pre">error</span></tt> specifies which error the torrent encountered.</p>
</div>
<div class="section" id="file-renamed-alert">
<h2>file_renamed_alert</h2>
<p>This is posted as a response to a <tt class="docutils literal"><span class="pre">torrent_handle::rename_file</span></tt> call, if the rename
@ -6060,7 +6174,7 @@ struct peer_disconnected_alert: peer_alert
<div class="section" id="invalid-request-alert">
<h2>invalid_request_alert</h2>
<p>This is a debug alert that is generated by an incoming invalid piece request.
<tt class="docutils literal"><span class="pre">ìp</span></tt> is the address of the peer and the <tt class="docutils literal"><span class="pre">request</span></tt> is the actual incoming
<tt class="docutils literal"><span class="pre">Ïp</span></tt> is the address of the peer and the <tt class="docutils literal"><span class="pre">request</span></tt> is the actual incoming
request from the peer.</p>
<pre class="literal-block">
struct invalid_request_alert: peer_alert
@ -7495,13 +7609,13 @@ std::string error_code_to_string(boost::system::error_code const&amp; ec)
static const char const* swedish[] =
{
&quot;inget fel&quot;,
&quot;en fil i torrenten kolliderar med en fil från en annan torrent&quot;,
&quot;en fil i torrenten kolliderar med en fil frÂn en annan torrent&quot;,
&quot;hash check misslyckades&quot;,
&quot;torrent filen är inte en dictionary&quot;,
&quot;'info'-nyckeln saknas eller är korrupt i torrentfilen&quot;,
&quot;'info'-fältet är inte en dictionary&quot;,
&quot;'piece length' fältet saknas eller är korrupt i torrentfilen&quot;,
&quot;torrentfilen saknar namnfältet&quot;,
&quot;torrent filen r inte en dictionary&quot;,
&quot;'info'-nyckeln saknas eller r korrupt i torrentfilen&quot;,
&quot;'info'-f‰ltet ‰r inte en dictionary&quot;,
&quot;'piece length' f‰ltet saknas eller ‰r korrupt i torrentfilen&quot;,
&quot;torrentfilen saknar namnfltet&quot;,
&quot;ogiltigt namn i torrentfilen (kan vara en attack)&quot;,
// ... more strings here
};

View File

@ -158,7 +158,13 @@ The ``session`` class has the following synopsis::
void remove_torrent(torrent_handle const& h
, int options = none);
torrent_handle find_torrent(sha_hash const& ih);
std::vector<torrent_handle> get_torrents() const;
void get_torrent_status(std::vector<torrent_status>* ret
, boost::function<bool(torrent_status const&)> const& pred
, boost::uint32_t flags = 0) const;
void refresh_torrent_status(std::vector<torrent_status>* ret
, boost::uint32_t flags) const;
void set_settings(session_settings const& settings);
session_settings settings() const;
@ -565,6 +571,36 @@ See ``torrent_handle::is_valid()`` to know if the torrent was found or not.
``get_torrents()`` returns a vector of torrent_handles to all the torrents
currently in the session.
get_torrent_status() refresh_torrent_status()
---------------------------------------------
::
void get_torrent_status(std::vector<torrent_status>* ret
, boost::function<bool(torrent_status const&)> const& pred
, boost::uint32_t flags = 0) const;
void refresh_torrent_status(std::vector<torrent_status>* ret
, boost::uint32_t flags = 0) const;
``get_torrent_status`` returns a vector of the ``torrent_status`` for every
torrent which satisfies ``pred``, which is a predicate function which determines
if a torrent should be included in the returned set or not. Returning true means
it should be included and false means excluded. The ``flags`` argument is the same
as to ``torrent_handle::status()``. Since ``pred`` is guaranteed to be called for
every torrent, it may be used to count the number of torrents of different categories
as well.
``refresh_torrent_status`` takes a vector of ``torrent_status`` structs (for instance
the same vector that was returned by ``get_torrent_status()``) and refreshes the
status based on the ``handle`` member. It is possible to use this function by
first setting up a vector of default constructed ``torrent_status`` objects, only
initializing the ``handle`` member, in order to request the torrent status for
multiple torrents in a single call. This can save a significant amount of time
if you have a lot of torrents.
Any ``torrent_status`` object whose ``handle`` member is not referring to a
valid torrent are ignored.
load_asnum_db() load_country_db() as_for_ip()
---------------------------------------------
@ -3146,6 +3182,8 @@ It contains the following fields::
checking_resume_data
};
torrent_handle handle;
state_t state;
bool paused;
bool auto_managed;
@ -3244,6 +3282,8 @@ It contains the following fields::
bool need_save_resume;
};
``handle`` is a handle to the torrent whose status the object represents.
``progress`` is a value in the range [0, 1], that represents the progress of the
torrent's current task. It may be checking files or downloading.

View File

@ -73,17 +73,19 @@
<li><a class="reference internal" href="#high-performance-seeding" id="id12">high performance seeding</a><ul>
<li><a class="reference internal" href="#file-pool" id="id13">file pool</a></li>
<li><a class="reference internal" href="#disk-cache" id="id14">disk cache</a></li>
<li><a class="reference internal" href="#send-buffer-low-watermark" id="id15">send buffer low watermark</a></li>
<li><a class="reference internal" href="#peers" id="id16">peers</a></li>
<li><a class="reference internal" href="#torrent-limits" id="id17">torrent limits</a></li>
<li><a class="reference internal" href="#utp-tcp-mixed-mode" id="id15">uTP-TCP mixed mode</a></li>
<li><a class="reference internal" href="#send-buffer-low-watermark" id="id16">send buffer low watermark</a></li>
<li><a class="reference internal" href="#peers" id="id17">peers</a></li>
<li><a class="reference internal" href="#torrent-limits" id="id18">torrent limits</a></li>
</ul>
</li>
<li><a class="reference internal" href="#benchmarking" id="id18">benchmarking</a><ul>
<li><a class="reference internal" href="#disk-metrics" id="id19">disk metrics</a></li>
<li><a class="reference internal" href="#session-stats" id="id20">session stats</a></li>
<li><a class="reference internal" href="#scalability" id="id19">scalability</a></li>
<li><a class="reference internal" href="#benchmarking" id="id20">benchmarking</a><ul>
<li><a class="reference internal" href="#disk-metrics" id="id21">disk metrics</a></li>
<li><a class="reference internal" href="#session-stats" id="id22">session stats</a></li>
</ul>
</li>
<li><a class="reference internal" href="#contributions" id="id21">contributions</a></li>
<li><a class="reference internal" href="#contributions" id="id23">contributions</a></li>
</ul>
</div>
<div class="section" id="tuning-libtorrent">
@ -312,6 +314,21 @@ the same pieces, and on the other hand assume that they won't request the same p
and drop them when the first peer requests it. To enable volatile read cache, set
<tt class="docutils literal"><span class="pre">session_settings::volatile_read_cache</span></tt> to true.</p>
</div>
<div class="section" id="utp-tcp-mixed-mode">
<h2>uTP-TCP mixed mode</h2>
<p>libtorrent supports <a class="reference external" href="utp.html">uTP</a>, which has a delay based congestion controller. In order to
avoid having a single TCP bittorrent connection completely starve out any uTP connection,
there is a mixed mode algorithm. This attempts to detect congestion on the uTP peers and
throttle TCP to avoid it taking over all bandwidth. This balances the bandwidth resources
between the two protocols. When running on a network where the bandwidth is in such an
abundance that it's virtually infinite, this algorithm is no longer necessary, and might
even be harmful to throughput. It is adviced to experiment with the
<tt class="docutils literal"><span class="pre">session_setting::mixed_mode_algorithm</span></tt>, setting it to <tt class="docutils literal"><span class="pre">session_settings::prefer_tcp</span></tt>.
This setting entirely disables the balancing and unthrottles all connections. On a typical
home connection, this would mean that none of the benefits of uTP would be preserved
(the modem's send buffer would be full at all times) and uTP connections would for the most
part be squashed by the TCP traffic.</p>
</div>
<div class="section" id="send-buffer-low-watermark">
<h2>send buffer low watermark</h2>
<p>libtorrent uses a low watermark for send buffers to determine when a new piece should
@ -347,9 +364,37 @@ number via <tt class="docutils literal"><span class="pre">session::set_max_uploa
and <tt class="docutils literal"><span class="pre">session_settings::active_seeds</span></tt>.</p>
</div>
</div>
<div class="section" id="scalability">
<h1>scalability</h1>
<p>In order to make more efficient use of the libtorrent interface when running a large
number of torrents simultaneously, one can use the <tt class="docutils literal"><span class="pre">session::get_torrent_status()</span></tt> call
together with <tt class="docutils literal"><span class="pre">session::refresh_torrent_status()</span></tt>. Keep in mind that every call into
libtorrent that return some value have to block your thread while posting a message to
the main network thread and then wait for a response (calls that don't return any data
will simply post the message and then immediately return). The time this takes might
become significant once you reach a few hundred torrents (depending on how many calls
you make to each torrent and how often). <tt class="docutils literal"><span class="pre">get_torrent_status</span></tt> lets you query the
status of all torrents in a single call. This will actually loop through all torrents
and run a provided predicate function to determine whether or not to include it in
the returned vector. If you have a lot of torrents, you might want to update the status
of only certain torrents. For instance, you might only be interested in torrents that
are being downloaded.</p>
<p>The intended use of these functions is to start off by calling <tt class="docutils literal"><span class="pre">get_torrent_status</span></tt>
to get a list of all torrents that match your criteria. Then call <tt class="docutils literal"><span class="pre">refresh_torrent_status</span></tt>
on that list. This will only refresh the status for the torrents in your list, and thus
ignore all other torrents you might be running. This may save a significant amount of
time, especially if the number of torrents you're interested in is small. In order to
keep your list of interested torrents up to date, you can either call <tt class="docutils literal"><span class="pre">get_torrent_status</span></tt>
from time to time, to include torrents you might have become interested in since the last
time. In order to stop refreshing a certain torrent, simply remove it from the list.</p>
<p>A more efficient way however, would be to subscribe to status alert notifications, and
update your list based on these alerts. There are alerts for when torrents are added, removed,
paused, resumed, completed etc. Doing this ensures that you only query status for the
minimal set of torrents you are actually interested in.</p>
</div>
<div class="section" id="benchmarking">
<h1>benchmarking</h1>
<p>There are a bunch of built-in instrumentation of libtorrent that can be used to get an insight
<p>There is a bunch of built-in instrumentation of libtorrent that can be used to get an insight
into what it's doing and how well it performs. This instrumentation is enabled by defining
preprocessor symbols when building.</p>
<p>There are also a number of scripts that parses the log files and generates graphs (requires

View File

@ -343,10 +343,41 @@ torrent limits
To seed thousands of torrents, you need to increase the ``session_settings::active_limit``
and ``session_settings::active_seeds``.
scalability
===========
In order to make more efficient use of the libtorrent interface when running a large
number of torrents simultaneously, one can use the ``session::get_torrent_status()`` call
together with ``session::refresh_torrent_status()``. Keep in mind that every call into
libtorrent that return some value have to block your thread while posting a message to
the main network thread and then wait for a response (calls that don't return any data
will simply post the message and then immediately return). The time this takes might
become significant once you reach a few hundred torrents (depending on how many calls
you make to each torrent and how often). ``get_torrent_status`` lets you query the
status of all torrents in a single call. This will actually loop through all torrents
and run a provided predicate function to determine whether or not to include it in
the returned vector. If you have a lot of torrents, you might want to update the status
of only certain torrents. For instance, you might only be interested in torrents that
are being downloaded.
The intended use of these functions is to start off by calling ``get_torrent_status``
to get a list of all torrents that match your criteria. Then call ``refresh_torrent_status``
on that list. This will only refresh the status for the torrents in your list, and thus
ignore all other torrents you might be running. This may save a significant amount of
time, especially if the number of torrents you're interested in is small. In order to
keep your list of interested torrents up to date, you can either call ``get_torrent_status``
from time to time, to include torrents you might have become interested in since the last
time. In order to stop refreshing a certain torrent, simply remove it from the list.
A more efficient way however, would be to subscribe to status alert notifications, and
update your list based on these alerts. There are alerts for when torrents are added, removed,
paused, resumed, completed etc. Doing this ensures that you only query status for the
minimal set of torrents you are actually interested in.
benchmarking
============
There are a bunch of built-in instrumentation of libtorrent that can be used to get an insight
There is a bunch of built-in instrumentation of libtorrent that can be used to get an insight
into what it's doing and how well it performs. This instrumentation is enabled by defining
preprocessor symbols when building.

View File

@ -185,11 +185,15 @@ bool print_fails = false;
bool print_send_bufs = true;
enum {
torrents_all = 0,
torrents_downloading = 1,
torrents_not_paused = 2,
torrents_seeding = 3,
torrents_paused = 4
torrents_all,
torrents_downloading,
torrents_not_paused,
torrents_seeding,
torrents_queued,
torrents_stopped,
torrents_checking,
torrents_max
};
int torrent_filter = torrents_not_paused;
@ -201,13 +205,13 @@ struct torrent_entry
libtorrent::torrent_status status;
};
typedef std::multimap<std::string, torrent_entry> handles_t;
// maps filenames to torrent_handles
typedef std::multimap<std::string, libtorrent::torrent_handle> handles_t;
bool show_torrent(torrent_entry const& te)
using libtorrent::torrent_status;
bool show_torrent(libtorrent::torrent_status const& st, int torrent_filter)
{
using libtorrent::torrent_status;
torrent_status const& st = te.status;
switch (torrent_filter)
{
case torrents_all: return true;
@ -220,11 +224,33 @@ bool show_torrent(torrent_entry const& te)
return !st.paused
&& (st.state == torrent_status::seeding
|| st.state == torrent_status::finished);
case torrents_paused: return st.paused;
case torrents_queued: return st.paused && st.auto_managed;
case torrents_stopped: return st.paused && !st.auto_managed;
case torrents_checking: return st.state == torrent_status::checking_files
|| st.state == torrent_status::queued_for_checking;
}
return true;
}
bool yes(libtorrent::torrent_status const&)
{ return true; }
bool compare_torrent(torrent_status const& lhs, torrent_status const& rhs)
{
if (lhs.queue_position != -1 && rhs.queue_position != -1)
{
// both are downloading, sort by queue pos
return lhs.queue_position < rhs.queue_position;
}
else if (lhs.queue_position == -1 && rhs.queue_position == -1)
{
// both are seeding, sort by seed-rank
return lhs.seed_rank > rhs.seed_rank;
}
return (lhs.queue_position == -1) < (rhs.queue_position == -1);
}
FILE* g_log_file = 0;
int active_torrent = 0;
@ -627,8 +653,11 @@ void add_torrent(libtorrent::session& ses
return;
}
handles.insert(std::pair<const std::string, torrent_entry>(
monitored_dir?std::string(torrent):std::string(), h));
if (monitored_dir)
{
handles.insert(std::pair<const std::string, torrent_handle>(
torrent, h));
}
h.set_max_connections(max_connections_per_torrent);
h.set_max_uploads(-1);
@ -643,7 +672,7 @@ void add_torrent(libtorrent::session& ses
void scan_dir(std::string const& dir_path
, libtorrent::session& ses
, handles_t& handles
, handles_t& files
, float preferred_ratio
, int allocation_mode
, std::string const& save_path
@ -660,8 +689,8 @@ void scan_dir(std::string const& dir_path
std::string file = combine_path(dir_path, i.file());
if (extension(file) != ".torrent") continue;
handles_t::iterator k = handles.find(file);
if (k != handles.end())
handles_t::iterator k = files.find(file);
if (k != files.end())
{
valid.insert(file);
continue;
@ -669,14 +698,14 @@ void scan_dir(std::string const& dir_path
// the file has been added to the dir, start
// downloading it.
add_torrent(ses, handles, file, preferred_ratio, allocation_mode
add_torrent(ses, files, file, preferred_ratio, allocation_mode
, save_path, true, torrent_upload_limit, torrent_download_limit);
valid.insert(file);
}
// remove the torrents that are no longer in the directory
for (handles_t::iterator i = handles.begin(); !handles.empty() && i != handles.end();)
for (handles_t::iterator i = files.begin(); !files.empty() && i != files.end();)
{
if (i->first.empty() || valid.find(i->first) != valid.end())
{
@ -684,10 +713,10 @@ void scan_dir(std::string const& dir_path
continue;
}
torrent_handle& h = i->second.handle;
torrent_handle& h = i->second;
if (!h.is_valid())
{
handles.erase(i++);
files.erase(i++);
continue;
}
@ -697,17 +726,17 @@ void scan_dir(std::string const& dir_path
// will save it to disk
if (h.need_save_resume_data()) h.save_resume_data();
handles.erase(i++);
files.erase(i++);
}
}
torrent_entry& get_active_torrent(handles_t const& handles)
torrent_status const& get_active_torrent(std::vector<torrent_status> const& torrents)
{
if (active_torrent >= handles.size()
if (active_torrent >= torrents.size()
|| active_torrent < 0) active_torrent = 0;
handles_t::const_iterator i = handles.begin();
std::vector<torrent_status>::const_iterator i = torrents.begin();
std::advance(i, active_torrent);
return const_cast<torrent_entry&>(i->second);
return *i;
}
void print_alert(libtorrent::alert const* a, std::string& str)
@ -752,7 +781,7 @@ int save_file(std::string const& filename, std::vector<char>& v)
}
void handle_alert(libtorrent::session& ses, libtorrent::alert* a
, handles_t const& handles)
, handles_t const& files)
{
using namespace libtorrent;
@ -775,16 +804,16 @@ void handle_alert(libtorrent::session& ses, libtorrent::alert* a
std::vector<char> out;
bencode(std::back_inserter(out), *p->resume_data);
save_file(combine_path(h.save_path(), ".resume/" + h.name() + ".resume"), out);
if (std::find_if(handles.begin(), handles.end()
, boost::bind(&torrent_entry::handle, boost::bind(&handles_t::value_type::second, _1)) == h) == handles.end())
if (std::find_if(files.begin(), files.end()
, boost::bind(&handles_t::value_type::second, _1) == h) == files.end())
ses.remove_torrent(h);
}
}
else if (save_resume_data_failed_alert* p = alert_cast<save_resume_data_failed_alert>(a))
{
torrent_handle h = p->handle;
if (std::find_if(handles.begin(), handles.end()
, boost::bind(&torrent_entry::handle, boost::bind(&handles_t::value_type::second, _1)) == h) == handles.end())
if (std::find_if(files.begin(), files.end()
, boost::bind(&handles_t::value_type::second, _1) == h) == files.end())
ses.remove_torrent(h);
}
}
@ -880,7 +909,9 @@ int main(int argc, char* argv[])
// it was added through the directory monitor. It is used to
// be able to remove torrents that were added via the directory
// monitor when they're not in the directory anymore.
handles_t handles;
std::vector<torrent_status> handles;
handles_t files;
session ses(fingerprint("LT", LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR, 0, 0)
, session::add_default_plugins
, alert::all_categories
@ -1107,8 +1138,6 @@ int main(int argc, char* argv[])
continue;
}
handles.insert(std::pair<const std::string, torrent_handle>(std::string(), h));
h.set_max_connections(max_connections_per_torrent);
h.set_max_uploads(-1);
h.set_ratio(preferred_ratio);
@ -1139,8 +1168,6 @@ int main(int argc, char* argv[])
continue;
}
handles.insert(std::pair<const std::string, torrent_handle>(std::string(), h));
h.set_max_connections(max_connections_per_torrent);
h.set_max_uploads(-1);
h.set_ratio(preferred_ratio);
@ -1151,7 +1178,7 @@ int main(int argc, char* argv[])
}
// if it's a torrent file, open it as usual
add_torrent(ses, handles, i->c_str(), preferred_ratio
add_torrent(ses, files, i->c_str(), preferred_ratio
, allocation_mode, save_path, false
, torrent_upload_limit, torrent_download_limit);
}
@ -1162,6 +1189,13 @@ int main(int argc, char* argv[])
while (loop_limit > 1 || loop_limit == 0)
{
handles.clear();
ses.get_torrent_status(&handles, boost::bind(&show_torrent, _1, torrent_filter));
if (active_torrent >= handles.size()) active_torrent = handles.size() - 1;
std::sort(handles.begin(), handles.end(), &compare_torrent);
if (loop_limit > 1) --loop_limit;
char c = 0;
while (sleep_and_input(&c, refresh_delay))
@ -1183,30 +1217,38 @@ int main(int argc, char* argv[])
if (c == 68)
{
// arrow left
if (torrent_filter > 0) --torrent_filter;
if (torrent_filter > 0)
{
--torrent_filter;
handles.clear();
ses.get_torrent_status(&handles, boost::bind(&show_torrent, _1, torrent_filter));
if (active_torrent >= handles.size()) active_torrent = handles.size() - 1;
std::sort(handles.begin(), handles.end(), &compare_torrent);
}
}
else if (c == 67)
{
// arrow right
if (torrent_filter < torrents_paused) ++torrent_filter;
if (torrent_filter < torrents_max - 1)
{
++torrent_filter;
handles.clear();
ses.get_torrent_status(&handles, boost::bind(&show_torrent, _1, torrent_filter));
if (active_torrent >= handles.size()) active_torrent = handles.size() - 1;
std::sort(handles.begin(), handles.end(), &compare_torrent);
}
}
else if (c == 65)
{
// arrow up
int prev = active_torrent;
--active_torrent;
while (active_torrent > 0 && !show_torrent(get_active_torrent(handles)))
--active_torrent;
if (active_torrent < 0) active_torrent = prev;
if (active_torrent < 0) active_torrent = 0;
}
else if (c == 66)
{
// arrow down
int prev = active_torrent;
++active_torrent;
while (active_torrent < handles.size() && !show_torrent(get_active_torrent(handles)))
++active_torrent;
if (active_torrent >= handles.size()) active_torrent = prev;
if (active_torrent >= handles.size()) active_torrent = handles.size() - 1;
}
}
@ -1221,11 +1263,12 @@ int main(int argc, char* argv[])
printf("saving peers for torrents\n");
std::vector<peer_list_entry> peers;
for (handles_t::iterator i = handles.begin();
i != handles.end(); ++i)
std::vector<torrent_handle> torrents = ses.get_torrents();
for (std::vector<torrent_handle>::iterator i = torrents.begin();
i != torrents.end(); ++i)
{
i->second.handle.get_full_peer_list(peers);
FILE* f = fopen(("peers_" + i->second.handle.name()).c_str(), "w+");
i->get_full_peer_list(peers);
FILE* f = fopen(("peers_" + i->name()).c_str(), "w+");
if (!f) break;
for (std::vector<peer_list_entry>::iterator k = peers.begin()
, end(peers.end()); k != end; ++k)
@ -1255,59 +1298,59 @@ int main(int argc, char* argv[])
if (c == 's' && !handles.empty())
{
torrent_entry& te = get_active_torrent(handles);
te.handle.set_sequential_download(!te.status.sequential_download);
torrent_status const& ts = get_active_torrent(handles);
ts.handle.set_sequential_download(!ts.sequential_download);
}
if (c == 'R')
{
// save resume data for all torrents
for (handles_t::iterator i = handles.begin()
for (std::vector<torrent_status>::iterator i = handles.begin()
, end(handles.end()); i != end; ++i)
{
if (i->second.status.need_save_resume)
i->second.handle.save_resume_data();
if (i->need_save_resume)
i->handle.save_resume_data();
}
}
if (c == 'o' && !handles.empty())
{
torrent_entry& te = get_active_torrent(handles);
int num_pieces = te.handle.get_torrent_info().num_pieces();
torrent_status const& ts = get_active_torrent(handles);
int num_pieces = ts.num_pieces;
if (num_pieces > 300) num_pieces = 300;
for (int i = 0; i < num_pieces; ++i)
{
te.handle.set_piece_deadline(i, (i+5) * 1000, torrent_handle::alert_when_available);
ts.handle.set_piece_deadline(i, (i+5) * 1000, torrent_handle::alert_when_available);
}
}
if (c == 'v' && !handles.empty())
{
torrent_entry& te = get_active_torrent(handles);
te.handle.scrape_tracker();
torrent_status const& ts = get_active_torrent(handles);
ts.handle.scrape_tracker();
}
if (c == 'p' && !handles.empty())
{
torrent_entry& te = get_active_torrent(handles);
if (!te.status.auto_managed && te.status.paused)
torrent_status const& ts = get_active_torrent(handles);
if (!ts.auto_managed && ts.paused)
{
te.handle.auto_managed(true);
ts.handle.auto_managed(true);
}
else
{
te.handle.auto_managed(false);
te.handle.pause(torrent_handle::graceful_pause);
ts.handle.auto_managed(false);
ts.handle.pause(torrent_handle::graceful_pause);
}
// the alert handler for save_resume_data_alert
// will save it to disk
if (te.status.need_save_resume) te.handle.save_resume_data();
if (ts.need_save_resume) ts.handle.save_resume_data();
}
if (c == 'c' && !handles.empty())
{
torrent_entry& te = get_active_torrent(handles);
te.handle.clear_error();
torrent_status const& ts = get_active_torrent(handles);
ts.handle.clear_error();
}
// toggle displays
@ -1332,15 +1375,19 @@ int main(int argc, char* argv[])
if (c == 'q') break;
int terminal_width = 80;
int terminal_height = 50;
#ifndef _WIN32
{
winsize size;
ioctl(STDOUT_FILENO, TIOCGWINSZ, (char*)&size);
terminal_width = size.ws_col;
terminal_height = size.ws_row;
if (terminal_width < 64)
terminal_width = 64;
if (terminal_height < 25)
terminal_height = 25;
}
#endif
@ -1353,7 +1400,7 @@ int main(int argc, char* argv[])
std::string event_string;
::print_alert(a.get(), event_string);
::handle_alert(ses, a.get(), handles);
::handle_alert(ses, a.get(), files);
events.push_back(event_string);
if (events.size() >= 20) events.pop_front();
@ -1370,7 +1417,7 @@ int main(int argc, char* argv[])
"[1] toggle IP [2] toggle AS [3] toggle timers [4] toggle block progress "
"[5] toggle peer rate [6] toggle failures [7] toggle send buffers [R] save resume data\n";
char const* filter_names[] = { "all", "downloading", "non-paused", "seeding", "paused"};
char const* filter_names[] = { "all", "downloading", "non-paused", "seeding", "queued", "stopped", "checking"};
for (int i = 0; i < sizeof(filter_names)/sizeof(filter_names[0]); ++i)
{
out += '[';
@ -1383,12 +1430,18 @@ int main(int argc, char* argv[])
char str[500];
int torrent_index = 0;
torrent_handle active_handle;
for (handles_t::iterator i = handles.begin();
int lines_printed = 3;
for (std::vector<torrent_status>::iterator i = handles.begin();
i != handles.end(); ++torrent_index)
{
torrent_entry& te = i->second;
if (!te.handle.is_valid())
if (lines_printed >= terminal_height - 15)
{
out += "...\n";
break;
}
torrent_status& s = *i;
if (!s.handle.is_valid())
{
handles.erase(i++);
continue;
@ -1398,12 +1451,6 @@ int main(int argc, char* argv[])
++i;
}
te.status = te.handle.status();
torrent_status const& s = te.status;
if (!show_torrent(te))
continue;
#ifdef ANSI_TERMINAL_COLORS
char const* term = "\x1b[0m";
#else
@ -1420,7 +1467,7 @@ int main(int argc, char* argv[])
out += " ";
}
int queue_pos = te.status.queue_position;
int queue_pos = s.queue_position;
if (queue_pos == -1) out += "- ";
else
{
@ -1431,7 +1478,7 @@ int main(int argc, char* argv[])
if (s.paused) out += esc("34");
else out += esc("37");
std::string name = te.handle.name();
std::string name = s.handle.name();
if (name.size() > 40) name.resize(40);
snprintf(str, sizeof(str), "%-40s %s ", name.c_str(), term);
out += str;
@ -1443,6 +1490,7 @@ int main(int argc, char* argv[])
out += s.error;
out += esc("0");
out += "\n";
++lines_printed;
continue;
}
@ -1467,8 +1515,9 @@ int main(int argc, char* argv[])
, s.up_bandwidth_queue, s.down_bandwidth_queue
, esc("32"), add_suffix(s.all_time_download).c_str(), term
, esc("31"), add_suffix(s.all_time_upload).c_str(), term
, s.seed_rank, te.status.need_save_resume?'S':' ', esc("0"));
, s.seed_rank, s.need_save_resume?'S':' ', esc("0"));
out += str;
++lines_printed;
if (torrent_index != active_torrent && s.state == torrent_status::seeding) continue;
char const* progress_bar_color = "33"; // yellow
@ -1499,12 +1548,14 @@ int main(int argc, char* argv[])
, progress_bar(s.progress_ppm / 1000, terminal_width - 43 - 20, "35").c_str());
out += str;
}
++lines_printed;
if (print_piece_bar && s.state != torrent_status::seeding)
{
out += " ";
out += piece_bar(s.pieces, terminal_width - 7);
out += "\n";
++lines_printed;
}
if (s.state != torrent_status::queued_for_checking && s.state != torrent_status::checking_files)
@ -1523,10 +1574,8 @@ int main(int argc, char* argv[])
, esc("37"), t.hours(), t.minutes(), t.seconds(), esc("0")
, esc("36"), s.current_tracker.c_str(), esc("0"));
out += str;
++lines_printed;
}
if (torrent_index != active_torrent) continue;
active_handle = te.handle;
}
cache_status cs = ses.get_cache_status();
@ -1624,10 +1673,12 @@ int main(int argc, char* argv[])
out += str;
}
if (active_handle.is_valid())
torrent_status const* st = 0;
if (!handles.empty()) st = &get_active_torrent(handles);
if (st && st->handle.is_valid())
{
torrent_handle h = active_handle;
torrent_status s = h.status();
torrent_handle h = st->handle;
torrent_status const& s = *st;
if ((print_downloads && s.state != torrent_status::seeding)
|| print_peers)
@ -1804,7 +1855,7 @@ int main(int argc, char* argv[])
if (!monitor_dir.empty()
&& next_dir_scan < time_now())
{
scan_dir(monitor_dir, ses, handles, preferred_ratio
scan_dir(monitor_dir, ses, files, preferred_ratio
, allocation_mode, save_path, torrent_upload_limit
, torrent_download_limit);
next_dir_scan = time_now() + seconds(poll_interval);
@ -1819,17 +1870,18 @@ int main(int argc, char* argv[])
ses.pause();
printf("saving resume data\n");
for (handles_t::iterator i = handles.begin();
i != handles.end(); ++i)
std::vector<torrent_status> temp;
ses.get_torrent_status(&temp, &yes, 0);
for (std::vector<torrent_status>::iterator i = temp.begin();
i != temp.end(); ++i)
{
torrent_entry& te = i->second;
if (!te.handle.is_valid()) continue;
te.status = te.handle.status();
if (te.status.paused) continue;
if (!te.status.has_metadata) continue;
torrent_status& st = *i;
if (!st.handle.is_valid()) continue;
if (st.paused) continue;
if (!st.has_metadata) continue;
// save_resume_data will generate an alert when it's done
te.handle.save_resume_data();
st.handle.save_resume_data();
++num_resume_data;
printf("\r%d ", num_resume_data);
}

View File

@ -274,7 +274,13 @@ namespace libtorrent
void remove_torrent(torrent_handle const& h, int options);
std::vector<torrent_handle> get_torrents();
void get_torrent_status(std::vector<torrent_status>* ret
, boost::function<bool(torrent_status const&)> const& pred
, boost::uint32_t flags) const;
void refresh_torrent_status(std::vector<torrent_status>* ret
, boost::uint32_t flags) const;
std::vector<torrent_handle> get_torrents() const;
void queue_check_torrent(boost::shared_ptr<torrent> const& t);
void dequeue_check_torrent(boost::shared_ptr<torrent> const& t);

View File

@ -176,6 +176,12 @@ namespace libtorrent
void save_state(entry& e, boost::uint32_t flags = 0xffffffff) const;
void load_state(lazy_entry const& e);
void get_torrent_status(std::vector<torrent_status>* ret
, boost::function<bool(torrent_status const&)> const& pred
, boost::uint32_t flags = 0) const;
void refresh_torrent_status(std::vector<torrent_status>* ret
, boost::uint32_t flags = 0) const;
// returns a list of all torrents in this session
std::vector<torrent_handle> get_torrents() const;

View File

@ -300,7 +300,7 @@ namespace libtorrent
void set_piece_deadline(int piece, int t, int flags);
void update_piece_priorities();
torrent_status status(boost::uint32_t flags) const;
void status(torrent_status* st, boost::uint32_t flags);
void file_progress(std::vector<size_type>& fp, int flags = 0) const;

View File

@ -69,6 +69,7 @@ namespace libtorrent
struct torrent_plugin;
struct peer_info;
struct peer_list_entry;
struct torrent_status;
#ifndef BOOST_NO_EXCEPTIONS
// for compatibility with 0.14
@ -77,273 +78,6 @@ namespace libtorrent
void throw_invalid_handle();
#endif
struct TORRENT_EXPORT torrent_status
{
torrent_status()
: state(checking_resume_data)
, paused(false)
, auto_managed(false)
, sequential_download(false)
, is_seeding(false)
, is_finished(false)
, has_metadata(false)
, progress(0.f)
, progress_ppm(0)
, total_download(0)
, total_upload(0)
, total_payload_download(0)
, total_payload_upload(0)
, total_failed_bytes(0)
, total_redundant_bytes(0)
, download_rate(0)
, upload_rate(0)
, download_payload_rate(0)
, upload_payload_rate(0)
, num_seeds(0)
, num_peers(0)
, num_complete(-1)
, num_incomplete(-1)
, list_seeds(0)
, list_peers(0)
, num_pieces(0)
, total_done(0)
, total_wanted_done(0)
, total_wanted(0)
, distributed_copies(0.f)
, block_size(0)
, num_uploads(0)
, num_connections(0)
, uploads_limit(0)
, connections_limit(0)
, storage_mode(storage_mode_sparse)
, up_bandwidth_queue(0)
, down_bandwidth_queue(0)
, all_time_upload(0)
, all_time_download(0)
, active_time(0)
, finished_time(0)
, seeding_time(0)
, seed_rank(0)
, last_scrape(0)
, has_incoming(false)
, sparse_regions(0)
, seed_mode(false)
, upload_mode(false)
, share_mode(false)
, priority(0)
, added_time(0)
, completed_time(0)
, last_seen_complete(0)
, time_since_upload(0)
, time_since_download(0)
, queue_position(0)
{}
enum state_t
{
queued_for_checking,
checking_files,
downloading_metadata,
downloading,
finished,
seeding,
allocating,
checking_resume_data
};
state_t state;
bool paused;
bool auto_managed;
bool sequential_download;
bool is_seeding;
bool is_finished;
bool has_metadata;
float progress;
// progress parts per million (progress * 1000000)
// when disabling floating point operations, this is
// the only option to query progress
int progress_ppm;
std::string error;
boost::posix_time::time_duration next_announce;
boost::posix_time::time_duration announce_interval;
std::string current_tracker;
// transferred this session!
// total, payload plus protocol
size_type total_download;
size_type total_upload;
// payload only
size_type total_payload_download;
size_type total_payload_upload;
// the amount of payload bytes that
// has failed their hash test
size_type total_failed_bytes;
// the number of payload bytes that
// has been received redundantly.
size_type total_redundant_bytes;
// current transfer rate
// payload plus protocol
int download_rate;
int upload_rate;
// the rate of payload that is
// sent and received
int download_payload_rate;
int upload_payload_rate;
// the number of peers this torrent is connected to
// that are seeding.
int num_seeds;
// the number of peers this torrent
// is connected to (including seeds).
int num_peers;
// if the tracker sends scrape info in its
// announce reply, these fields will be
// set to the total number of peers that
// have the whole file and the total number
// of peers that are still downloading
int num_complete;
int num_incomplete;
// this is the number of seeds whose IP we know
// but are not necessarily connected to
int list_seeds;
// this is the number of peers whose IP we know
// (including seeds), but are not necessarily
// connected to
int list_peers;
// the number of peers in our peerlist that
// we potentially could connect to
int connect_candidates;
bitfield pieces;
// this is the number of pieces the client has
// downloaded. it is equal to:
// std::accumulate(pieces->begin(), pieces->end());
int num_pieces;
// the number of bytes of the file we have
// including pieces that may have been filtered
// after we downloaded them
size_type total_done;
// the number of bytes we have of those that we
// want. i.e. not counting bytes from pieces that
// are filtered as not wanted.
size_type total_wanted_done;
// the total number of bytes we want to download
// this may be smaller than the total torrent size
// in case any pieces are filtered as not wanted
size_type total_wanted;
// the number of distributed copies of the file.
// note that one copy may be spread out among many peers.
//
// the integer part tells how many copies
// there are of the rarest piece(s)
//
// the fractional part tells the fraction of pieces that
// have more copies than the rarest piece(s).
// the number of full distributed copies (i.e. the number
// of peers that have the rarest piece)
int distributed_full_copies;
// the fraction of pieces that more peers has than the
// rarest pieces. This indicates how close the swarm is
// to have one more full distributed copy
int distributed_fraction;
float distributed_copies;
// the block size that is used in this torrent. i.e.
// the number of bytes each piece request asks for
// and each bit in the download queue bitfield represents
int block_size;
int num_uploads;
int num_connections;
int uploads_limit;
int connections_limit;
// true if the torrent is saved in compact mode
// false if it is saved in full allocation mode
storage_mode_t storage_mode;
int up_bandwidth_queue;
int down_bandwidth_queue;
// number of bytes downloaded since torrent was started
// saved and restored from resume data
size_type all_time_upload;
size_type all_time_download;
// the number of seconds of being active
// and as being a seed, saved and restored
// from resume data
int active_time;
int finished_time;
int seeding_time;
// higher value means more important to seed
int seed_rank;
// number of seconds since last scrape, or -1 if
// there hasn't been a scrape
int last_scrape;
// true if there are incoming connections to this
// torrent
bool has_incoming;
// the number of "holes" in the torrent
int sparse_regions;
// is true if this torrent is (still) in seed_mode
bool seed_mode;
// this is set to true when the torrent is blocked
// from downloading, typically caused by a file
// write operation failing
bool upload_mode;
// this is true if the torrent is in share-mode
bool share_mode;
// the priority of this torrent
int priority;
// the time this torrent was added and completed
time_t added_time;
time_t completed_time;
time_t last_seen_complete;
// number of seconds since last upload or download activity
int time_since_upload;
int time_since_download;
// the position in the download queue where this torrent is
// this is -1 for seeds and finished torrents
int queue_position;
// true if this torrent has had changes since the last
// time resume data was saved
bool need_save_resume;
};
struct TORRENT_EXPORT block_info
{
enum block_state_t
@ -677,6 +411,275 @@ namespace libtorrent
};
struct TORRENT_EXPORT torrent_status
{
torrent_status()
: state(checking_resume_data)
, paused(false)
, auto_managed(false)
, sequential_download(false)
, is_seeding(false)
, is_finished(false)
, has_metadata(false)
, progress(0.f)
, progress_ppm(0)
, total_download(0)
, total_upload(0)
, total_payload_download(0)
, total_payload_upload(0)
, total_failed_bytes(0)
, total_redundant_bytes(0)
, download_rate(0)
, upload_rate(0)
, download_payload_rate(0)
, upload_payload_rate(0)
, num_seeds(0)
, num_peers(0)
, num_complete(-1)
, num_incomplete(-1)
, list_seeds(0)
, list_peers(0)
, num_pieces(0)
, total_done(0)
, total_wanted_done(0)
, total_wanted(0)
, distributed_copies(0.f)
, block_size(0)
, num_uploads(0)
, num_connections(0)
, uploads_limit(0)
, connections_limit(0)
, storage_mode(storage_mode_sparse)
, up_bandwidth_queue(0)
, down_bandwidth_queue(0)
, all_time_upload(0)
, all_time_download(0)
, active_time(0)
, finished_time(0)
, seeding_time(0)
, seed_rank(0)
, last_scrape(0)
, has_incoming(false)
, sparse_regions(0)
, seed_mode(false)
, upload_mode(false)
, share_mode(false)
, priority(0)
, added_time(0)
, completed_time(0)
, last_seen_complete(0)
, time_since_upload(0)
, time_since_download(0)
, queue_position(0)
{}
// handle to the torrent
torrent_handle handle;
enum state_t
{
queued_for_checking,
checking_files,
downloading_metadata,
downloading,
finished,
seeding,
allocating,
checking_resume_data
};
state_t state;
bool paused;
bool auto_managed;
bool sequential_download;
bool is_seeding;
bool is_finished;
bool has_metadata;
float progress;
// progress parts per million (progress * 1000000)
// when disabling floating point operations, this is
// the only option to query progress
int progress_ppm;
std::string error;
boost::posix_time::time_duration next_announce;
boost::posix_time::time_duration announce_interval;
std::string current_tracker;
// transferred this session!
// total, payload plus protocol
size_type total_download;
size_type total_upload;
// payload only
size_type total_payload_download;
size_type total_payload_upload;
// the amount of payload bytes that
// has failed their hash test
size_type total_failed_bytes;
// the number of payload bytes that
// has been received redundantly.
size_type total_redundant_bytes;
// current transfer rate
// payload plus protocol
int download_rate;
int upload_rate;
// the rate of payload that is
// sent and received
int download_payload_rate;
int upload_payload_rate;
// the number of peers this torrent is connected to
// that are seeding.
int num_seeds;
// the number of peers this torrent
// is connected to (including seeds).
int num_peers;
// if the tracker sends scrape info in its
// announce reply, these fields will be
// set to the total number of peers that
// have the whole file and the total number
// of peers that are still downloading
int num_complete;
int num_incomplete;
// this is the number of seeds whose IP we know
// but are not necessarily connected to
int list_seeds;
// this is the number of peers whose IP we know
// (including seeds), but are not necessarily
// connected to
int list_peers;
// the number of peers in our peerlist that
// we potentially could connect to
int connect_candidates;
bitfield pieces;
// this is the number of pieces the client has
// downloaded. it is equal to:
// std::accumulate(pieces->begin(), pieces->end());
int num_pieces;
// the number of bytes of the file we have
// including pieces that may have been filtered
// after we downloaded them
size_type total_done;
// the number of bytes we have of those that we
// want. i.e. not counting bytes from pieces that
// are filtered as not wanted.
size_type total_wanted_done;
// the total number of bytes we want to download
// this may be smaller than the total torrent size
// in case any pieces are filtered as not wanted
size_type total_wanted;
// the number of distributed copies of the file.
// note that one copy may be spread out among many peers.
//
// the integer part tells how many copies
// there are of the rarest piece(s)
//
// the fractional part tells the fraction of pieces that
// have more copies than the rarest piece(s).
// the number of full distributed copies (i.e. the number
// of peers that have the rarest piece)
int distributed_full_copies;
// the fraction of pieces that more peers has than the
// rarest pieces. This indicates how close the swarm is
// to have one more full distributed copy
int distributed_fraction;
float distributed_copies;
// the block size that is used in this torrent. i.e.
// the number of bytes each piece request asks for
// and each bit in the download queue bitfield represents
int block_size;
int num_uploads;
int num_connections;
int uploads_limit;
int connections_limit;
// true if the torrent is saved in compact mode
// false if it is saved in full allocation mode
storage_mode_t storage_mode;
int up_bandwidth_queue;
int down_bandwidth_queue;
// number of bytes downloaded since torrent was started
// saved and restored from resume data
size_type all_time_upload;
size_type all_time_download;
// the number of seconds of being active
// and as being a seed, saved and restored
// from resume data
int active_time;
int finished_time;
int seeding_time;
// higher value means more important to seed
int seed_rank;
// number of seconds since last scrape, or -1 if
// there hasn't been a scrape
int last_scrape;
// true if there are incoming connections to this
// torrent
bool has_incoming;
// the number of "holes" in the torrent
int sparse_regions;
// is true if this torrent is (still) in seed_mode
bool seed_mode;
// this is set to true when the torrent is blocked
// from downloading, typically caused by a file
// write operation failing
bool upload_mode;
// this is true if the torrent is in share-mode
bool share_mode;
// the priority of this torrent
int priority;
// the time this torrent was added and completed
time_t added_time;
time_t completed_time;
time_t last_seen_complete;
// number of seconds since last upload or download activity
int time_since_upload;
int time_since_download;
// the position in the download queue where this torrent is
// this is -1 for seeds and finished torrents
int queue_position;
// true if this torrent has had changes since the last
// time resume data was saved
bool need_save_resume;
};
}

View File

@ -300,6 +300,12 @@ namespace libtorrent
m_impl->m_io_service.post(boost::bind(&fun_wrap, &done, &m_impl->cond, &m_impl->mut, boost::function<void(void)>(boost::bind(&session_impl:: x, m_impl.get(), a1, a2)))); \
do { m_impl->cond.wait(l); } while(!done)
#define TORRENT_SYNC_CALL3(x, a1, a2, a3) \
bool done = false; \
mutex::scoped_lock l(m_impl->mut); \
m_impl->m_io_service.post(boost::bind(&fun_wrap, &done, &m_impl->cond, &m_impl->mut, boost::function<void(void)>(boost::bind(&session_impl:: x, m_impl.get(), a1, a2, a3)))); \
do { m_impl->cond.wait(l); } while(!done)
#define TORRENT_SYNC_CALL_RET(type, x) \
bool done = false; \
type r; \
@ -509,6 +515,19 @@ namespace libtorrent
TORRENT_ASYNC_CALL1(set_key, key);
}
void session::get_torrent_status(std::vector<torrent_status>* ret
, boost::function<bool(torrent_status const&)> const& pred
, boost::uint32_t flags) const
{
TORRENT_SYNC_CALL3(get_torrent_status, ret, boost::ref(pred), flags);
}
void session::refresh_torrent_status(std::vector<torrent_status>* ret
, boost::uint32_t flags) const
{
TORRENT_SYNC_CALL2(refresh_torrent_status, ret, flags);
}
std::vector<torrent_handle> session::get_torrents() const
{
TORRENT_SYNC_CALL_RET(std::vector<torrent_handle>, get_torrents);

View File

@ -3592,11 +3592,39 @@ namespace aux {
}
#endif
std::vector<torrent_handle> session_impl::get_torrents()
void session_impl::get_torrent_status(std::vector<torrent_status>* ret
, boost::function<bool(torrent_status const&)> const& pred
, boost::uint32_t flags) const
{
for (session_impl::torrent_map::const_iterator i
= m_torrents.begin(), end(m_torrents.end());
i != end; ++i)
{
if (i->second->is_aborted()) continue;
torrent_status st;
i->second->status(&st, flags);
if (!pred(st)) continue;
ret->push_back(st);
}
}
void session_impl::refresh_torrent_status(std::vector<torrent_status>* ret
, boost::uint32_t flags) const
{
for (std::vector<torrent_status>::iterator i
= ret->begin(), end(ret->end()); i != end; ++i)
{
boost::shared_ptr<torrent> t = i->handle.m_torrent.lock();
if (!t) continue;
t->status(&*i, flags);
}
}
std::vector<torrent_handle> session_impl::get_torrents() const
{
std::vector<torrent_handle> ret;
for (session_impl::torrent_map::iterator i
for (session_impl::torrent_map::const_iterator i
= m_torrents.begin(), end(m_torrents.end());
i != end; ++i)
{

View File

@ -7139,96 +7139,96 @@ namespace libtorrent
#endif
}
torrent_status torrent::status(boost::uint32_t flags) const
void torrent::status(torrent_status* st, boost::uint32_t flags)
{
INVARIANT_CHECK;
ptime now = time_now();
torrent_status st;
st->handle = get_handle();
st.has_incoming = m_has_incoming;
if (m_error) st.error = m_error.message() + ": " + m_error_file;
st.seed_mode = m_seed_mode;
st->has_incoming = m_has_incoming;
if (m_error) st->error = m_error.message() + ": " + m_error_file;
st->seed_mode = m_seed_mode;
st.added_time = m_added_time;
st.completed_time = m_completed_time;
st->added_time = m_added_time;
st->completed_time = m_completed_time;
st.last_scrape = m_last_scrape;
st.share_mode = m_share_mode;
st.upload_mode = m_upload_mode;
st.up_bandwidth_queue = 0;
st.down_bandwidth_queue = 0;
st.priority = m_priority;
st->last_scrape = m_last_scrape;
st->share_mode = m_share_mode;
st->upload_mode = m_upload_mode;
st->up_bandwidth_queue = 0;
st->down_bandwidth_queue = 0;
st->priority = m_priority;
st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end()
st->num_peers = (int)std::count_if(m_connections.begin(), m_connections.end()
, !boost::bind(&peer_connection::is_connecting, _1));
st.list_peers = m_policy.num_peers();
st.list_seeds = m_policy.num_seeds();
st.connect_candidates = m_policy.num_connect_candidates();
st.seed_rank = seed_rank(settings());
st->list_peers = m_policy.num_peers();
st->list_seeds = m_policy.num_seeds();
st->connect_candidates = m_policy.num_connect_candidates();
st->seed_rank = seed_rank(settings());
st.all_time_upload = m_total_uploaded;
st.all_time_download = m_total_downloaded;
st->all_time_upload = m_total_uploaded;
st->all_time_download = m_total_downloaded;
// activity time
st.active_time = m_active_time;
st.active_time = m_active_time;
st.seeding_time = m_seeding_time;
st.time_since_upload = m_last_upload;
st.time_since_download = m_last_download;
st->active_time = m_active_time;
st->active_time = m_active_time;
st->seeding_time = m_seeding_time;
st->time_since_upload = m_last_upload;
st->time_since_download = m_last_download;
st.storage_mode = (storage_mode_t)m_storage_mode;
st->storage_mode = (storage_mode_t)m_storage_mode;
st.num_complete = (m_complete == 0xffffff) ? -1 : m_complete;
st.num_incomplete = (m_incomplete == 0xffffff) ? -1 : m_incomplete;
st.paused = is_torrent_paused();
st.auto_managed = m_auto_managed;
st.sequential_download = m_sequential_download;
st.is_seeding = is_seed();
st.is_finished = is_finished();
st.has_metadata = valid_metadata();
bytes_done(st, flags & torrent_handle::query_accurate_download_counters);
TORRENT_ASSERT(st.total_wanted_done >= 0);
TORRENT_ASSERT(st.total_done >= st.total_wanted_done);
st->num_complete = (m_complete == 0xffffff) ? -1 : m_complete;
st->num_incomplete = (m_incomplete == 0xffffff) ? -1 : m_incomplete;
st->paused = is_torrent_paused();
st->auto_managed = m_auto_managed;
st->sequential_download = m_sequential_download;
st->is_seeding = is_seed();
st->is_finished = is_finished();
st->has_metadata = valid_metadata();
bytes_done(*st, flags & torrent_handle::query_accurate_download_counters);
TORRENT_ASSERT(st->total_wanted_done >= 0);
TORRENT_ASSERT(st->total_done >= st->total_wanted_done);
// payload transfer
st.total_payload_download = m_stat.total_payload_download();
st.total_payload_upload = m_stat.total_payload_upload();
st->total_payload_download = m_stat.total_payload_download();
st->total_payload_upload = m_stat.total_payload_upload();
// total transfer
st.total_download = m_stat.total_payload_download()
st->total_download = m_stat.total_payload_download()
+ m_stat.total_protocol_download();
st.total_upload = m_stat.total_payload_upload()
st->total_upload = m_stat.total_payload_upload()
+ m_stat.total_protocol_upload();
// failed bytes
st.total_failed_bytes = m_total_failed_bytes;
st.total_redundant_bytes = m_total_redundant_bytes;
st->total_failed_bytes = m_total_failed_bytes;
st->total_redundant_bytes = m_total_redundant_bytes;
// transfer rate
st.download_rate = m_stat.download_rate();
st.upload_rate = m_stat.upload_rate();
st.download_payload_rate = m_stat.download_payload_rate();
st.upload_payload_rate = m_stat.upload_payload_rate();
st->download_rate = m_stat.download_rate();
st->upload_rate = m_stat.upload_rate();
st->download_payload_rate = m_stat.download_payload_rate();
st->upload_payload_rate = m_stat.upload_payload_rate();
if (m_waiting_tracker && !is_paused())
st.next_announce = boost::posix_time::seconds(
st->next_announce = boost::posix_time::seconds(
total_seconds(next_announce() - now));
else
st.next_announce = boost::posix_time::seconds(0);
st->next_announce = boost::posix_time::seconds(0);
if (st.next_announce.is_negative())
st.next_announce = boost::posix_time::seconds(0);
if (st->next_announce.is_negative())
st->next_announce = boost::posix_time::seconds(0);
st.announce_interval = boost::posix_time::seconds(0);
st->announce_interval = boost::posix_time::seconds(0);
st.current_tracker.clear();
st->current_tracker.clear();
if (m_last_working_tracker >= 0)
{
TORRENT_ASSERT(m_last_working_tracker < int(m_trackers.size()));
st.current_tracker = m_trackers[m_last_working_tracker].url;
st->current_tracker = m_trackers[m_last_working_tracker].url;
}
else
{
@ -7236,82 +7236,82 @@ namespace libtorrent
for (i = m_trackers.begin(); i != m_trackers.end(); ++i)
{
if (!i->updating) continue;
st.current_tracker = i->url;
st->current_tracker = i->url;
break;
}
}
st.num_uploads = m_num_uploads;
st.uploads_limit = m_max_uploads;
st.num_connections = int(m_connections.size());
st.connections_limit = m_max_connections;
st->num_uploads = m_num_uploads;
st->uploads_limit = m_max_uploads;
st->num_connections = int(m_connections.size());
st->connections_limit = m_max_connections;
// if we don't have any metadata, stop here
st.queue_position = queue_position();
st.need_save_resume = need_save_resume_data();
st->queue_position = queue_position();
st->need_save_resume = need_save_resume_data();
st.state = (torrent_status::state_t)m_state;
st->state = (torrent_status::state_t)m_state;
if (!valid_metadata())
{
st.state = torrent_status::downloading_metadata;
st.progress_ppm = m_progress_ppm;
st->state = torrent_status::downloading_metadata;
st->progress_ppm = m_progress_ppm;
#if !TORRENT_NO_FPU
st.progress = m_progress_ppm / 1000000.f;
st->progress = m_progress_ppm / 1000000.f;
#endif
st.block_size = 0;
return st;
st->block_size = 0;
return;
}
st.block_size = block_size();
st->block_size = block_size();
if (m_state == torrent_status::checking_files)
{
st.progress_ppm = m_progress_ppm;
st->progress_ppm = m_progress_ppm;
#if !TORRENT_NO_FPU
st.progress = m_progress_ppm / 1000000.f;
st->progress = m_progress_ppm / 1000000.f;
#endif
}
else if (st.total_wanted == 0)
else if (st->total_wanted == 0)
{
st.progress_ppm = 1000000;
st.progress = 1.f;
st->progress_ppm = 1000000;
st->progress = 1.f;
}
else
{
st.progress_ppm = st.total_wanted_done * 1000000
/ st.total_wanted;
st->progress_ppm = st->total_wanted_done * 1000000
/ st->total_wanted;
#if !TORRENT_NO_FPU
st.progress = st.progress_ppm / 1000000.f;
st->progress = st->progress_ppm / 1000000.f;
#endif
}
if (has_picker())
{
st.sparse_regions = m_picker->sparse_regions();
st->sparse_regions = m_picker->sparse_regions();
int num_pieces = m_picker->num_pieces();
st.pieces.resize(num_pieces, false);
st->pieces.resize(num_pieces, false);
for (int i = 0; i < num_pieces; ++i)
if (m_picker->have_piece(i)) st.pieces.set_bit(i);
if (m_picker->have_piece(i)) st->pieces.set_bit(i);
}
st.num_pieces = num_have();
st.num_seeds = num_seeds();
st->num_pieces = num_have();
st->num_seeds = num_seeds();
if ((flags & torrent_handle::query_distributed_copies) && m_picker.get())
{
boost::tie(st.distributed_full_copies, st.distributed_fraction) =
boost::tie(st->distributed_full_copies, st->distributed_fraction) =
m_picker->distributed_copies();
#if TORRENT_NO_FPU
st.distributed_copies = -1.f;
st->distributed_copies = -1.f;
#else
st.distributed_copies = st.distributed_full_copies
+ float(st.distributed_fraction) / 1000;
st->distributed_copies = st->distributed_full_copies
+ float(st->distributed_fraction) / 1000;
#endif
}
else
{
st.distributed_full_copies = -1;
st.distributed_fraction = -1;
st.distributed_copies = -1.f;
st->distributed_full_copies = -1;
st->distributed_fraction = -1;
st->distributed_copies = -1.f;
}
if (flags & torrent_handle::query_last_seen_complete)
@ -7322,13 +7322,12 @@ namespace libtorrent
{
last = (std::max)(last, (*i)->last_seen_complete());
}
st.last_seen_complete = last;
st->last_seen_complete = last;
}
else
{
st.last_seen_complete = 0;
st->last_seen_complete = 0;
}
return st;
}
void torrent::add_redundant_bytes(int b)

View File

@ -469,8 +469,9 @@ namespace libtorrent
torrent_status torrent_handle::status(boost::uint32_t flags) const
{
INVARIANT_CHECK;
TORRENT_SYNC_CALL_RET1(torrent_status, torrent_status(), status, flags);
return r;
torrent_status st;
TORRENT_SYNC_CALL2(status, &st, flags);
return st;
}
void torrent_handle::set_sequential_download(bool sd) const