initial support for queuing
This commit is contained in:
parent
fc7dd2c5eb
commit
c043d4b21d
|
@ -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)
|
||||
|
|
373
docs/manual.html
373
docs/manual.html
|
@ -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<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();
|
||||
|
||||
|
@ -439,34 +427,46 @@ typedef storage_interface* (&storage_constructor_type)(
|
|||
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);
|
||||
</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<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;
|
||||
|
||||
|
@ -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 >=
|
||||
<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<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;
|
||||
};
|
||||
</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
|
||||
|
|
208
docs/manual.rst
208
docs/manual.rst
|
@ -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
|
||||
===========
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 = ¶ms.ti->info_hash();
|
||||
else ih = ¶ms.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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue