initial support for queuing

This commit is contained in:
Arvid Norberg 2008-04-24 03:28:48 +00:00
parent fc7dd2c5eb
commit c043d4b21d
14 changed files with 912 additions and 521 deletions

View File

@ -1,3 +1,6 @@
* receive buffer optimizations (memcpy savings and memory savings)
* Support for specifying the TOS byte for peer traffic.
* Basic support for queueing of torrents.
* Better bias to give connections to downloading torrents
with fewer peers.
* Optimized resource usage (removed the checking thread)

View File

@ -98,118 +98,124 @@
<li><a class="reference internal" href="#pause-resume-is-paused" id="id82">pause() resume() is_paused()</a></li>
<li><a class="reference internal" href="#resolve-countries" id="id83">resolve_countries()</a></li>
<li><a class="reference internal" href="#is-seed" id="id84">is_seed()</a></li>
<li><a class="reference internal" href="#has-metadata" id="id85">has_metadata()</a></li>
<li><a class="reference internal" href="#set-tracker-login" id="id86">set_tracker_login()</a></li>
<li><a class="reference internal" href="#trackers-replace-trackers" id="id87">trackers() replace_trackers()</a></li>
<li><a class="reference internal" href="#add-url-seed-remove-url-seed-url-seeds" id="id88">add_url_seed() remove_url_seed() url_seeds()</a></li>
<li><a class="reference internal" href="#use-interface" id="id89">use_interface()</a></li>
<li><a class="reference internal" href="#info-hash" id="id90">info_hash()</a></li>
<li><a class="reference internal" href="#id5" id="id91">set_max_uploads() set_max_connections()</a></li>
<li><a class="reference internal" href="#save-resume-data" id="id92">save_resume_data()</a></li>
<li><a class="reference internal" href="#id6" id="id93">status()</a></li>
<li><a class="reference internal" href="#get-download-queue" id="id94">get_download_queue()</a></li>
<li><a class="reference internal" href="#get-peer-info" id="id95">get_peer_info()</a></li>
<li><a class="reference internal" href="#get-torrent-info" id="id96">get_torrent_info()</a></li>
<li><a class="reference internal" href="#is-valid" id="id97">is_valid()</a></li>
<li><a class="reference internal" href="#is-auto-managed-auto-managed" id="id85">is_auto_managed() auto_managed()</a></li>
<li><a class="reference internal" href="#has-metadata" id="id86">has_metadata()</a></li>
<li><a class="reference internal" href="#set-tracker-login" id="id87">set_tracker_login()</a></li>
<li><a class="reference internal" href="#trackers-replace-trackers" id="id88">trackers() replace_trackers()</a></li>
<li><a class="reference internal" href="#add-url-seed-remove-url-seed-url-seeds" id="id89">add_url_seed() remove_url_seed() url_seeds()</a></li>
<li><a class="reference internal" href="#use-interface" id="id90">use_interface()</a></li>
<li><a class="reference internal" href="#info-hash" id="id91">info_hash()</a></li>
<li><a class="reference internal" href="#id5" id="id92">set_max_uploads() set_max_connections()</a></li>
<li><a class="reference internal" href="#save-resume-data" id="id93">save_resume_data()</a></li>
<li><a class="reference internal" href="#id6" id="id94">status()</a></li>
<li><a class="reference internal" href="#get-download-queue" id="id95">get_download_queue()</a></li>
<li><a class="reference internal" href="#get-peer-info" id="id96">get_peer_info()</a></li>
<li><a class="reference internal" href="#get-torrent-info" id="id97">get_torrent_info()</a></li>
<li><a class="reference internal" href="#is-valid" id="id98">is_valid()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#torrent-status" id="id98">torrent_status</a></li>
<li><a class="reference internal" href="#peer-info" id="id99">peer_info</a></li>
<li><a class="reference internal" href="#session-settings" id="id100">session_settings</a></li>
<li><a class="reference internal" href="#pe-settings" id="id101">pe_settings</a></li>
<li><a class="reference internal" href="#proxy-settings" id="id102">proxy_settings</a></li>
<li><a class="reference internal" href="#ip-filter" id="id103">ip_filter</a><ul>
<li><a class="reference internal" href="#id9" id="id104">ip_filter()</a></li>
<li><a class="reference internal" href="#add-rule" id="id105">add_rule()</a></li>
<li><a class="reference internal" href="#access" id="id106">access()</a></li>
<li><a class="reference internal" href="#export-filter" id="id107">export_filter()</a></li>
<li><a class="reference internal" href="#torrent-status" id="id99">torrent_status</a></li>
<li><a class="reference internal" href="#peer-info" id="id100">peer_info</a></li>
<li><a class="reference internal" href="#session-settings" id="id101">session_settings</a></li>
<li><a class="reference internal" href="#pe-settings" id="id102">pe_settings</a></li>
<li><a class="reference internal" href="#proxy-settings" id="id103">proxy_settings</a></li>
<li><a class="reference internal" href="#ip-filter" id="id104">ip_filter</a><ul>
<li><a class="reference internal" href="#id9" id="id105">ip_filter()</a></li>
<li><a class="reference internal" href="#add-rule" id="id106">add_rule()</a></li>
<li><a class="reference internal" href="#access" id="id107">access()</a></li>
<li><a class="reference internal" href="#export-filter" id="id108">export_filter()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#big-number" id="id108">big_number</a></li>
<li><a class="reference internal" href="#hasher" id="id109">hasher</a></li>
<li><a class="reference internal" href="#fingerprint" id="id110">fingerprint</a></li>
<li><a class="reference internal" href="#upnp-and-nat-pmp" id="id111">UPnP and NAT-PMP</a><ul>
<li><a class="reference internal" href="#add-mapping" id="id112">add_mapping</a></li>
<li><a class="reference internal" href="#delete-mapping" id="id113">delete_mapping</a></li>
<li><a class="reference internal" href="#router-model" id="id114">router_model()</a></li>
<li><a class="reference internal" href="#big-number" id="id109">big_number</a></li>
<li><a class="reference internal" href="#hasher" id="id110">hasher</a></li>
<li><a class="reference internal" href="#fingerprint" id="id111">fingerprint</a></li>
<li><a class="reference internal" href="#upnp-and-nat-pmp" id="id112">UPnP and NAT-PMP</a><ul>
<li><a class="reference internal" href="#add-mapping" id="id113">add_mapping</a></li>
<li><a class="reference internal" href="#delete-mapping" id="id114">delete_mapping</a></li>
<li><a class="reference internal" href="#router-model" id="id115">router_model()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#free-functions" id="id115">free functions</a><ul>
<li><a class="reference internal" href="#identify-client" id="id116">identify_client()</a></li>
<li><a class="reference internal" href="#client-fingerprint" id="id117">client_fingerprint()</a></li>
<li><a class="reference internal" href="#bdecode-bencode" id="id118">bdecode() bencode()</a></li>
<li><a class="reference internal" href="#free-functions" id="id116">free functions</a><ul>
<li><a class="reference internal" href="#identify-client" id="id117">identify_client()</a></li>
<li><a class="reference internal" href="#client-fingerprint" id="id118">client_fingerprint()</a></li>
<li><a class="reference internal" href="#bdecode-bencode" id="id119">bdecode() bencode()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#alerts" id="id119">alerts</a><ul>
<li><a class="reference internal" href="#external-ip-alert" id="id120">external_ip_alert</a></li>
<li><a class="reference internal" href="#listen-failed-alert" id="id121">listen_failed_alert</a></li>
<li><a class="reference internal" href="#portmap-error-alert" id="id122">portmap_error_alert</a></li>
<li><a class="reference internal" href="#portmap-alert" id="id123">portmap_alert</a></li>
<li><a class="reference internal" href="#file-error-alert" id="id124">file_error_alert</a></li>
<li><a class="reference internal" href="#tracker-announce-alert" id="id125">tracker_announce_alert</a></li>
<li><a class="reference internal" href="#tracker-alert" id="id126">tracker_alert</a></li>
<li><a class="reference internal" href="#tracker-error-alert" id="id127">tracker_error_alert</a></li>
<li><a class="reference internal" href="#tracker-reply-alert" id="id128">tracker_reply_alert</a></li>
<li><a class="reference internal" href="#tracker-warning-alert" id="id129">tracker_warning_alert</a></li>
<li><a class="reference internal" href="#scrape-reply-alert" id="id130">scrape_reply_alert</a></li>
<li><a class="reference internal" href="#scrape-failed-alert" id="id131">scrape_failed_alert</a></li>
<li><a class="reference internal" href="#url-seed-alert" id="id132">url_seed_alert</a></li>
<li><a class="reference internal" href="#hash-failed-alert" id="id133">hash_failed_alert</a></li>
<li><a class="reference internal" href="#peer-ban-alert" id="id134">peer_ban_alert</a></li>
<li><a class="reference internal" href="#peer-error-alert" id="id135">peer_error_alert</a></li>
<li><a class="reference internal" href="#invalid-request-alert" id="id136">invalid_request_alert</a></li>
<li><a class="reference internal" href="#torrent-finished-alert" id="id137">torrent_finished_alert</a></li>
<li><a class="reference internal" href="#metadata-failed-alert" id="id138">metadata_failed_alert</a></li>
<li><a class="reference internal" href="#metadata-received-alert" id="id139">metadata_received_alert</a></li>
<li><a class="reference internal" href="#fastresume-rejected-alert" id="id140">fastresume_rejected_alert</a></li>
<li><a class="reference internal" href="#peer-blocked-alert" id="id141">peer_blocked_alert</a></li>
<li><a class="reference internal" href="#storage-moved-alert" id="id142">storage_moved_alert</a></li>
<li><a class="reference internal" href="#torrent-paused-alert" id="id143">torrent_paused_alert</a></li>
<li><a class="reference internal" href="#save-resume-data-alert" id="id144">save_resume_data_alert</a></li>
<li><a class="reference internal" href="#dispatcher" id="id145">dispatcher</a></li>
<li><a class="reference internal" href="#alerts" id="id120">alerts</a><ul>
<li><a class="reference internal" href="#external-ip-alert" id="id121">external_ip_alert</a></li>
<li><a class="reference internal" href="#listen-failed-alert" id="id122">listen_failed_alert</a></li>
<li><a class="reference internal" href="#portmap-error-alert" id="id123">portmap_error_alert</a></li>
<li><a class="reference internal" href="#portmap-alert" id="id124">portmap_alert</a></li>
<li><a class="reference internal" href="#file-error-alert" id="id125">file_error_alert</a></li>
<li><a class="reference internal" href="#tracker-announce-alert" id="id126">tracker_announce_alert</a></li>
<li><a class="reference internal" href="#tracker-alert" id="id127">tracker_alert</a></li>
<li><a class="reference internal" href="#tracker-error-alert" id="id128">tracker_error_alert</a></li>
<li><a class="reference internal" href="#tracker-reply-alert" id="id129">tracker_reply_alert</a></li>
<li><a class="reference internal" href="#tracker-warning-alert" id="id130">tracker_warning_alert</a></li>
<li><a class="reference internal" href="#scrape-reply-alert" id="id131">scrape_reply_alert</a></li>
<li><a class="reference internal" href="#scrape-failed-alert" id="id132">scrape_failed_alert</a></li>
<li><a class="reference internal" href="#url-seed-alert" id="id133">url_seed_alert</a></li>
<li><a class="reference internal" href="#hash-failed-alert" id="id134">hash_failed_alert</a></li>
<li><a class="reference internal" href="#peer-ban-alert" id="id135">peer_ban_alert</a></li>
<li><a class="reference internal" href="#peer-error-alert" id="id136">peer_error_alert</a></li>
<li><a class="reference internal" href="#invalid-request-alert" id="id137">invalid_request_alert</a></li>
<li><a class="reference internal" href="#torrent-finished-alert" id="id138">torrent_finished_alert</a></li>
<li><a class="reference internal" href="#metadata-failed-alert" id="id139">metadata_failed_alert</a></li>
<li><a class="reference internal" href="#metadata-received-alert" id="id140">metadata_received_alert</a></li>
<li><a class="reference internal" href="#fastresume-rejected-alert" id="id141">fastresume_rejected_alert</a></li>
<li><a class="reference internal" href="#peer-blocked-alert" id="id142">peer_blocked_alert</a></li>
<li><a class="reference internal" href="#storage-moved-alert" id="id143">storage_moved_alert</a></li>
<li><a class="reference internal" href="#torrent-paused-alert" id="id144">torrent_paused_alert</a></li>
<li><a class="reference internal" href="#save-resume-data-alert" id="id145">save_resume_data_alert</a></li>
<li><a class="reference internal" href="#dispatcher" id="id146">dispatcher</a></li>
</ul>
</li>
<li><a class="reference internal" href="#exceptions" id="id146">exceptions</a><ul>
<li><a class="reference internal" href="#invalid-handle" id="id147">invalid_handle</a></li>
<li><a class="reference internal" href="#duplicate-torrent" id="id148">duplicate_torrent</a></li>
<li><a class="reference internal" href="#invalid-encoding" id="id149">invalid_encoding</a></li>
<li><a class="reference internal" href="#type-error" id="id150">type_error</a></li>
<li><a class="reference internal" href="#invalid-torrent-file" id="id151">invalid_torrent_file</a></li>
<li><a class="reference internal" href="#exceptions" id="id147">exceptions</a><ul>
<li><a class="reference internal" href="#invalid-handle" id="id148">invalid_handle</a></li>
<li><a class="reference internal" href="#duplicate-torrent" id="id149">duplicate_torrent</a></li>
<li><a class="reference internal" href="#invalid-encoding" id="id150">invalid_encoding</a></li>
<li><a class="reference internal" href="#type-error" id="id151">type_error</a></li>
<li><a class="reference internal" href="#invalid-torrent-file" id="id152">invalid_torrent_file</a></li>
</ul>
</li>
<li><a class="reference internal" href="#storage-interface" id="id152">storage_interface</a><ul>
<li><a class="reference internal" href="#initialize" id="id153">initialize()</a></li>
<li><a class="reference internal" href="#read" id="id154">read()</a></li>
<li><a class="reference internal" href="#write" id="id155">write()</a></li>
<li><a class="reference internal" href="#id11" id="id156">move_storage()</a></li>
<li><a class="reference internal" href="#verify-resume-data" id="id157">verify_resume_data()</a></li>
<li><a class="reference internal" href="#write-resume-data" id="id158">write_resume_data()</a></li>
<li><a class="reference internal" href="#move-slot" id="id159">move_slot()</a></li>
<li><a class="reference internal" href="#swap-slots" id="id160">swap_slots()</a></li>
<li><a class="reference internal" href="#swap-slots3" id="id161">swap_slots3()</a></li>
<li><a class="reference internal" href="#hash-for-slot" id="id162">hash_for_slot()</a></li>
<li><a class="reference internal" href="#release-files" id="id163">release_files()</a></li>
<li><a class="reference internal" href="#delete-files" id="id164">delete_files()</a></li>
<li><a class="reference internal" href="#storage-interface" id="id153">storage_interface</a><ul>
<li><a class="reference internal" href="#initialize" id="id154">initialize()</a></li>
<li><a class="reference internal" href="#read" id="id155">read()</a></li>
<li><a class="reference internal" href="#write" id="id156">write()</a></li>
<li><a class="reference internal" href="#id11" id="id157">move_storage()</a></li>
<li><a class="reference internal" href="#verify-resume-data" id="id158">verify_resume_data()</a></li>
<li><a class="reference internal" href="#write-resume-data" id="id159">write_resume_data()</a></li>
<li><a class="reference internal" href="#move-slot" id="id160">move_slot()</a></li>
<li><a class="reference internal" href="#swap-slots" id="id161">swap_slots()</a></li>
<li><a class="reference internal" href="#swap-slots3" id="id162">swap_slots3()</a></li>
<li><a class="reference internal" href="#hash-for-slot" id="id163">hash_for_slot()</a></li>
<li><a class="reference internal" href="#release-files" id="id164">release_files()</a></li>
<li><a class="reference internal" href="#delete-files" id="id165">delete_files()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#fast-resume" id="id165">fast resume</a><ul>
<li><a class="reference internal" href="#file-format" id="id166">file format</a></li>
<li><a class="reference internal" href="#queuing" id="id166">queuing</a><ul>
<li><a class="reference internal" href="#downloading" id="id167">downloading</a></li>
<li><a class="reference internal" href="#seeding" id="id168">seeding</a></li>
</ul>
</li>
<li><a class="reference internal" href="#threads" id="id167">threads</a></li>
<li><a class="reference internal" href="#storage-allocation" id="id168">storage allocation</a><ul>
<li><a class="reference internal" href="#sparse-allocation" id="id169">sparse allocation</a></li>
<li><a class="reference internal" href="#full-allocation" id="id170">full allocation</a></li>
<li><a class="reference internal" href="#compact-allocation" id="id171">compact allocation</a></li>
<li><a class="reference internal" href="#fast-resume" id="id169">fast resume</a><ul>
<li><a class="reference internal" href="#file-format" id="id170">file format</a></li>
</ul>
</li>
<li><a class="reference internal" href="#extensions" id="id172">extensions</a><ul>
<li><a class="reference internal" href="#metadata-from-peers" id="id173">metadata from peers</a></li>
<li><a class="reference internal" href="#http-seeding" id="id174">HTTP seeding</a></li>
<li><a class="reference internal" href="#threads" id="id171">threads</a></li>
<li><a class="reference internal" href="#storage-allocation" id="id172">storage allocation</a><ul>
<li><a class="reference internal" href="#sparse-allocation" id="id173">sparse allocation</a></li>
<li><a class="reference internal" href="#full-allocation" id="id174">full allocation</a></li>
<li><a class="reference internal" href="#compact-allocation" id="id175">compact allocation</a></li>
</ul>
</li>
<li><a class="reference internal" href="#filename-checks" id="id175">filename checks</a></li>
<li><a class="reference internal" href="#acknowledgments" id="id176">acknowledgments</a></li>
<li><a class="reference internal" href="#extensions" id="id176">extensions</a><ul>
<li><a class="reference internal" href="#metadata-from-peers" id="id177">metadata from peers</a></li>
<li><a class="reference internal" href="#http-seeding" id="id178">HTTP seeding</a></li>
</ul>
</li>
<li><a class="reference internal" href="#filename-checks" id="id179">filename checks</a></li>
<li><a class="reference internal" href="#acknowledgments" id="id180">acknowledgments</a></li>
</ul>
</div>
<div class="section" id="overview">
@ -279,25 +285,7 @@ class session: public boost::noncopyable
, std::pair&lt;int, int&gt; listen_port_range
, char const* listen_interface = 0);
torrent_handle add_torrent(
boost::intrusive_ptr&lt;torrent_info&gt; const&amp; ti
, boost::filesystem::path const&amp; save_path
, entry const&amp; resume_data = entry()
, storage_mode_t storage_mode = storage_mode_sparse
, bool paused = false
, storage_constructor_type sc = default_storage_constructor
, void* userdata = 0);
torrent_handle add_torrent(
char const* tracker_url
, sha1_hash const&amp; info_hash
, char const* name
, boost::filesystem::path const&amp; save_path
, entry const&amp; resume_data = entry()
, storage_mode_t storage_mode = storage_mode_sparse
, bool paused = false
, storage_constructor_type sc = default_storage_constructor
, void* userdata = 0);
torrent_handle add_torrent(add_torrent_params const&amp; params);
session_proxy abort();
@ -439,34 +427,46 @@ typedef storage_interface* (&amp;storage_constructor_type)(
boost::intrusive_ptr&lt;torrent_info const&gt;, fs::path const&amp;
, file_pool&amp;);
torrent_handle add_torrent(
boost::intrusive_ptr&lt;torrent_info&gt; const&amp; ti
, boost::filesystem::path const&amp; save_path
, entry const&amp; resume_data = entry()
, storage_mode_t storage_mode = storage_mode_sparse
, bool paused = false
, storage_constructor_type sc = default_storage_constructor
, void* userdata = 0);
struct add_torrent_params
{
add_torrent_params(storage_constructor_type s);
torrent_handle add_torrent(
char const* tracker_url
, sha1_hash const&amp; info_hash
, char const* name
, boost::filesystem::path const&amp; save_path
, entry const&amp; resume_data = entry()
, storage_mode_t storage_mode = storage_mode_sparse
, bool paused = false
, storage_constructor_type sc = default_storage_constructor
, void* userdata = 0);
boost::intrusive_ptr&lt;torrent_info&gt; ti;
char const* tracker_url;
sha1_hash info_hash;
char const* name;
fs::path save_path;
entry const* resume_data;
storage_mode_t storage_mode;
bool paused;
bool auto_managed;
bool duplicate_is_error;
storage_constructor_type storage;
void* userdata;
};
torrent_handle add_torrent(add_torrent_params const&amp; params);
</pre>
</blockquote>
<p>You add torrents through the <tt class="docutils literal"><span class="pre">add_torrent()</span></tt> function where you give an
object representing the information found in the torrent file and the path where you
want to save the files. The <tt class="docutils literal"><span class="pre">save_path</span></tt> will be prepended to the directory
structure in the torrent-file.</p>
object with all the parameters.</p>
<p>The only mandatory parameter is <tt class="docutils literal"><span class="pre">save_path</span></tt> which is the directory where you
want the files to be saved. You also need to specify either the <tt class="docutils literal"><span class="pre">ti</span></tt> (the
torrent file) or <tt class="docutils literal"><span class="pre">info_hash</span></tt> (the info hash of the torrent). If you specify the
info-hash, the torrent file will be downloaded from peers, which requires them to
support the metadata extension. For the metadata extension to work, libtorrent must
be built with extensions enabled (<tt class="docutils literal"><span class="pre">TORRENT_DISABLE_EXTENSIONS</span></tt> must not be
defined). It also takes an optional <tt class="docutils literal"><span class="pre">name</span></tt> argument. This may be 0 in case no
name should be assigned to the torrent. In case it's not 0, the name is used for
the torrent as long as it doesn't have metadata. See <tt class="docutils literal"><span class="pre">torrent_handle::name</span></tt>.</p>
<p>If the torrent doesn't have a tracker, but relies on the DHT to find peers, the
<tt class="docutils literal"><span class="pre">tracker_url</span></tt> can be 0, otherwise you might specify a tracker url that tracks this
torrent.</p>
<p>If the torrent you are trying to add already exists in the session (is either queued
for checking, being checked or downloading) <tt class="docutils literal"><span class="pre">add_torrent()</span></tt> will throw
<a class="reference internal" href="#duplicate-torrent">duplicate_torrent</a> which derives from <tt class="docutils literal"><span class="pre">std::exception</span></tt>.</p>
<a class="reference internal" href="#duplicate-torrent">duplicate_torrent</a> which derives from <tt class="docutils literal"><span class="pre">std::exception</span></tt> unless <tt class="docutils literal"><span class="pre">duplicate_is_error</span></tt>
is set to false. In that case, <tt class="docutils literal"><span class="pre">add_torrent</span></tt> will return the handle to the existing
torrent.</p>
<p>The optional parameter, <tt class="docutils literal"><span class="pre">resume_data</span></tt> can be given if up to date fast-resume data
is available. The fast-resume data can be acquired from a running torrent by calling
<a class="reference internal" href="#save-resume-data">save_resume_data()</a> on <a class="reference internal" href="#torrent-handle">torrent_handle</a>. See <a class="reference internal" href="#fast-resume">fast resume</a>.</p>
@ -490,24 +490,19 @@ downloaded.</dd>
a paused state. I.e. it won't connect to the tracker or any of the peers until it's
resumed. This is typically a good way of avoiding race conditions when setting
configuration options on torrents before starting them.</p>
<p><tt class="docutils literal"><span class="pre">storage_constructor</span></tt> can be used to customize how the data is stored. The default
<p>If <tt class="docutils literal"><span class="pre">auto_managed</span></tt> is true, this torrent will be queued, started and seeded
automatically by libtorrent. When this is set, the torrent should also be started
as paused. The default queue order is the order the torrents were added. They
are all downloaded in that order. For more details, see <a class="reference internal" href="#queuing">queuing</a>.</p>
<p><tt class="docutils literal"><span class="pre">storage</span></tt> can be used to customize how the data is stored. The default
storage will simply write the data to the files it belongs to, but it could be
overridden to save everything to a single file at a specific location or encrypt the
content on disk for instance. For more information about the <tt class="docutils literal"><span class="pre">storage_interface</span></tt>
that needs to be implemented for a custom storage, see <a class="reference internal" href="#storage-interface">storage_interface</a>.</p>
<p>The <a class="reference internal" href="#torrent-handle">torrent_handle</a> returned by <tt class="docutils literal"><span class="pre">add_torrent()</span></tt> can be used to retrieve information
about the torrent's progress, its peers etc. It is also used to abort a torrent.</p>
<p>The <tt class="docutils literal"><span class="pre">userdata</span></tt> parameter is optional and will be passed on to the extension
constructor functions, if any (see <a class="reference internal" href="#add-extension">add_extension()</a>).</p>
<p>The second overload that takes a tracker url and an info-hash instead of metadata
(<tt class="docutils literal"><span class="pre">torrent_info</span></tt>) can be used with torrents where (at least some) peers support
the metadata extension. For the overload to be available, libtorrent must be built
with extensions enabled (<tt class="docutils literal"><span class="pre">TORRENT_DISABLE_EXTENSIONS</span></tt> must not be defined). It also
takes an optional <tt class="docutils literal"><span class="pre">name</span></tt> argument. This may be 0 in case no name should be assigned
to the torrent. In case it's not 0, the name is used for the torrent as long as it doesn't
have metadata. See <tt class="docutils literal"><span class="pre">torrent_handle::name</span></tt>.</p>
<p>If the torrent doesn't have a tracker, but relies on the DHT to find peers, the
<tt class="docutils literal"><span class="pre">tracker_url</span></tt> can be 0.</p>
<p>The <a class="reference internal" href="#torrent-handle">torrent_handle</a> returned by <tt class="docutils literal"><span class="pre">add_torrent()</span></tt> can be used to retrieve information
about the torrent's progress, its peers etc. It is also used to abort a torrent.</p>
</div>
<div class="section" id="remove-torrent">
<h2>remove_torrent()</h2>
@ -1679,12 +1674,8 @@ struct torrent_handle
void prioritize_files(std::vector&lt;int&gt; const&amp; files) const;
// these functions are deprecated
void filter_piece(int index, bool filter) const;
void filter_pieces(std::vector&lt;bool&gt; const&amp; bitmask) const;
bool is_piece_filtered(int index) const;
std::vector&lt;bool&gt; filtered_pieces() const;
void filter_files(std::vector&lt;bool&gt; const&amp; files) const;
bool is_auto_managed() const;
void auto_managed(bool m) const;
bool has_metadata() const;
@ -1705,8 +1696,8 @@ it will throw <tt class="docutils literal"><span class="pre">invalid_handle</spa
<div class="warning">
<p class="first admonition-title">Warning</p>
<p class="last">All operations on a <tt class="docutils literal"><span class="pre">torrent_handle</span></tt> may throw <a class="reference internal" href="#invalid-handle">invalid_handle</a>
exception, in case the handle is no longer refering to a torrent. There are
two exceptions, <tt class="docutils literal"><span class="pre">info_hash()</span></tt> and <tt class="docutils literal"><span class="pre">is_valid()</span></tt> will never throw.
exception, in case the handle is no longer refering to a torrent. There is
one exception <tt class="docutils literal"><span class="pre">is_valid()</span></tt> will never throw.
Since the torrents are processed by a background thread, there is no
guarantee that a handle will remain valid between two calls.</p>
</div>
@ -1936,6 +1927,18 @@ bool is_seed() const;
</blockquote>
<p>Returns true if the torrent is in seed mode (i.e. if it has finished downloading).</p>
</div>
<div class="section" id="is-auto-managed-auto-managed">
<h2>is_auto_managed() auto_managed()</h2>
<blockquote>
<pre class="literal-block">
bool is_auto_managed() const;
void auto_managed(bool m) const;
</pre>
</blockquote>
<p><tt class="docutils literal"><span class="pre">is_auto_managed()</span></tt> returns true if this torrent is currently <em>auto managed</em>.
<tt class="docutils literal"><span class="pre">auto_managed()</span></tt> changes whether the torrent is auto managed or not. For more info,
see <a class="reference internal" href="#queuing">queuing</a>.</p>
</div>
<div class="section" id="has-metadata">
<h2>has_metadata()</h2>
<blockquote>
@ -2208,7 +2211,6 @@ it has been added to the session. Usually this is because the storage for the to
somehow invalid or if the filenames are not allowed (and hence cannot be opened/created) on
your filesystem. If such an error occurs, a <a class="reference internal" href="#file-error-alert">file_error_alert</a> is generated and all handles
that refers to that torrent will become invalid.</p>
<p><em>TODO: document storage</em></p>
</div>
</div>
<div class="section" id="torrent-status">
@ -2289,6 +2291,8 @@ struct torrent_status
int active_time;
int seeding_time;
float seed_cycles;
};
</pre>
<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
@ -2442,6 +2446,10 @@ number of seconds this torrent has been active (not paused) and the number of
seconds it has been active while being a seed. <tt class="docutils literal"><span class="pre">seeding_time</span></tt> should be &gt;=
<tt class="docutils literal"><span class="pre">active_time</span></tt> They are saved in and restored from resume data, to keep totals
across sessions.</p>
<p><tt class="docutils literal"><span class="pre">seed_cycles</span></tt> is the number of times this torrent has reached the seed limits.
It will keep being seeded, but it will rotate between torrents that haven't
completed as many cycles. The fraction part of this number is the progress
of the current cycle. For more information, see <a class="reference internal" href="#queuing">queuing</a>.</p>
</div>
<div class="section" id="peer-info">
<h1>peer_info</h1>
@ -2814,6 +2822,13 @@ struct session_settings
int cache_expiry;
std::pair&lt;int, int&gt; outgoing_ports;
char peer_tos;
int active_downloads;
int active_seeds;
int auto_manage_interval;
float share_ratio_limit;
float seed_time_ratio_limit;
int seed_time_limit;
};
</pre>
<p><tt class="docutils literal"><span class="pre">user_agent</span></tt> this is the client identification to the tracker.
@ -2974,6 +2989,19 @@ to peers if a previous socket to that peer and port is in <tt class="docutils li
sent to peers (including web seeds). The default value for this is <tt class="docutils literal"><span class="pre">0x0</span></tt>
(no marking). One potentially useful TOS mark is <tt class="docutils literal"><span class="pre">0x20</span></tt>, this represents
the <em>QBone scavenger service</em>. For more details, see <a class="reference external" href="http://qbone.internet2.edu/qbss/">QBSS</a>.</p>
<p><tt class="docutils literal"><span class="pre">active_downloads</span></tt> and <tt class="docutils literal"><span class="pre">active_seeds</span></tt> controls how many active seeding and
downloading torrents the queuing mechanism allows. Seeding torrents are
counted against the downloads limit but downloading torrenst are not
counted against the seed limit.</p>
<p><tt class="docutils literal"><span class="pre">auto_manage_interval</span></tt> is the number of seconds between the torrent queue
is updated, and rotated.</p>
<p><tt class="docutils literal"><span class="pre">share_ratio_limit</span></tt> is the upload / download ratio limit for considering a
seeding torrent have completed one seed cycle. See <a class="reference internal" href="#queuing">queuing</a>.</p>
<p><tt class="docutils literal"><span class="pre">seed_time_ratio_limit</span></tt> is the seeding time / downloading time ratio limit
for considering a seeding torrent to have completed one seed cycle. See <a class="reference internal" href="#queuing">queuing</a>.</p>
<p><tt class="docutils literal"><span class="pre">seed_time_limit</span></tt> is the limit on the time a torrent has been an active seed
(specified in seconds) before it is considered having completed one seed cycle.
See <a class="reference internal" href="#queuing">queuing</a>.</p>
</div>
<div class="section" id="pe-settings">
<h1>pe_settings</h1>
@ -4247,6 +4275,43 @@ void delete_files() = 0;
<p>This function should delete all files and directories belonging to this storage.</p>
</div>
</div>
<div class="section" id="queuing">
<h1>queuing</h1>
<p>libtorrent supports <em>queuing</em>. Which means it makes sure that a limited number of
torrents are being downloaded at any given time, and once a torrent is completely
downloaded, the next in line is started.</p>
<p>Torrents that are <em>auto managed</em> are subject to the queuing and the active torrents
limits. To make a torrent auto managed, set <tt class="docutils literal"><span class="pre">auto_managed</span></tt> to true when adding the
torrent (see <a class="reference internal" href="#add-torrent">add_torrent()</a>).</p>
<p>The limits of the number of downloading and seeding torrents are controlled via
<tt class="docutils literal"><span class="pre">active_downloads</span></tt> and <tt class="docutils literal"><span class="pre">active_seeds</span></tt> in <a class="reference internal" href="#session-settings">session_settings</a>. These limits takes
non auto managed torrents into account as well. If there are are more non-auto managed
torrents being downloaded than the <tt class="docutils literal"><span class="pre">active_downloads</span></tt> setting, any auto managed
torrents will be queued until torrents are removed so that the number drops below
the limit.</p>
<p>Seeding torrents counts as downloads, but downloading torrents don't count as
seeding. So, <tt class="docutils literal"><span class="pre">active_downloads</span></tt> should typically be greater than <tt class="docutils literal"><span class="pre">active_seeds</span></tt>.
The default values are 8 active downloads and 5 active seeds.</p>
<p>At a regular interval, torrents are checked if there needs to be any re-ordering of
which torrents are active and which are queued. This interval can be controlled via
<tt class="docutils literal"><span class="pre">auto_manage_interval</span></tt> in <a class="reference internal" href="#session-settings">session_settings</a>. It defaults to every 30 seconds.</p>
<p>For queuing to work, resume data needs to be saved and restored for all torrents.
See <a class="reference internal" href="#save-resume-data">save_resume_data()</a>.</p>
<div class="section" id="downloading">
<h2>downloading</h2>
<p><strong>TODO: finish</strong></p>
</div>
<div class="section" id="seeding">
<h2>seeding</h2>
<p>Auto managed seeding torrents are rotated, so that all of them are allocated a fair
amount of seeding. Torrents with fewer completed <em>seed cycles</em> are prioritized for
seeding. A seed cycle is completed when a torrent meets either the share ratio limit
(uploaded bytes / downloaded bytes), the share time ratio (time seeding / time
downloaing) or seed time limit (time seeded).</p>
<p>The relevant settings to control these limits are <tt class="docutils literal"><span class="pre">share_ratio_limit</span></tt>,
<tt class="docutils literal"><span class="pre">seed_time_ratio_limit</span></tt> and <tt class="docutils literal"><span class="pre">seed_time_limit</span></tt> in <a class="reference internal" href="#session-settings">session_settings</a>.</p>
</div>
</div>
<div class="section" id="fast-resume">
<h1>fast resume</h1>
<p>The fast resume mechanism is a way to remember which pieces are downloaded

View File

@ -59,7 +59,6 @@ For documentation on these types, please refer to the `asio documentation`_.
.. _`asio documentation`: http://asio.sourceforge.net/asio-0.3.8/doc/asio/reference.html
session
=======
@ -77,25 +76,7 @@ The ``session`` class has the following synopsis::
, std::pair<int, int> listen_port_range
, char const* listen_interface = 0);
torrent_handle add_torrent(
boost::intrusive_ptr<torrent_info> const& ti
, boost::filesystem::path const& save_path
, entry const& resume_data = entry()
, storage_mode_t storage_mode = storage_mode_sparse
, bool paused = false
, storage_constructor_type sc = default_storage_constructor
, void* userdata = 0);
torrent_handle add_torrent(
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, boost::filesystem::path const& save_path
, entry const& resume_data = entry()
, storage_mode_t storage_mode = storage_mode_sparse
, bool paused = false
, storage_constructor_type sc = default_storage_constructor
, void* userdata = 0);
torrent_handle add_torrent(add_torrent_params const& params);
session_proxy abort();
@ -242,34 +223,48 @@ add_torrent()
boost::intrusive_ptr<torrent_info const>, fs::path const&
, file_pool&);
torrent_handle add_torrent(
boost::intrusive_ptr<torrent_info> const& ti
, boost::filesystem::path const& save_path
, entry const& resume_data = entry()
, storage_mode_t storage_mode = storage_mode_sparse
, bool paused = false
, storage_constructor_type sc = default_storage_constructor
, void* userdata = 0);
struct add_torrent_params
{
add_torrent_params(storage_constructor_type s);
torrent_handle add_torrent(
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, boost::filesystem::path const& save_path
, entry const& resume_data = entry()
, storage_mode_t storage_mode = storage_mode_sparse
, bool paused = false
, storage_constructor_type sc = default_storage_constructor
, void* userdata = 0);
boost::intrusive_ptr<torrent_info> ti;
char const* tracker_url;
sha1_hash info_hash;
char const* name;
fs::path save_path;
entry const* resume_data;
storage_mode_t storage_mode;
bool paused;
bool auto_managed;
bool duplicate_is_error;
storage_constructor_type storage;
void* userdata;
};
torrent_handle add_torrent(add_torrent_params const& params);
You add torrents through the ``add_torrent()`` function where you give an
object representing the information found in the torrent file and the path where you
want to save the files. The ``save_path`` will be prepended to the directory
structure in the torrent-file.
object with all the parameters.
The only mandatory parameter is ``save_path`` which is the directory where you
want the files to be saved. You also need to specify either the ``ti`` (the
torrent file) or ``info_hash`` (the info hash of the torrent). If you specify the
info-hash, the torrent file will be downloaded from peers, which requires them to
support the metadata extension. For the metadata extension to work, libtorrent must
be built with extensions enabled (``TORRENT_DISABLE_EXTENSIONS`` must not be
defined). It also takes an optional ``name`` argument. This may be 0 in case no
name should be assigned to the torrent. In case it's not 0, the name is used for
the torrent as long as it doesn't have metadata. See ``torrent_handle::name``.
If the torrent doesn't have a tracker, but relies on the DHT to find peers, the
``tracker_url`` can be 0, otherwise you might specify a tracker url that tracks this
torrent.
If the torrent you are trying to add already exists in the session (is either queued
for checking, being checked or downloading) ``add_torrent()`` will throw
duplicate_torrent_ which derives from ``std::exception``.
duplicate_torrent_ which derives from ``std::exception`` unless ``duplicate_is_error``
is set to false. In that case, ``add_torrent`` will return the handle to the existing
torrent.
The optional parameter, ``resume_data`` can be given if up to date fast-resume data
is available. The fast-resume data can be acquired from a running torrent by calling
@ -299,28 +294,22 @@ a paused state. I.e. it won't connect to the tracker or any of the peers until i
resumed. This is typically a good way of avoiding race conditions when setting
configuration options on torrents before starting them.
``storage_constructor`` can be used to customize how the data is stored. The default
If ``auto_managed`` is true, this torrent will be queued, started and seeded
automatically by libtorrent. When this is set, the torrent should also be started
as paused. The default queue order is the order the torrents were added. They
are all downloaded in that order. For more details, see queuing_.
``storage`` can be used to customize how the data is stored. The default
storage will simply write the data to the files it belongs to, but it could be
overridden to save everything to a single file at a specific location or encrypt the
content on disk for instance. For more information about the ``storage_interface``
that needs to be implemented for a custom storage, see `storage_interface`_.
The torrent_handle_ returned by ``add_torrent()`` can be used to retrieve information
about the torrent's progress, its peers etc. It is also used to abort a torrent.
The ``userdata`` parameter is optional and will be passed on to the extension
constructor functions, if any (see `add_extension()`_).
The second overload that takes a tracker url and an info-hash instead of metadata
(``torrent_info``) can be used with torrents where (at least some) peers support
the metadata extension. For the overload to be available, libtorrent must be built
with extensions enabled (``TORRENT_DISABLE_EXTENSIONS`` must not be defined). It also
takes an optional ``name`` argument. This may be 0 in case no name should be assigned
to the torrent. In case it's not 0, the name is used for the torrent as long as it doesn't
have metadata. See ``torrent_handle::name``.
If the torrent doesn't have a tracker, but relies on the DHT to find peers, the
``tracker_url`` can be 0.
The torrent_handle_ returned by ``add_torrent()`` can be used to retrieve information
about the torrent's progress, its peers etc. It is also used to abort a torrent.
remove_torrent()
@ -1624,13 +1613,9 @@ Its declaration looks like this::
void prioritize_files(std::vector<int> const& files) const;
// these functions are deprecated
void filter_piece(int index, bool filter) const;
void filter_pieces(std::vector<bool> const& bitmask) const;
bool is_piece_filtered(int index) const;
std::vector<bool> filtered_pieces() const;
void filter_files(std::vector<bool> const& files) const;
bool is_auto_managed() const;
void auto_managed(bool m) const;
bool has_metadata() const;
boost::filesystem::path save_path() const;
@ -1649,8 +1634,8 @@ valid handle. If you try to perform any operation on an uninitialized handle,
it will throw ``invalid_handle``.
.. warning:: All operations on a ``torrent_handle`` may throw invalid_handle_
exception, in case the handle is no longer refering to a torrent. There are
two exceptions, ``info_hash()`` and ``is_valid()`` will never throw.
exception, in case the handle is no longer refering to a torrent. There is
one exception ``is_valid()`` will never throw.
Since the torrents are processed by a background thread, there is no
guarantee that a handle will remain valid between two calls.
@ -1894,6 +1879,17 @@ is_seed()
Returns true if the torrent is in seed mode (i.e. if it has finished downloading).
is_auto_managed() auto_managed()
--------------------------------
::
bool is_auto_managed() const;
void auto_managed(bool m) const;
``is_auto_managed()`` returns true if this torrent is currently *auto managed*.
``auto_managed()`` changes whether the torrent is auto managed or not. For more info,
see queuing_.
has_metadata()
--------------
@ -2188,8 +2184,6 @@ somehow invalid or if the filenames are not allowed (and hence cannot be opened/
your filesystem. If such an error occurs, a file_error_alert_ is generated and all handles
that refers to that torrent will become invalid.
*TODO: document storage*
torrent_status
==============
@ -2270,6 +2264,8 @@ It contains the following fields::
int active_time;
int seeding_time;
float seed_cycles;
};
``progress`` is a value in the range [0, 1], that represents the progress of the
@ -2441,6 +2437,12 @@ seconds it has been active while being a seed. ``seeding_time`` should be >=
``active_time`` They are saved in and restored from resume data, to keep totals
across sessions.
``seed_cycles`` is the number of times this torrent has reached the seed limits.
It will keep being seeded, but it will rotate between torrents that haven't
completed as many cycles. The fraction part of this number is the progress
of the current cycle. For more information, see queuing_.
peer_info
=========
@ -2812,6 +2814,13 @@ that will be sent to the tracker. The user-agent is a good way to identify your
int cache_expiry;
std::pair<int, int> outgoing_ports;
char peer_tos;
int active_downloads;
int active_seeds;
int auto_manage_interval;
float share_ratio_limit;
float seed_time_ratio_limit;
int seed_time_limit;
};
``user_agent`` this is the client identification to the tracker.
@ -3014,6 +3023,24 @@ the *QBone scavenger service*. For more details, see QBSS_.
.. _`QBSS`: http://qbone.internet2.edu/qbss/
``active_downloads`` and ``active_seeds`` controls how many active seeding and
downloading torrents the queuing mechanism allows. Seeding torrents are
counted against the downloads limit but downloading torrenst are not
counted against the seed limit.
``auto_manage_interval`` is the number of seconds between the torrent queue
is updated, and rotated.
``share_ratio_limit`` is the upload / download ratio limit for considering a
seeding torrent have completed one seed cycle. See queuing_.
``seed_time_ratio_limit`` is the seeding time / downloading time ratio limit
for considering a seeding torrent to have completed one seed cycle. See queuing_.
``seed_time_limit`` is the limit on the time a torrent has been an active seed
(specified in seconds) before it is considered having completed one seed cycle.
See queuing_.
pe_settings
===========
@ -4449,6 +4476,53 @@ delete_files()
This function should delete all files and directories belonging to this storage.
queuing
=======
libtorrent supports *queuing*. Which means it makes sure that a limited number of
torrents are being downloaded at any given time, and once a torrent is completely
downloaded, the next in line is started.
Torrents that are *auto managed* are subject to the queuing and the active torrents
limits. To make a torrent auto managed, set ``auto_managed`` to true when adding the
torrent (see `add_torrent()`_).
The limits of the number of downloading and seeding torrents are controlled via
``active_downloads`` and ``active_seeds`` in session_settings_. These limits takes
non auto managed torrents into account as well. If there are are more non-auto managed
torrents being downloaded than the ``active_downloads`` setting, any auto managed
torrents will be queued until torrents are removed so that the number drops below
the limit.
Seeding torrents counts as downloads, but downloading torrents don't count as
seeding. So, ``active_downloads`` should typically be greater than ``active_seeds``.
The default values are 8 active downloads and 5 active seeds.
At a regular interval, torrents are checked if there needs to be any re-ordering of
which torrents are active and which are queued. This interval can be controlled via
``auto_manage_interval`` in session_settings_. It defaults to every 30 seconds.
For queuing to work, resume data needs to be saved and restored for all torrents.
See `save_resume_data()`_.
downloading
-----------
**TODO: finish**
seeding
-------
Auto managed seeding torrents are rotated, so that all of them are allocated a fair
amount of seeding. Torrents with fewer completed *seed cycles* are prioritized for
seeding. A seed cycle is completed when a torrent meets either the share ratio limit
(uploaded bytes / downloaded bytes), the share time ratio (time seeding / time
downloaing) or seed time limit (time seeded).
The relevant settings to control these limits are ``share_ratio_limit``,
``seed_time_ratio_limit`` and ``seed_time_limit`` in session_settings_.
fast resume
===========

View File

@ -529,9 +529,16 @@ void add_torrent(libtorrent::session& ses
catch (invalid_encoding&) {}
catch (boost::filesystem::filesystem_error&) {}
torrent_handle h = ses.add_torrent(t, save_path, resume_data
, compact_mode ? storage_mode_compact : storage_mode_sparse, false
); //, mapped_storage_constructor);
add_torrent_params p;
p.ti = t;
p.save_path = save_path;
p.resume_data = &resume_data;
p.storage_mode = compact_mode ? storage_mode_compact : storage_mode_sparse;
p.paused = true;
p.duplicate_is_error = false;
p.auto_managed = true;
torrent_handle h = ses.add_torrent(p);
handles.insert(std::make_pair(
monitored_dir?std::string(torrent):std::string(), h));
@ -948,9 +955,16 @@ int main(int ac, char* av[])
{
sha1_hash info_hash = boost::lexical_cast<sha1_hash>(what[1]);
torrent_handle h = ses.add_torrent(std::string(what[2]).c_str()
, info_hash, 0, save_path, entry(), compact_allocation_mode ? storage_mode_compact
: storage_mode_sparse, false); // , mapped_storage_constructor);
add_torrent_params p;
p.name = std::string(what[2]).c_str();
p.info_hash = info_hash;
p.save_path = save_path;
p.storage_mode = compact_allocation_mode ? storage_mode_compact : storage_mode_sparse;
p.paused = true;
p.duplicate_is_error = false;
p.auto_managed = true;
torrent_handle h = ses.add_torrent(p);
handles.insert(std::make_pair(std::string(), h));
h.set_max_connections(50);
@ -1203,25 +1217,27 @@ int main(int ac, char* av[])
++i;
}
out << "- " << esc("37") << std::setw(40)
<< std::setiosflags(std::ios::left);
if (h.has_metadata())
{
std::string name = h.get_torrent_info().name();
if (name.size() > 40) name.resize(40);
out << name;
}
else
{
out << "-";
}
out << "- ";
if (h.is_paused()) out << esc("34");
else out << esc("37");
out << std::setw(40) << std::setiosflags(std::ios::left);
std::string name = h.name();
if (name.size() > 40) name.resize(40);
out << name;
out << esc("0") << " ";
torrent_status s = h.status();
if (s.state != torrent_status::seeding)
bool paused = h.is_paused();
bool auto_managed = h.is_auto_managed();
if (paused && !auto_managed) out << "paused ";
else if (paused && auto_managed) out << "queued ";
else
{
static char const* state_str[] =
{"queued", "checking", "connecting", "downloading metadata"
{"queued for checking", "checking", "connecting", "downloading metadata"
, "downloading", "finished", "seeding", "allocating"};
out << state_str[s.state] << " ";
}
@ -1270,7 +1286,7 @@ int main(int ac, char* av[])
<< " bw queue: (" << s.up_bandwidth_queue << " | " << s.down_bandwidth_queue << ") "
"all-time (" << s.active_time - s.seeding_time << "/" << s.active_time << ")"
" (Rx: " << esc("32") << add_suffix(s.all_time_download) << esc("0")
<< " Tx: " << esc("31") << add_suffix(s.all_time_upload) << esc("0") << ")\n";
<< " Tx: " << esc("31") << add_suffix(s.all_time_upload) << esc("0") << ") " << s.seed_cycles << "\n";
if (s.state != torrent_status::seeding)
{
boost::posix_time::time_duration t = s.next_announce;
@ -1336,7 +1352,7 @@ int main(int ac, char* av[])
}
char* piece_state[4] = {"", "slow", "medium", "fast"};
out << "] " << piece_state[i->piece_state];
if (cp) out << (i->piece_state > 0?" | ":"") << "cache age: " << total_seconds(time_now() - cp->last_use);
if (cp) out << (i->piece_state > 0?" | ":"") << "cache age: " << (total_milliseconds(time_now() - cp->last_use) / 1000.f);
out << "\n";
}

View File

@ -198,25 +198,7 @@ namespace libtorrent
, const char* net_interface = 0);
bool is_listening() const;
torrent_handle add_torrent(
boost::intrusive_ptr<torrent_info> ti
, fs::path const& save_path
, entry const& resume_data
, storage_mode_t storage_mode
, storage_constructor_type sc
, bool paused
, void* userdata);
torrent_handle add_torrent(
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, fs::path const& save_path
, entry const& resume_data
, storage_mode_t storage_mode
, storage_constructor_type sc
, bool paused
, void* userdata);
torrent_handle add_torrent(add_torrent_params const&);
void remove_torrent(torrent_handle const& h, int options);
@ -491,6 +473,10 @@ namespace libtorrent
// recomputed.
int m_unchoke_time_scaler;
// this is used to decide when to recalculate which
// torrents to keep queued and which to activate
int m_auto_manage_time_scaler;
// works like unchoke_time_scaler but it
// is only decresed when the unchoke set
// is recomputed, and when it reaches zero,
@ -513,6 +499,10 @@ namespace libtorrent
bool m_incoming_connection;
void second_tick(asio::error_code const& e);
void recalculate_auto_managed_torrents();
void recalculate_unchoke_slots(int congested_torrents
, int uncongested_torrents);
ptime m_last_tick;
// when outgoing_ports is configured, this is the
@ -532,6 +522,10 @@ namespace libtorrent
// but for the udp port used by the DHT.
int m_external_udp_port;
// the sequence number to assign to the
// next torrent that's added
int m_torrent_sequence;
udp_socket m_dht_socket;
void on_receive_udp(asio::error_code const& e

View File

@ -62,6 +62,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/fingerprint.hpp"
#include "libtorrent/time.hpp"
#include "libtorrent/disk_io_thread.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/storage.hpp"
@ -120,6 +121,34 @@ namespace libtorrent
boost::shared_ptr<aux::session_impl> m_impl;
};
struct add_torrent_params
{
add_torrent_params(storage_constructor_type sc = default_storage_constructor)
: tracker_url(0)
, name(0)
, resume_data(0)
, storage_mode(storage_mode_sparse)
, paused(true)
, auto_managed(true)
, duplicate_is_error(false)
, storage(sc)
, userdata(0)
{}
boost::intrusive_ptr<torrent_info> ti;
char const* tracker_url;
sha1_hash info_hash;
char const* name;
fs::path save_path;
entry const* resume_data;
storage_mode_t storage_mode;
bool paused;
bool auto_managed;
bool duplicate_is_error;
storage_constructor_type storage;
void* userdata;
};
class TORRENT_EXPORT session: public boost::noncopyable, aux::eh_initializer
{
public:
@ -148,6 +177,9 @@ namespace libtorrent
torrent_handle find_torrent(sha1_hash const& info_hash) const;
// all torrent_handles must be destructed before the session is destructed!
torrent_handle add_torrent(add_torrent_params const& params);
// deprecated in 0.14
torrent_handle add_torrent(
torrent_info const& ti
, fs::path const& save_path
@ -156,6 +188,7 @@ namespace libtorrent
, bool paused = false
, storage_constructor_type sc = default_storage_constructor) TORRENT_DEPRECATED;
// deprecated in 0.14
torrent_handle add_torrent(
boost::intrusive_ptr<torrent_info> ti
, fs::path const& save_path
@ -163,8 +196,9 @@ namespace libtorrent
, storage_mode_t storage_mode = storage_mode_sparse
, bool paused = false
, storage_constructor_type sc = default_storage_constructor
, void* userdata = 0);
, void* userdata = 0) TORRENT_DEPRECATED;
// deprecated in 0.14
torrent_handle add_torrent(
char const* tracker_url
, sha1_hash const& info_hash
@ -174,7 +208,7 @@ namespace libtorrent
, storage_mode_t storage_mode = storage_mode_sparse
, bool paused = false
, storage_constructor_type sc = default_storage_constructor
, void* userdata = 0);
, void* userdata = 0) TORRENT_DEPRECATED;
session_proxy abort() { return session_proxy(m_impl); }

View File

@ -128,6 +128,12 @@ namespace libtorrent
, cache_expiry(60)
, outgoing_ports(0,0)
, peer_tos(0)
, active_downloads(8)
, active_seeds(5)
, auto_manage_interval(30)
, share_ratio_limit(2.f)
, seed_time_ratio_limit(7.f)
, seed_time_limit(24 * 60 * 60) // 24 hours
{}
// this is the user agent that will be sent to the tracker
@ -347,8 +353,31 @@ namespace libtorrent
// http://qbone.internet2.edu/qbss/
// For unmarked packets, set to 0
char peer_tos;
};
// for auto managed torrents, these are the limits
// they are subject to. If there are too many torrents
// some of the auto managed ones will be paused until
// some slots free up.
int active_downloads;
int active_seeds;
// the number of seconds in between recalculating which
// torrents to activate and which ones to queue
int auto_manage_interval;
// when a seeding torrent reaches eaither the share ratio
// (bytes up / bytes down) or the seed time ratio
// (seconds as seed / seconds as downloader) or the seed
// time limit (seconds as seed) it is considered
// done, and it will leave room for other torrents
// the default value for share ratio is 2
// the default seed time ratio is 7, because that's a common
// asymmetry ratio on connections
float share_ratio_limit;
float seed_time_ratio_limit;
int seed_time_limit;
};
#ifndef TORRENT_DISABLE_DHT
struct dht_settings
{

View File

@ -105,7 +105,9 @@ namespace libtorrent
, int block_size
, storage_constructor_type sc
, bool paused
, entry const& resume_data);
, entry const* resume_data
, int seq
, bool auto_managed);
// used with metadata-less torrents
// (the metadata is downloaded from the peers)
@ -120,7 +122,9 @@ namespace libtorrent
, int block_size
, storage_constructor_type sc
, bool paused
, entry const& resume_data);
, entry const* resume_data
, int seq
, bool auto_managed);
~torrent();
@ -147,6 +151,9 @@ namespace libtorrent
void files_checked();
void start_checking();
float seed_cycles(session_settings const& s) const;
int seed_cycles_int(session_settings const& s) const { return int(seed_cycles(s)); }
storage_mode_t storage_mode() const { return m_storage_mode; }
// this will flag the torrent as aborted. The main
// loop in session_impl will check for this state
@ -180,6 +187,9 @@ namespace libtorrent
bool is_paused() const { return m_paused; }
void save_resume_data();
bool is_auto_managed() const { return m_auto_managed; }
void auto_managed(bool a);
void delete_files();
// ============ start deprecation =============
@ -562,6 +572,8 @@ namespace libtorrent
// a return value of false indicates an error
bool set_metadata(entry const& metadata, std::string& error);
int sequence_number() const { return m_sequence_number; }
private:
void on_files_deleted(int ret, disk_io_job const& j);
@ -593,6 +605,13 @@ namespace libtorrent
// paused to the time should_request() is called
bool m_just_paused;
// if this is true, libtorrent may pause and resume
// this torrent depending on queuing rules. Torrents
// started with auto_managed flag set may be added in
// a paused state in case there are no available
// slots.
bool m_auto_managed;
tracker_request::event_t m_event;
void parse_response(const entry& e, std::vector<peer_entry>& peer_list);

View File

@ -118,6 +118,7 @@ namespace libtorrent
, all_time_download(0)
, active_time(0)
, seeding_time(0)
, seed_cycles(0.f)
{}
enum state_t
@ -255,6 +256,8 @@ namespace libtorrent
// from resume data
int active_time;
int seeding_time;
float seed_cycles;
};
struct TORRENT_EXPORT block_info
@ -332,6 +335,9 @@ namespace libtorrent
void resume() const;
void save_resume_data() const;
bool is_auto_managed() const;
void auto_managed(bool m) const;
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
void resolve_countries(bool r);
bool resolve_countries() const;
@ -342,6 +348,7 @@ namespace libtorrent
// ================ start deprecation ============
// deprecated in 0.13
// marks the piece with the given index as filtered
// it will not be downloaded
void filter_piece(int index, bool filter) const TORRENT_DEPRECATED;
@ -370,6 +377,7 @@ namespace libtorrent
// to.
void use_interface(const char* net_interface) const;
// deprecated in 0.14
// use save_resume_data() instead. It is async. and
// will return the resume data in an alert
entry write_resume_data() const TORRENT_DEPRECATED;

View File

@ -2449,6 +2449,7 @@ namespace libtorrent
if (pid == m_ses.get_peer_id())
{
set_failed();
disconnect("closing connection to ourself");
return;
}
@ -2465,6 +2466,7 @@ namespace libtorrent
// since it most likely is ourself then
if (pid == m_ses.get_peer_id())
{
set_failed();
disconnect("closing connection to ourself");
return;
}

View File

@ -239,6 +239,10 @@ namespace libtorrent
return m_impl->find_torrent_handle(info_hash);
}
torrent_handle session::add_torrent(add_torrent_params const& params)
{
return m_impl->add_torrent(params);
}
// if the torrent already exists, this will throw duplicate_torrent
torrent_handle session::add_torrent(
@ -251,8 +255,13 @@ namespace libtorrent
{
TORRENT_ASSERT(!ti.m_half_metadata);
boost::intrusive_ptr<torrent_info> tip(new torrent_info(ti));
return m_impl->add_torrent(tip, save_path, resume_data
, storage_mode, sc, paused, 0);
add_torrent_params p(sc);
p.ti = tip;
p.save_path = save_path;
p.resume_data = &resume_data;
p.storage_mode = storage_mode;
p.paused = paused;
return m_impl->add_torrent(p);
}
torrent_handle session::add_torrent(
@ -265,8 +274,14 @@ namespace libtorrent
, void* userdata)
{
TORRENT_ASSERT(!ti->m_half_metadata);
return m_impl->add_torrent(ti, save_path, resume_data
, storage_mode, sc, paused, userdata);
add_torrent_params p(sc);
p.ti = ti;
p.save_path = save_path;
p.resume_data = &resume_data;
p.storage_mode = storage_mode;
p.paused = paused;
p.userdata = userdata;
return m_impl->add_torrent(p);
}
torrent_handle session::add_torrent(
@ -280,8 +295,13 @@ namespace libtorrent
, storage_constructor_type sc
, void* userdata)
{
return m_impl->add_torrent(tracker_url, info_hash, name, save_path, e
, storage_mode, sc, paused, userdata);
add_torrent_params p(sc);
p.tracker_url = tracker_url;
p.info_hash = info_hash;
p.save_path = save_path;
p.paused = paused;
p.userdata = userdata;
return m_impl->add_torrent(p);
}
void session::remove_torrent(const torrent_handle& h, int options)

View File

@ -74,6 +74,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/kademlia/dht_tracker.hpp"
#include "libtorrent/enum_net.hpp"
#include "libtorrent/config.hpp"
#ifndef TORRENT_DISABLE_ENCRYPTION
@ -158,6 +159,7 @@ namespace aux {
, m_max_connections(200)
, m_num_unchoked(0)
, m_unchoke_time_scaler(0)
, m_auto_manage_time_scaler(0)
, m_optimistic_unchoke_time_scaler(0)
, m_disconnect_time_scaler(90)
, m_incoming_connection(false)
@ -165,6 +167,7 @@ namespace aux {
#ifndef TORRENT_DISABLE_DHT
, m_dht_same_port(true)
, m_external_udp_port(0)
, m_torrent_sequence(0)
, m_dht_socket(m_io_service, bind(&session_impl::on_receive_udp, this, _1, _2, _3, _4)
, m_half_open)
#endif
@ -762,7 +765,7 @@ namespace aux {
+ boost::lexical_cast<std::string>(ep) + "' " + e.message();
(*m_logger) << msg << "\n";
#endif
#ifdef _WIN32
#ifdef TORRENT_WINDOWS
// Windows sometimes generates this error. It seems to be
// non-fatal and we have to do another async_accept.
if (e.value() == ERROR_SEM_TIMEOUT)
@ -1173,6 +1176,16 @@ namespace aux {
c.keep_alive();
}
// --------------------------------------------------------------
// auto managed torrent
// --------------------------------------------------------------
m_auto_manage_time_scaler--;
if (m_auto_manage_time_scaler <= 0)
{
m_auto_manage_time_scaler = settings().auto_manage_interval;
recalculate_auto_managed_torrents();
}
// --------------------------------------------------------------
// unchoke set and optimistic unchoke calculations
// --------------------------------------------------------------
@ -1180,173 +1193,8 @@ namespace aux {
if (m_unchoke_time_scaler <= 0 && !m_connections.empty())
{
m_unchoke_time_scaler = settings().unchoke_interval;
std::vector<peer_connection*> peers;
for (connection_map::iterator i = m_connections.begin()
, end(m_connections.end()); i != end; ++i)
{
peer_connection* p = i->get();
torrent* t = p->associated_torrent().lock().get();
if (!p->peer_info_struct()
|| t == 0
|| !p->is_peer_interested()
|| p->is_disconnecting()
|| p->is_connecting()
|| (p->share_diff() < -free_upload_amount
&& !t->is_seed()))
{
if (!(*i)->is_choked() && t)
{
policy::peer* pi = p->peer_info_struct();
if (pi && pi->optimistically_unchoked)
{
pi->optimistically_unchoked = false;
// force a new optimistic unchoke
m_optimistic_unchoke_time_scaler = 0;
}
t->choke_peer(*(*i));
}
continue;
}
peers.push_back(i->get());
}
// sorts the peers that are eligible for unchoke by download rate and secondary
// by total upload. The reason for this is, if all torrents are being seeded,
// the download rate will be 0, and the peers we have sent the least to should
// be unchoked
std::sort(peers.begin(), peers.end()
, bind(&peer_connection::unchoke_compare, _1, _2));
std::for_each(m_connections.begin(), m_connections.end()
, bind(&peer_connection::reset_choke_counters, _1));
// auto unchoke
int upload_limit = m_bandwidth_manager[peer_connection::upload_channel]->throttle();
if (m_settings.auto_upload_slots && upload_limit != bandwidth_limit::inf)
{
// if our current upload rate is less than 90% of our
// limit AND most torrents are not "congested", i.e.
// they are not holding back because of a per-torrent
// limit
if (m_stat.upload_rate() < upload_limit * 0.9f
&& m_allowed_upload_slots <= m_num_unchoked + 1
&& congested_torrents < uncongested_torrents)
{
++m_allowed_upload_slots;
}
else if (m_upload_channel.queue_size() > 1
&& m_allowed_upload_slots > m_max_uploads)
{
--m_allowed_upload_slots;
}
}
// reserve one upload slot for optimistic unchokes
int unchoke_set_size = m_allowed_upload_slots - 1;
m_num_unchoked = 0;
// go through all the peers and unchoke the first ones and choke
// all the other ones.
for (std::vector<peer_connection*>::iterator i = peers.begin()
, end(peers.end()); i != end; ++i)
{
peer_connection* p = *i;
TORRENT_ASSERT(p);
torrent* t = p->associated_torrent().lock().get();
TORRENT_ASSERT(t);
if (unchoke_set_size > 0)
{
if (p->is_choked())
{
if (!t->unchoke_peer(*p))
continue;
}
--unchoke_set_size;
++m_num_unchoked;
TORRENT_ASSERT(p->peer_info_struct());
if (p->peer_info_struct()->optimistically_unchoked)
{
// force a new optimistic unchoke
m_optimistic_unchoke_time_scaler = 0;
p->peer_info_struct()->optimistically_unchoked = false;
}
}
else
{
TORRENT_ASSERT(p->peer_info_struct());
if (!p->is_choked() && !p->peer_info_struct()->optimistically_unchoked)
t->choke_peer(*p);
if (!p->is_choked())
++m_num_unchoked;
}
}
m_optimistic_unchoke_time_scaler--;
if (m_optimistic_unchoke_time_scaler <= 0)
{
m_optimistic_unchoke_time_scaler
= settings().optimistic_unchoke_multiplier;
// find the peer that has been waiting the longest to be optimistically
// unchoked
connection_map::iterator current_optimistic_unchoke = m_connections.end();
connection_map::iterator optimistic_unchoke_candidate = m_connections.end();
ptime last_unchoke = max_time();
for (connection_map::iterator i = m_connections.begin()
, end(m_connections.end()); i != end; ++i)
{
peer_connection* p = i->get();
TORRENT_ASSERT(p);
policy::peer* pi = p->peer_info_struct();
if (!pi) continue;
torrent* t = p->associated_torrent().lock().get();
if (!t) continue;
if (pi->optimistically_unchoked)
{
TORRENT_ASSERT(!p->is_choked());
TORRENT_ASSERT(current_optimistic_unchoke == m_connections.end());
current_optimistic_unchoke = i;
}
if (pi->last_optimistically_unchoked < last_unchoke
&& !p->is_connecting()
&& !p->is_disconnecting()
&& p->is_peer_interested()
&& t->free_upload_slots()
&& p->is_choked())
{
last_unchoke = pi->last_optimistically_unchoked;
optimistic_unchoke_candidate = i;
}
}
if (optimistic_unchoke_candidate != m_connections.end()
&& optimistic_unchoke_candidate != current_optimistic_unchoke)
{
if (current_optimistic_unchoke != m_connections.end())
{
torrent* t = (*current_optimistic_unchoke)->associated_torrent().lock().get();
TORRENT_ASSERT(t);
(*current_optimistic_unchoke)->peer_info_struct()->optimistically_unchoked = false;
t->choke_peer(*current_optimistic_unchoke->get());
}
else
{
++m_num_unchoked;
}
torrent* t = (*optimistic_unchoke_candidate)->associated_torrent().lock().get();
TORRENT_ASSERT(t);
bool ret = t->unchoke_peer(*optimistic_unchoke_candidate->get());
TORRENT_ASSERT(ret);
(*optimistic_unchoke_candidate)->peer_info_struct()->optimistically_unchoked = true;
}
}
recalculate_unchoke_slots(congested_torrents
, uncongested_torrents);
}
// --------------------------------------------------------------
@ -1357,7 +1205,7 @@ namespace aux {
{
m_disconnect_time_scaler = 90;
// every 60 seconds, disconnect the worst peer
// every 90 seconds, disconnect the worst peer
// if we have reached the connection limit
if (num_connections() >= max_connections() && !m_torrents.empty())
{
@ -1372,6 +1220,269 @@ namespace aux {
}
}
void session_impl::recalculate_auto_managed_torrents()
{
// these vectors are filled with auto managed torrents
std::vector<torrent*> downloaders;
downloaders.reserve(m_torrents.size());
std::vector<torrent*> seeds;
seeds.reserve(m_torrents.size());
// these counters are set to the number of torrents
// of each kind we're allowed to have active
int num_downloaders = settings().active_downloads;
int num_seeds = settings().active_seeds;
for (torrent_map::iterator i = m_torrents.begin()
, end(m_torrents.end()); i != end; ++i)
{
torrent* t = i->second.get();
TORRENT_ASSERT(t);
if (t->is_auto_managed())
{
// this torrent is auto managed, add it to
// the list (depending on if it's a seed or not)
if (t->is_finished())
seeds.push_back(t);
else
downloaders.push_back(t);
}
else if (!t->is_paused())
{
// this is not an auto managed torrent,
// if it's running, decrease the respective
// counters.
if (t->is_finished())
{
--num_seeds;
--num_downloaders;
}
else
{
--num_downloaders;
}
}
}
bool handled_by_extension = false;
#ifndef TORRENT_DISABLE_EXTENSIONS
// TODO: allow extensions to sort torrents for queuing
#endif
if (!handled_by_extension)
{
std::sort(downloaders.begin(), downloaders.end()
, bind(&torrent::sequence_number, _1) < bind(&torrent::sequence_number, _2));
std::sort(seeds.begin(), seeds.end()
, bind(&torrent::seed_cycles_int, _1, boost::ref(m_settings))
< bind(&torrent::seed_cycles_int, _2, boost::ref(m_settings)));
}
for (std::vector<torrent*>::iterator i = downloaders.begin()
, end(downloaders.end()); i != end; ++i)
{
torrent* t = *i;
if (num_downloaders > 0)
{
--num_downloaders;
if (t->is_paused()) t->resume();
}
else
{
if (!t->is_paused()) t->pause();
}
}
for (std::vector<torrent*>::iterator i = seeds.begin()
, end(seeds.end()); i != end; ++i)
{
torrent* t = *i;
if (num_downloaders > 0 && num_seeds > 0)
{
--num_downloaders;
--num_seeds;
if (t->is_paused()) t->resume();
}
else
{
if (!t->is_paused()) t->pause();
}
}
}
void session_impl::recalculate_unchoke_slots(int congested_torrents
, int uncongested_torrents)
{
std::vector<peer_connection*> peers;
for (connection_map::iterator i = m_connections.begin()
, end(m_connections.end()); i != end; ++i)
{
peer_connection* p = i->get();
torrent* t = p->associated_torrent().lock().get();
if (!p->peer_info_struct()
|| t == 0
|| !p->is_peer_interested()
|| p->is_disconnecting()
|| p->is_connecting()
|| (p->share_diff() < -free_upload_amount
&& !t->is_seed()))
{
if (!(*i)->is_choked() && t)
{
policy::peer* pi = p->peer_info_struct();
if (pi && pi->optimistically_unchoked)
{
pi->optimistically_unchoked = false;
// force a new optimistic unchoke
m_optimistic_unchoke_time_scaler = 0;
}
t->choke_peer(*(*i));
}
continue;
}
peers.push_back(i->get());
}
// sorts the peers that are eligible for unchoke by download rate and secondary
// by total upload. The reason for this is, if all torrents are being seeded,
// the download rate will be 0, and the peers we have sent the least to should
// be unchoked
std::sort(peers.begin(), peers.end()
, bind(&peer_connection::unchoke_compare, _1, _2));
std::for_each(m_connections.begin(), m_connections.end()
, bind(&peer_connection::reset_choke_counters, _1));
// auto unchoke
int upload_limit = m_bandwidth_manager[peer_connection::upload_channel]->throttle();
if (m_settings.auto_upload_slots && upload_limit != bandwidth_limit::inf)
{
// if our current upload rate is less than 90% of our
// limit AND most torrents are not "congested", i.e.
// they are not holding back because of a per-torrent
// limit
if (m_stat.upload_rate() < upload_limit * 0.9f
&& m_allowed_upload_slots <= m_num_unchoked + 1
&& congested_torrents < uncongested_torrents)
{
++m_allowed_upload_slots;
}
else if (m_upload_channel.queue_size() > 1
&& m_allowed_upload_slots > m_max_uploads)
{
--m_allowed_upload_slots;
}
}
// reserve one upload slot for optimistic unchokes
int unchoke_set_size = m_allowed_upload_slots - 1;
m_num_unchoked = 0;
// go through all the peers and unchoke the first ones and choke
// all the other ones.
for (std::vector<peer_connection*>::iterator i = peers.begin()
, end(peers.end()); i != end; ++i)
{
peer_connection* p = *i;
TORRENT_ASSERT(p);
torrent* t = p->associated_torrent().lock().get();
TORRENT_ASSERT(t);
if (unchoke_set_size > 0)
{
if (p->is_choked())
{
if (!t->unchoke_peer(*p))
continue;
}
--unchoke_set_size;
++m_num_unchoked;
TORRENT_ASSERT(p->peer_info_struct());
if (p->peer_info_struct()->optimistically_unchoked)
{
// force a new optimistic unchoke
m_optimistic_unchoke_time_scaler = 0;
p->peer_info_struct()->optimistically_unchoked = false;
}
}
else
{
TORRENT_ASSERT(p->peer_info_struct());
if (!p->is_choked() && !p->peer_info_struct()->optimistically_unchoked)
t->choke_peer(*p);
if (!p->is_choked())
++m_num_unchoked;
}
}
m_optimistic_unchoke_time_scaler--;
if (m_optimistic_unchoke_time_scaler <= 0)
{
m_optimistic_unchoke_time_scaler
= settings().optimistic_unchoke_multiplier;
// find the peer that has been waiting the longest to be optimistically
// unchoked
connection_map::iterator current_optimistic_unchoke = m_connections.end();
connection_map::iterator optimistic_unchoke_candidate = m_connections.end();
ptime last_unchoke = max_time();
for (connection_map::iterator i = m_connections.begin()
, end(m_connections.end()); i != end; ++i)
{
peer_connection* p = i->get();
TORRENT_ASSERT(p);
policy::peer* pi = p->peer_info_struct();
if (!pi) continue;
torrent* t = p->associated_torrent().lock().get();
if (!t) continue;
if (pi->optimistically_unchoked)
{
TORRENT_ASSERT(!p->is_choked());
TORRENT_ASSERT(current_optimistic_unchoke == m_connections.end());
current_optimistic_unchoke = i;
}
if (pi->last_optimistically_unchoked < last_unchoke
&& !p->is_connecting()
&& !p->is_disconnecting()
&& p->is_peer_interested()
&& t->free_upload_slots()
&& p->is_choked())
{
last_unchoke = pi->last_optimistically_unchoked;
optimistic_unchoke_candidate = i;
}
}
if (optimistic_unchoke_candidate != m_connections.end()
&& optimistic_unchoke_candidate != current_optimistic_unchoke)
{
if (current_optimistic_unchoke != m_connections.end())
{
torrent* t = (*current_optimistic_unchoke)->associated_torrent().lock().get();
TORRENT_ASSERT(t);
(*current_optimistic_unchoke)->peer_info_struct()->optimistically_unchoked = false;
t->choke_peer(*current_optimistic_unchoke->get());
}
else
{
++m_num_unchoked;
}
torrent* t = (*optimistic_unchoke_candidate)->associated_torrent().lock().get();
TORRENT_ASSERT(t);
bool ret = t->unchoke_peer(*optimistic_unchoke_candidate->get());
TORRENT_ASSERT(ret);
(*optimistic_unchoke_candidate)->peer_info_struct()->optimistically_unchoked = true;
}
}
}
void session_impl::operator()()
{
eh_initializer();
@ -1476,18 +1587,11 @@ namespace aux {
return torrent_handle(find_torrent(info_hash));
}
torrent_handle session_impl::add_torrent(
boost::intrusive_ptr<torrent_info> ti
, fs::path const& save_path
, entry const& resume_data
, storage_mode_t storage_mode
, storage_constructor_type sc
, bool paused
, void* userdata)
torrent_handle session_impl::add_torrent(add_torrent_params const& params)
{
TORRENT_ASSERT(!save_path.empty());
TORRENT_ASSERT(!params.save_path.empty());
if (ti->begin_files() == ti->end_files())
if (params.ti && params.ti->num_files() == 0)
{
#ifndef BOOST_NO_EXCEPTIONS
throw std::runtime_error("no files in torrent");
@ -1510,9 +1614,18 @@ namespace aux {
#endif
}
// figure out the info hash of the torrent
sha1_hash const* ih = 0;
if (params.ti) ih = &params.ti->info_hash();
else ih = &params.info_hash;
// is the torrent already active?
if (!find_torrent(ti->info_hash()).expired())
boost::shared_ptr<torrent> torrent_ptr = find_torrent(*ih).lock();
if (torrent_ptr)
{
if (!params.duplicate_is_error)
return torrent_handle(torrent_ptr);
#ifndef BOOST_NO_EXCEPTIONS
throw duplicate_torrent();
#else
@ -1523,25 +1636,36 @@ namespace aux {
// create the torrent and the data associated with
// the checker thread and store it before starting
// the thread
boost::shared_ptr<torrent> torrent_ptr(
new torrent(*this, ti, save_path
, m_listen_interface, storage_mode, 16 * 1024
, sc, paused, resume_data));
if (params.ti)
{
torrent_ptr.reset(new torrent(*this, params.ti, params.save_path
, m_listen_interface, params.storage_mode, 16 * 1024
, params.storage, params.paused, params.resume_data
, m_torrent_sequence, params.auto_managed));
}
else
{
torrent_ptr.reset(new torrent(*this, params.tracker_url, *ih, params.name
, params.save_path, m_listen_interface, params.storage_mode, 16 * 1024
, params.storage, params.paused, params.resume_data
, m_torrent_sequence, params.auto_managed));
}
torrent_ptr->start();
++m_torrent_sequence;
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
boost::shared_ptr<torrent_plugin> tp((*i)(torrent_ptr.get(), userdata));
boost::shared_ptr<torrent_plugin> tp((*i)(torrent_ptr.get(), params.userdata));
if (tp) torrent_ptr->add_extension(tp);
}
#endif
#ifndef TORRENT_DISABLE_DHT
if (m_dht)
if (m_dht && params.ti)
{
torrent_info::nodes_t const& nodes = ti->nodes();
torrent_info::nodes_t const& nodes = params.ti->nodes();
std::for_each(nodes.begin(), nodes.end(), bind(
(void(dht::dht_tracker::*)(std::pair<std::string, int> const&))
&dht::dht_tracker::add_node
@ -1549,7 +1673,7 @@ namespace aux {
}
#endif
m_torrents.insert(std::make_pair(ti->info_hash(), torrent_ptr));
m_torrents.insert(std::make_pair(*ih, torrent_ptr));
return torrent_handle(torrent_ptr);
}
@ -1568,62 +1692,6 @@ namespace aux {
m_queued_for_checking.front()->start_checking();
}
torrent_handle session_impl::add_torrent(
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, fs::path const& save_path
, entry const& resume_data
, storage_mode_t storage_mode
, storage_constructor_type sc
, bool paused
, void* userdata)
{
// TODO: support resume data in this case
TORRENT_ASSERT(!save_path.empty());
// lock the session
session_impl::mutex_t::scoped_lock l(m_mutex);
// INVARIANT_CHECK;
// is the torrent already active?
if (!find_torrent(info_hash).expired())
{
#ifndef BOOST_NO_EXCEPTIONS
throw duplicate_torrent();
#else
return torrent_handle();
#endif
}
// you cannot add new torrents to a session that is closing down
TORRENT_ASSERT(!is_aborted());
// create the torrent and the data associated with
// the checker thread and store it before starting
// the thread
boost::shared_ptr<torrent> torrent_ptr(
new torrent(*this, tracker_url, info_hash, name
, save_path, m_listen_interface, storage_mode, 16 * 1024
, sc, paused, resume_data));
torrent_ptr->start();
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
boost::shared_ptr<torrent_plugin> tp((*i)(torrent_ptr.get(), userdata));
if (tp) torrent_ptr->add_extension(tp);
}
#endif
m_torrents.insert(std::make_pair(info_hash, torrent_ptr));
return torrent_handle(torrent_ptr);
}
void session_impl::remove_torrent(const torrent_handle& h, int options)
{
boost::shared_ptr<torrent> tptr = h.m_torrent.lock();

View File

@ -157,11 +157,14 @@ namespace libtorrent
, int block_size
, storage_constructor_type sc
, bool paused
, entry const& resume_data)
, entry const* resume_data
, int seq
, bool auto_managed)
: m_torrent_file(tf)
, m_abort(false)
, m_paused(paused)
, m_just_paused(false)
, m_auto_managed(auto_managed)
, m_event(tracker_request::started)
, m_block_size(0)
, m_storage(0)
@ -196,7 +199,6 @@ namespace libtorrent
, m_storage_mode(storage_mode)
, m_state(torrent_status::queued_for_checking)
, m_progress(0.f)
, m_resume_data(resume_data)
, m_default_block_size(block_size)
, m_connections_initialized(true)
, m_settings(ses.settings())
@ -206,11 +208,13 @@ namespace libtorrent
, m_max_connections((std::numeric_limits<int>::max)())
, m_deficit_counter(0)
, m_policy(this)
, m_sequence_number(seq)
, m_active_time(seconds(0))
, m_seeding_time(seconds(0))
, m_total_uploaded(0)
, m_total_downloaded(0)
{
if (resume_data) m_resume_data = *resume_data;
#ifndef NDEBUG
m_files_checked = false;
#endif
@ -227,11 +231,14 @@ namespace libtorrent
, int block_size
, storage_constructor_type sc
, bool paused
, entry const& resume_data)
, entry const* resume_data
, int seq
, bool auto_managed)
: m_torrent_file(new torrent_info(info_hash))
, m_abort(false)
, m_paused(paused)
, m_just_paused(false)
, m_auto_managed(auto_managed)
, m_event(tracker_request::started)
, m_block_size(0)
, m_storage(0)
@ -265,7 +272,6 @@ namespace libtorrent
, m_storage_mode(storage_mode)
, m_state(torrent_status::queued_for_checking)
, m_progress(0.f)
, m_resume_data(resume_data)
, m_default_block_size(block_size)
, m_connections_initialized(false)
, m_settings(ses.settings())
@ -275,11 +281,13 @@ namespace libtorrent
, m_max_connections((std::numeric_limits<int>::max)())
, m_deficit_counter(0)
, m_policy(this)
, m_sequence_number(seq)
, m_active_time(seconds(0))
, m_seeding_time(seconds(0))
, m_total_uploaded(0)
, m_total_downloaded(0)
{
if (resume_data) m_resume_data = *resume_data;
#ifndef NDEBUG
m_files_checked = false;
#endif
@ -453,6 +461,7 @@ namespace libtorrent
}
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
m_num_pieces = 0;
auto_managed(false);
pause();
return;
}
@ -633,6 +642,7 @@ namespace libtorrent
}
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
m_num_pieces = 0;
auto_managed(false);
pause();
m_ses.done_checking(shared_from_this());
return;
@ -3264,6 +3274,42 @@ namespace libtorrent
}
}
void torrent::auto_managed(bool a)
{
INVARIANT_CHECK;
if (m_auto_managed == a) return;
m_auto_managed = a;
// recalculate which torrents should be
// paused
m_ses.m_auto_manage_time_scaler = 0;
}
float torrent::seed_cycles(session_settings const& s) const
{
if (!is_seed()) return 0.f;
int seeding = total_seconds(m_seeding_time);
int downloading = total_seconds(m_active_time) - seeding;
// if the seed time limit is set to less than 60 minutes
// use 60 minutes, to avoid oscillation
float ret = seeding / float((std::max)(s.seed_time_limit, 60 * 60));
// if it took less than 30 minutes to download, disregard the
// seed_time_ratio_limit, since it would make it oscillate too frequent
if (downloading > 30 * 60 && s.seed_time_ratio_limit >= 1.f)
ret = (std::max)(ret, (seeding / downloading
/ s.seed_time_ratio_limit));
size_type downloaded = (std::max)(m_total_downloaded, m_torrent_file->total_size());
if (downloaded > 0 && s.share_ratio_limit >= 1.f)
ret = (std::max)(ret, float(m_total_uploaded) / downloaded
/ s.share_ratio_limit);
return ret;
}
// this is an async operation triggered by the client
void torrent::save_resume_data()
{
@ -3608,6 +3654,7 @@ namespace libtorrent
st.list_peers = m_policy.num_peers();
st.list_seeds = m_policy.num_seeds();
st.connect_candidates = m_policy.num_connect_candidates();
st.seed_cycles = seed_cycles(m_ses.m_settings);
st.all_time_upload = m_total_uploaded;
st.all_time_download = m_total_downloaded;

View File

@ -265,6 +265,18 @@ namespace libtorrent
TORRENT_FORWARD(resume());
}
bool torrent_handle::is_auto_managed() const
{
INVARIANT_CHECK;
TORRENT_FORWARD_RETURN(is_auto_managed(), true);
}
void torrent_handle::auto_managed(bool m) const
{
INVARIANT_CHECK;
TORRENT_FORWARD(auto_managed(m));
}
void torrent_handle::set_tracker_login(std::string const& name
, std::string const& password) const
{