big change in the way storage is checked. The checker thread can now check the fastresume data of a new torrent without waiting for a currently checking one

This commit is contained in:
Arvid Norberg 2005-10-13 07:59:05 +00:00
parent 7af0fad1ba
commit 189a8756ee
13 changed files with 975 additions and 598 deletions

View File

@ -1,4 +1,6 @@
* files that are being checked will no longer stall files that don't need
checking.
* changed the way libtorrent identifies support for its excentions
to look for 'ext' at the end of the peer-id.
* improved performance by adding a circle buffer for the send buffer

View File

@ -5,7 +5,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.3.8: http://docutils.sourceforge.net/" />
<title>libtorrent manual</title>
<meta name="author" content="Arvid Norberg, c99ang&#64;cs.umu.se" />
<meta name="author" content="Arvid Norberg, arvid&#64;rasterbar.com" />
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
@ -16,143 +16,145 @@
<col class="docinfo-content" />
<tbody valign="top">
<tr><th class="docinfo-name">Author:</th>
<td>Arvid Norberg, <a class="last reference" href="mailto:c99ang&#64;cs.umu.se">c99ang&#64;cs.umu.se</a></td></tr>
<td>Arvid Norberg, <a class="last reference" href="mailto:arvid&#64;rasterbar.com">arvid&#64;rasterbar.com</a></td></tr>
</tbody>
</table>
<div class="contents topic" id="table-of-contents">
<p class="topic-title first"><a name="table-of-contents">Table of contents</a></p>
<ul class="simple">
<li><a class="reference" href="#introduction" id="id20" name="id20">introduction</a></li>
<li><a class="reference" href="#downloading-and-building" id="id21" name="id21">downloading and building</a><ul>
<li><a class="reference" href="#building-with-bbv2" id="id22" name="id22">building with BBv2</a></li>
<li><a class="reference" href="#building-with-autotools" id="id23" name="id23">building with autotools</a></li>
<li><a class="reference" href="#building-with-other-build-systems" id="id24" name="id24">Building with other build systems</a></li>
<li><a class="reference" href="#build-configurations" id="id25" name="id25">Build configurations</a></li>
<li><a class="reference" href="#introduction" id="id21" name="id21">introduction</a></li>
<li><a class="reference" href="#downloading-and-building" id="id22" name="id22">downloading and building</a><ul>
<li><a class="reference" href="#building-with-bbv2" id="id23" name="id23">building with BBv2</a></li>
<li><a class="reference" href="#building-with-autotools" id="id24" name="id24">building with autotools</a></li>
<li><a class="reference" href="#building-with-other-build-systems" id="id25" name="id25">building with other build systems</a></li>
<li><a class="reference" href="#build-configurations" id="id26" name="id26">build configurations</a></li>
</ul>
</li>
<li><a class="reference" href="#overview" id="id26" name="id26">overview</a></li>
<li><a class="reference" href="#session" id="id27" name="id27">session</a><ul>
<li><a class="reference" href="#id7" id="id28" name="id28">session()</a></li>
<li><a class="reference" href="#id8" id="id29" name="id29">~session()</a></li>
<li><a class="reference" href="#add-torrent" id="id30" name="id30">add_torrent()</a></li>
<li><a class="reference" href="#remove-torrent" id="id31" name="id31">remove_torrent()</a></li>
<li><a class="reference" href="#disable-extensions-enable-extension" id="id32" name="id32">disable_extensions() enable_extension()</a></li>
<li><a class="reference" href="#set-upload-rate-limit-set-download-rate-limit" id="id33" name="id33">set_upload_rate_limit() set_download_rate_limit()</a></li>
<li><a class="reference" href="#set-max-uploads-set-max-connections" id="id34" name="id34">set_max_uploads() set_max_connections()</a></li>
<li><a class="reference" href="#set-ip-filter" id="id35" name="id35">set_ip_filter()</a></li>
<li><a class="reference" href="#status" id="id36" name="id36">status()</a></li>
<li><a class="reference" href="#is-listening-listen-port-listen-on" id="id37" name="id37">is_listening() listen_port() listen_on()</a></li>
<li><a class="reference" href="#pop-alert-set-severity-level" id="id38" name="id38">pop_alert() set_severity_level()</a></li>
<li><a class="reference" href="#overview" id="id27" name="id27">overview</a></li>
<li><a class="reference" href="#session" id="id28" name="id28">session</a><ul>
<li><a class="reference" href="#id7" id="id29" name="id29">session()</a></li>
<li><a class="reference" href="#id8" id="id30" name="id30">~session()</a></li>
<li><a class="reference" href="#add-torrent" id="id31" name="id31">add_torrent()</a></li>
<li><a class="reference" href="#remove-torrent" id="id32" name="id32">remove_torrent()</a></li>
<li><a class="reference" href="#disable-extensions-enable-extension" id="id33" name="id33">disable_extensions() enable_extension()</a></li>
<li><a class="reference" href="#set-upload-rate-limit-set-download-rate-limit" id="id34" name="id34">set_upload_rate_limit() set_download_rate_limit()</a></li>
<li><a class="reference" href="#set-max-uploads-set-max-connections" id="id35" name="id35">set_max_uploads() set_max_connections()</a></li>
<li><a class="reference" href="#set-ip-filter" id="id36" name="id36">set_ip_filter()</a></li>
<li><a class="reference" href="#status" id="id37" name="id37">status()</a></li>
<li><a class="reference" href="#is-listening-listen-port-listen-on" id="id38" name="id38">is_listening() listen_port() listen_on()</a></li>
<li><a class="reference" href="#pop-alert-set-severity-level" id="id39" name="id39">pop_alert() set_severity_level()</a></li>
</ul>
</li>
<li><a class="reference" href="#entry" id="id39" name="id39">entry</a><ul>
<li><a class="reference" href="#integer-string-list-dict-type" id="id40" name="id40">integer() string() list() dict() type()</a></li>
<li><a class="reference" href="#entry" id="id40" name="id40">entry</a><ul>
<li><a class="reference" href="#integer-string-list-dict-type" id="id41" name="id41">integer() string() list() dict() type()</a></li>
<li><a class="reference" href="#operator" id="id42" name="id42">operator[]</a></li>
<li><a class="reference" href="#find-key" id="id43" name="id43">find_key()</a></li>
</ul>
</li>
<li><a class="reference" href="#torrent-info" id="id41" name="id41">torrent_info</a><ul>
<li><a class="reference" href="#id9" id="id42" name="id42">torrent_info()</a></li>
<li><a class="reference" href="#set-comment-set-piece-size-set-creator-set-hash-add-tracker-add-file" id="id43" name="id43">set_comment() set_piece_size() set_creator() set_hash() add_tracker() add_file()</a></li>
<li><a class="reference" href="#create-torrent" id="id44" name="id44">create_torrent()</a></li>
<li><a class="reference" href="#begin-files-end-files-rbegin-files-rend-files" id="id45" name="id45">begin_files() end_files() rbegin_files() rend_files()</a></li>
<li><a class="reference" href="#num-files-file-at" id="id46" name="id46">num_files() file_at()</a></li>
<li><a class="reference" href="#print" id="id47" name="id47">print()</a></li>
<li><a class="reference" href="#trackers" id="id48" name="id48">trackers()</a></li>
<li><a class="reference" href="#total-size-piece-length-piece-size-num-pieces" id="id49" name="id49">total_size() piece_length() piece_size() num_pieces()</a></li>
<li><a class="reference" href="#hash-for-piece-info-hash" id="id50" name="id50">hash_for_piece() info_hash()</a></li>
<li><a class="reference" href="#name-comment-creation-date-creator" id="id51" name="id51">name() comment() creation_date() creator()</a></li>
<li><a class="reference" href="#torrent-info" id="id44" name="id44">torrent_info</a><ul>
<li><a class="reference" href="#id9" id="id45" name="id45">torrent_info()</a></li>
<li><a class="reference" href="#set-comment-set-piece-size-set-creator-set-hash-add-tracker-add-file" id="id46" name="id46">set_comment() set_piece_size() set_creator() set_hash() add_tracker() add_file()</a></li>
<li><a class="reference" href="#create-torrent" id="id47" name="id47">create_torrent()</a></li>
<li><a class="reference" href="#begin-files-end-files-rbegin-files-rend-files" id="id48" name="id48">begin_files() end_files() rbegin_files() rend_files()</a></li>
<li><a class="reference" href="#num-files-file-at" id="id49" name="id49">num_files() file_at()</a></li>
<li><a class="reference" href="#print" id="id50" name="id50">print()</a></li>
<li><a class="reference" href="#trackers" id="id51" name="id51">trackers()</a></li>
<li><a class="reference" href="#total-size-piece-length-piece-size-num-pieces" id="id52" name="id52">total_size() piece_length() piece_size() num_pieces()</a></li>
<li><a class="reference" href="#hash-for-piece-info-hash" id="id53" name="id53">hash_for_piece() info_hash()</a></li>
<li><a class="reference" href="#name-comment-creation-date-creator" id="id54" name="id54">name() comment() creation_date() creator()</a></li>
</ul>
</li>
<li><a class="reference" href="#torrent-handle" id="id52" name="id52">torrent_handle</a><ul>
<li><a class="reference" href="#save-path" id="id53" name="id53">save_path()</a></li>
<li><a class="reference" href="#move-storage" id="id54" name="id54">move_storage()</a></li>
<li><a class="reference" href="#force-reannounce" id="id55" name="id55">force_reannounce()</a></li>
<li><a class="reference" href="#connect-peer" id="id56" name="id56">connect_peer()</a></li>
<li><a class="reference" href="#set-ratio" id="id57" name="id57">set_ratio()</a></li>
<li><a class="reference" href="#set-upload-limit-set-download-limit" id="id58" name="id58">set_upload_limit() set_download_limit()</a></li>
<li><a class="reference" href="#pause-resume-is-paused" id="id59" name="id59">pause() resume() is_paused()</a></li>
<li><a class="reference" href="#is-seed" id="id60" name="id60">is_seed()</a></li>
<li><a class="reference" href="#has-metadata" id="id61" name="id61">has_metadata()</a></li>
<li><a class="reference" href="#set-tracker-login" id="id62" name="id62">set_tracker_login()</a></li>
<li><a class="reference" href="#trackers-replace-trackers" id="id63" name="id63">trackers() replace_trackers()</a></li>
<li><a class="reference" href="#use-interface" id="id64" name="id64">use_interface()</a></li>
<li><a class="reference" href="#info-hash" id="id65" name="id65">info_hash()</a></li>
<li><a class="reference" href="#id11" id="id66" name="id66">set_max_uploads() set_max_connections()</a></li>
<li><a class="reference" href="#write-resume-data" id="id67" name="id67">write_resume_data()</a></li>
<li><a class="reference" href="#metadata" id="id68" name="id68">metadata()</a></li>
<li><a class="reference" href="#id12" id="id69" name="id69">status()</a></li>
<li><a class="reference" href="#get-download-queue" id="id70" name="id70">get_download_queue()</a></li>
<li><a class="reference" href="#get-peer-info" id="id71" name="id71">get_peer_info()</a></li>
<li><a class="reference" href="#get-torrent-info" id="id72" name="id72">get_torrent_info()</a></li>
<li><a class="reference" href="#is-valid" id="id73" name="id73">is_valid()</a></li>
<li><a class="reference" href="#torrent-handle" id="id55" name="id55">torrent_handle</a><ul>
<li><a class="reference" href="#save-path" id="id56" name="id56">save_path()</a></li>
<li><a class="reference" href="#move-storage" id="id57" name="id57">move_storage()</a></li>
<li><a class="reference" href="#force-reannounce" id="id58" name="id58">force_reannounce()</a></li>
<li><a class="reference" href="#connect-peer" id="id59" name="id59">connect_peer()</a></li>
<li><a class="reference" href="#set-ratio" id="id60" name="id60">set_ratio()</a></li>
<li><a class="reference" href="#set-upload-limit-set-download-limit" id="id61" name="id61">set_upload_limit() set_download_limit()</a></li>
<li><a class="reference" href="#pause-resume-is-paused" id="id62" name="id62">pause() resume() is_paused()</a></li>
<li><a class="reference" href="#is-seed" id="id63" name="id63">is_seed()</a></li>
<li><a class="reference" href="#has-metadata" id="id64" name="id64">has_metadata()</a></li>
<li><a class="reference" href="#set-tracker-login" id="id65" name="id65">set_tracker_login()</a></li>
<li><a class="reference" href="#trackers-replace-trackers" id="id66" name="id66">trackers() replace_trackers()</a></li>
<li><a class="reference" href="#use-interface" id="id67" name="id67">use_interface()</a></li>
<li><a class="reference" href="#info-hash" id="id68" name="id68">info_hash()</a></li>
<li><a class="reference" href="#id11" id="id69" name="id69">set_max_uploads() set_max_connections()</a></li>
<li><a class="reference" href="#write-resume-data" id="id70" name="id70">write_resume_data()</a></li>
<li><a class="reference" href="#metadata" id="id71" name="id71">metadata()</a></li>
<li><a class="reference" href="#id12" id="id72" name="id72">status()</a></li>
<li><a class="reference" href="#get-download-queue" id="id73" name="id73">get_download_queue()</a></li>
<li><a class="reference" href="#get-peer-info" id="id74" name="id74">get_peer_info()</a></li>
<li><a class="reference" href="#get-torrent-info" id="id75" name="id75">get_torrent_info()</a></li>
<li><a class="reference" href="#is-valid" id="id76" name="id76">is_valid()</a></li>
</ul>
</li>
<li><a class="reference" href="#torrent-status" id="id74" name="id74">torrent_status</a></li>
<li><a class="reference" href="#peer-info" id="id75" name="id75">peer_info</a></li>
<li><a class="reference" href="#address" id="id76" name="id76">address</a></li>
<li><a class="reference" href="#http-settings" id="id77" name="id77">http_settings</a></li>
<li><a class="reference" href="#ip-filter" id="id78" name="id78">ip_filter</a><ul>
<li><a class="reference" href="#id14" id="id79" name="id79">ip_filter()</a></li>
<li><a class="reference" href="#add-rule" id="id80" name="id80">add_rule()</a></li>
<li><a class="reference" href="#access" id="id81" name="id81">access()</a></li>
<li><a class="reference" href="#export-filter" id="id82" name="id82">export_filter()</a></li>
<li><a class="reference" href="#torrent-status" id="id77" name="id77">torrent_status</a></li>
<li><a class="reference" href="#peer-info" id="id78" name="id78">peer_info</a></li>
<li><a class="reference" href="#address" id="id79" name="id79">address</a></li>
<li><a class="reference" href="#http-settings" id="id80" name="id80">http_settings</a></li>
<li><a class="reference" href="#ip-filter" id="id81" name="id81">ip_filter</a><ul>
<li><a class="reference" href="#id14" id="id82" name="id82">ip_filter()</a></li>
<li><a class="reference" href="#add-rule" id="id83" name="id83">add_rule()</a></li>
<li><a class="reference" href="#access" id="id84" name="id84">access()</a></li>
<li><a class="reference" href="#export-filter" id="id85" name="id85">export_filter()</a></li>
</ul>
</li>
<li><a class="reference" href="#big-number" id="id83" name="id83">big_number</a></li>
<li><a class="reference" href="#hasher" id="id84" name="id84">hasher</a></li>
<li><a class="reference" href="#fingerprint" id="id85" name="id85">fingerprint</a></li>
<li><a class="reference" href="#free-functions" id="id86" name="id86">free functions</a><ul>
<li><a class="reference" href="#identify-client" id="id87" name="id87">identify_client()</a></li>
<li><a class="reference" href="#bdecode-bencode" id="id88" name="id88">bdecode() bencode()</a></li>
<li><a class="reference" href="#big-number" id="id86" name="id86">big_number</a></li>
<li><a class="reference" href="#hasher" id="id87" name="id87">hasher</a></li>
<li><a class="reference" href="#fingerprint" id="id88" name="id88">fingerprint</a></li>
<li><a class="reference" href="#free-functions" id="id89" name="id89">free functions</a><ul>
<li><a class="reference" href="#identify-client" id="id90" name="id90">identify_client()</a></li>
<li><a class="reference" href="#bdecode-bencode" id="id91" name="id91">bdecode() bencode()</a></li>
</ul>
</li>
<li><a class="reference" href="#alerts" id="id89" name="id89">alerts</a><ul>
<li><a class="reference" href="#listen-failed-alert" id="id90" name="id90">listen_failed_alert</a></li>
<li><a class="reference" href="#file-error-alert" id="id91" name="id91">file_error_alert</a></li>
<li><a class="reference" href="#tracker-announce-alert" id="id92" name="id92">tracker_announce_alert</a></li>
<li><a class="reference" href="#tracker-alert" id="id93" name="id93">tracker_alert</a></li>
<li><a class="reference" href="#tracker-reply-alert" id="id94" name="id94">tracker_reply_alert</a></li>
<li><a class="reference" href="#tracker-warning-alert" id="id95" name="id95">tracker_warning_alert</a></li>
<li><a class="reference" href="#hash-failed-alert" id="id96" name="id96">hash_failed_alert</a></li>
<li><a class="reference" href="#peer-ban-alert" id="id97" name="id97">peer_ban_alert</a></li>
<li><a class="reference" href="#peer-error-alert" id="id98" name="id98">peer_error_alert</a></li>
<li><a class="reference" href="#invalid-request-alert" id="id99" name="id99">invalid_request_alert</a></li>
<li><a class="reference" href="#torrent-finished-alert" id="id100" name="id100">torrent_finished_alert</a></li>
<li><a class="reference" href="#metadata-received-alert" id="id101" name="id101">metadata_received_alert</a></li>
<li><a class="reference" href="#fastresume-rejected-alert" id="id102" name="id102">fastresume_rejected_alert</a></li>
<li><a class="reference" href="#dispatcher" id="id103" name="id103">dispatcher</a></li>
<li><a class="reference" href="#alerts" id="id92" name="id92">alerts</a><ul>
<li><a class="reference" href="#listen-failed-alert" id="id93" name="id93">listen_failed_alert</a></li>
<li><a class="reference" href="#file-error-alert" id="id94" name="id94">file_error_alert</a></li>
<li><a class="reference" href="#tracker-announce-alert" id="id95" name="id95">tracker_announce_alert</a></li>
<li><a class="reference" href="#tracker-alert" id="id96" name="id96">tracker_alert</a></li>
<li><a class="reference" href="#tracker-reply-alert" id="id97" name="id97">tracker_reply_alert</a></li>
<li><a class="reference" href="#tracker-warning-alert" id="id98" name="id98">tracker_warning_alert</a></li>
<li><a class="reference" href="#hash-failed-alert" id="id99" name="id99">hash_failed_alert</a></li>
<li><a class="reference" href="#peer-ban-alert" id="id100" name="id100">peer_ban_alert</a></li>
<li><a class="reference" href="#peer-error-alert" id="id101" name="id101">peer_error_alert</a></li>
<li><a class="reference" href="#invalid-request-alert" id="id102" name="id102">invalid_request_alert</a></li>
<li><a class="reference" href="#torrent-finished-alert" id="id103" name="id103">torrent_finished_alert</a></li>
<li><a class="reference" href="#metadata-received-alert" id="id104" name="id104">metadata_received_alert</a></li>
<li><a class="reference" href="#fastresume-rejected-alert" id="id105" name="id105">fastresume_rejected_alert</a></li>
<li><a class="reference" href="#dispatcher" id="id106" name="id106">dispatcher</a></li>
</ul>
</li>
<li><a class="reference" href="#exceptions" id="id104" name="id104">exceptions</a><ul>
<li><a class="reference" href="#invalid-handle" id="id105" name="id105">invalid_handle</a></li>
<li><a class="reference" href="#duplicate-torrent" id="id106" name="id106">duplicate_torrent</a></li>
<li><a class="reference" href="#invalid-encoding" id="id107" name="id107">invalid_encoding</a></li>
<li><a class="reference" href="#type-error" id="id108" name="id108">type_error</a></li>
<li><a class="reference" href="#invalid-torrent-file" id="id109" name="id109">invalid_torrent_file</a></li>
<li><a class="reference" href="#exceptions" id="id107" name="id107">exceptions</a><ul>
<li><a class="reference" href="#invalid-handle" id="id108" name="id108">invalid_handle</a></li>
<li><a class="reference" href="#duplicate-torrent" id="id109" name="id109">duplicate_torrent</a></li>
<li><a class="reference" href="#invalid-encoding" id="id110" name="id110">invalid_encoding</a></li>
<li><a class="reference" href="#type-error" id="id111" name="id111">type_error</a></li>
<li><a class="reference" href="#invalid-torrent-file" id="id112" name="id112">invalid_torrent_file</a></li>
</ul>
</li>
<li><a class="reference" href="#examples" id="id110" name="id110">examples</a><ul>
<li><a class="reference" href="#dump-torrent" id="id111" name="id111">dump_torrent</a></li>
<li><a class="reference" href="#simple-client" id="id112" name="id112">simple client</a></li>
<li><a class="reference" href="#make-torrent" id="id113" name="id113">make_torrent</a></li>
<li><a class="reference" href="#examples" id="id113" name="id113">examples</a><ul>
<li><a class="reference" href="#dump-torrent" id="id114" name="id114">dump_torrent</a></li>
<li><a class="reference" href="#simple-client" id="id115" name="id115">simple client</a></li>
<li><a class="reference" href="#make-torrent" id="id116" name="id116">make_torrent</a></li>
</ul>
</li>
<li><a class="reference" href="#fast-resume" id="id114" name="id114">fast resume</a><ul>
<li><a class="reference" href="#file-format" id="id115" name="id115">file format</a></li>
<li><a class="reference" href="#fast-resume" id="id117" name="id117">fast resume</a><ul>
<li><a class="reference" href="#file-format" id="id118" name="id118">file format</a></li>
</ul>
</li>
<li><a class="reference" href="#threads" id="id116" name="id116">threads</a></li>
<li><a class="reference" href="#storage-allocation" id="id117" name="id117">storage allocation</a><ul>
<li><a class="reference" href="#full-allocation" id="id118" name="id118">full allocation</a></li>
<li><a class="reference" href="#compact-allocation" id="id119" name="id119">compact allocation</a></li>
<li><a class="reference" href="#threads" id="id119" name="id119">threads</a></li>
<li><a class="reference" href="#storage-allocation" id="id120" name="id120">storage allocation</a><ul>
<li><a class="reference" href="#full-allocation" id="id121" name="id121">full allocation</a></li>
<li><a class="reference" href="#compact-allocation" id="id122" name="id122">compact allocation</a></li>
</ul>
</li>
<li><a class="reference" href="#extensions" id="id120" name="id120">extensions</a><ul>
<li><a class="reference" href="#chat-messages" id="id121" name="id121">chat messages</a></li>
<li><a class="reference" href="#metadata-from-peers" id="id122" name="id122">metadata from peers</a></li>
<li><a class="reference" href="#extensions" id="id123" name="id123">extensions</a><ul>
<li><a class="reference" href="#chat-messages" id="id124" name="id124">chat messages</a></li>
<li><a class="reference" href="#metadata-from-peers" id="id125" name="id125">metadata from peers</a></li>
</ul>
</li>
<li><a class="reference" href="#filename-checks" id="id123" name="id123">filename checks</a></li>
<li><a class="reference" href="#acknowledgements" id="id124" name="id124">acknowledgements</a></li>
<li><a class="reference" href="#filename-checks" id="id126" name="id126">filename checks</a></li>
<li><a class="reference" href="#acknowledgements" id="id127" name="id127">acknowledgements</a></li>
</ul>
</div>
<div class="section" id="introduction">
@ -227,7 +229,7 @@ Boost.Filesystem, Boost.Date_time and various other boost libraries as well as z
<p>Fails on:</p>
<blockquote>
<ul class="simple">
<li>GCC 2.95.4 (<tt class="docutils literal"><span class="pre">std::ios_base</span></tt> is missing)</li>
<li>GCC 2.95.4</li>
<li>msvc6 sp5</li>
</ul>
</blockquote>
@ -400,11 +402,30 @@ checking for main in -lboost_thread... yes
directory contains spaces. Make sure you either rename the directories with
spaces in their names to remove the spaces or move the libtorrent directory.</p>
</div>
<div class="section" id="creating-a-debug-build">
<h3><a name="creating-a-debug-build">Creating a debug build</a></h3>
<p>To tell configure to build a debug version (with debug info, asserts
and invariant checks enabled), you have to run the configure script
with the following option:</p>
<pre class="literal-block">
./configure --enable-debug=yes
</pre>
</div>
<div class="section" id="creating-a-release-build">
<h3><a name="creating-a-release-build">Creating a release build</a></h3>
<p>To tell the configure to build a release version (without debug info,
asserts and invariant checks), you have to run the configure script
with the following option:</p>
<pre class="literal-block">
./configure --enable-debug=no
</pre>
<p>The above option make use of -DNDEBUG, which is used throughout libtorrent.</p>
</div>
<div class="section" id="step-2-building-libtorrent">
<h3><a name="step-2-building-libtorrent">Step 2: Building libtorrent</a></h3>
<p>Once the configure script is run successfully, you just type <tt class="docutils literal"><span class="pre">make</span></tt> and
libtorrent, the examples and the tests will be built.</p>
<p>When libtorrent is built it may be a good idea to run the test, you do this
<p>When libtorrent is built it may be a good idea to run the tests, you do this
my running <tt class="docutils literal"><span class="pre">make</span> <span class="pre">check</span></tt>.</p>
<p>If you want to build a release version (without debug info, asserts and
invariant checks), you have to rerun the configure script and rebuild, like this:</p>
@ -416,7 +437,7 @@ make
</div>
</div>
<div class="section" id="building-with-other-build-systems">
<h2><a name="building-with-other-build-systems">Building with other build systems</a></h2>
<h2><a name="building-with-other-build-systems">building with other build systems</a></h2>
<p>If you're making your own project file, note that there are two versions of
the file abstraction. There's one <tt class="docutils literal"><span class="pre">file_win.cpp</span></tt> which relies on windows
file API that supports files larger than 2 Gigabytes. This does not work in
@ -431,7 +452,7 @@ options &quot;force conformance in for loop scope&quot;, &quot;treat wchar_t as
type&quot; and &quot;Enable Run-Time Type Info&quot; to Yes.</p>
</div>
<div class="section" id="build-configurations">
<h2><a name="build-configurations">Build configurations</a></h2>
<h2><a name="build-configurations">build configurations</a></h2>
<p>By default libtorrent is built In debug mode, and will have pretty expensive
invariant checks and asserts built into it. If you want to disable such checks
(you want to do that in a release build) you can see the table below for which
@ -474,10 +495,21 @@ UTF-8 strings in pathnames are converted into
UTF-16 before they are passed to the file
operations.</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">LITTLE_ENDIAN</span></tt></td>
<td>This will use the little endian version of the
sha-1 code. If defined on a big-endian system
the sha-1 hashes will be incorrect and fail.
If it is not defined and <tt class="docutils literal"><span class="pre">__BIG_ENDIAN__</span></tt>
isn't defined either (it is defined by Apple's
GCC) both little-endian and big-endian versions
will be built and the correct code will be
chosen at run-time.</td>
</tr>
</tbody>
</table>
<p>If you experience that libtorrent uses unreasonable amounts of cpu, it will definately help to
define <tt class="docutils literal"><span class="pre">NDEBUG</span></tt>, since it will remove the invariant checks within the library.</p>
<p>If you experience that libtorrent uses unreasonable amounts of cpu, it will
definately help to define <tt class="docutils literal"><span class="pre">NDEBUG</span></tt>, since it will remove the invariant checks
within the library.</p>
</div>
</div>
<div class="section" id="overview">
@ -514,7 +546,8 @@ the <tt class="docutils literal"><span class="pre">session</span></tt>, it conta
class session: public boost::noncopyable
{
session(const fingerprint&amp; print = libtorrent::fingerprint(&quot;LT&quot;, 0, 1, 0, 0));
session(const fingerprint&amp; print
= libtorrent::fingerprint(&quot;LT&quot;, 0, 1, 0, 0));
session(
const fingerprint&amp; print
@ -888,18 +921,64 @@ can assign the value you want it to have.</p>
entry torrent_file;
// ...
// throws if this is not a dictionary
entry::dictionary_type const&amp; dict = torrent_file.dict();
entry::dictionary_type::const_iterator i;
i = dict.find(&quot;announce&quot;);
if (i != dict.end())
{
std::string tracker_url= i-&gt;second.string();
std::string tracker_url = i-&gt;second.string();
std::cout &lt;&lt; tracker_url &lt;&lt; &quot;\n&quot;;
}
</pre>
<p>To make it easier to extract information from a torren file, the class <tt class="docutils literal"><span class="pre">torrent_info</span></tt>
<p>The following code is equivalent, but a little bit shorter:</p>
<pre class="literal-block">
entry torrent_file;
// ...
// throws if this is not a dictionary
if (entry* i = torrent_file.find_key(&quot;announce&quot;))
{
std::string tracker_url = i-&gt;string();
std::cout &lt;&lt; tracker_url &lt;&lt; &quot;\n&quot;;
}
</pre>
<p>To make it easier to extract information from a torrent file, the class <a class="reference" href="#torrent-info">torrent_info</a>
exists.</p>
</div>
<div class="section" id="operator">
<h2><a name="operator">operator[]</a></h2>
<blockquote>
<pre class="literal-block">
entry&amp; operator[](char const* key);
entry&amp; operator[](std::string const&amp; key);
entry const&amp; operator[](char const* key) const;
entry const&amp; operator[](std::string const&amp; key) const;
</pre>
</blockquote>
<p>All of these functions requires the entry to be a dictionary, if it isn't they
will throw <tt class="docutils literal"><span class="pre">libtorrent::type_error</span></tt>.</p>
<p>The non-const versions of the <tt class="docutils literal"><span class="pre">operator[]</span></tt> will return a reference to either
the existing element at the given key or, if there is no element with the
given key, a reference to a newly inserted element at that key.</p>
<p>The const version of <tt class="docutils literal"><span class="pre">operator[]</span></tt> will only return a reference to an
existing element at the given key. If the key is not found, it will throw
<tt class="docutils literal"><span class="pre">libtorrent::type_error</span></tt>.</p>
</div>
<div class="section" id="find-key">
<h2><a name="find-key">find_key()</a></h2>
<blockquote>
<pre class="literal-block">
entry* find_key(char const* key);
entry const* find_key(char const* key) const;
</pre>
</blockquote>
<p>These functions requires the entry to be a dictionary, if it isn't they
will throw <tt class="docutils literal"><span class="pre">libtorrent::type_error</span></tt>.</p>
<p>They will look for an element at the given key in the dictionary, if the
element cannot be found, they will return 0. If an element with the given
key is found, the return a pointer to it.</p>
</div>
</div>
<div class="section" id="torrent-info">
<h1><a name="torrent-info">torrent_info</a></h1>
@ -922,7 +1001,8 @@ public:
void add_file(boost::filesystem::path file, size_type size);
typedef std::vector&lt;file_entry&gt;::const_iterator file_iterator;
typedef std::vector&lt;file_entry&gt;::const_reverse_iterator reverse_file_iterator;
typedef std::vector&lt;file_entry&gt;::const_reverse_iterator
reverse_file_iterator;
file_iterator begin_files() const;
file_iterator end_files() const;
@ -990,12 +1070,12 @@ void add_file(boost::filesystem::path file, size_type size);
</blockquote>
<p>These files are used when creating a torrent file. <tt class="docutils literal"><span class="pre">set_comment()</span></tt> will simply set
the comment that belongs to this torrent. The comment can be retrieved with the
<tt class="docutils literal"><span class="pre">comment()</span></tt> member.</p>
<tt class="docutils literal"><span class="pre">comment()</span></tt> member. The string should be UTF-8 encoded.</p>
<p><tt class="docutils literal"><span class="pre">set_piece_size()</span></tt> will set the size of each piece in this torrent. The piece size must
be an even multiple of 2. i.e. usually something like 256 kiB, 512 kiB, 1024 kiB etc. The
size is given in number of bytes.</p>
<p><tt class="docutils literal"><span class="pre">set_creator()</span></tt> is an optional attribute that can be used to identify your application
that was used to create the torrent file.</p>
that was used to create the torrent file. The string should be UTF-8 encoded.</p>
<p><tt class="docutils literal"><span class="pre">set_hash()</span></tt> writes the hash for the piece with the given piece-index. You have to call
this function for every piece in the torrent. Usually the <a class="reference" href="#hasher">hasher</a> is used to calculate
the sha1-hash for a piece.</p>
@ -1037,7 +1117,8 @@ in the torrent, you can use <tt class="docutils literal"><span class="pre">begin
<tt class="docutils literal"><span class="pre">rbegin_files()</span></tt> and <tt class="docutils literal"><span class="pre">rend_files()</span></tt>. These will give you standard vector
iterators with the type <tt class="docutils literal"><span class="pre">file_entry</span></tt>.</p>
<p>The <tt class="docutils literal"><span class="pre">path</span></tt> is the full (relative) path of each file. i.e. if it is a multi-file
torrent, all the files starts with a directory with the same name as <tt class="docutils literal"><span class="pre">torrent_info::name()</span></tt>.</p>
torrent, all the files starts with a directory with the same name as <tt class="docutils literal"><span class="pre">torrent_info::name()</span></tt>.
The filenames are encoded with UTF-8.</p>
<pre class="literal-block">
struct file_entry
{
@ -1131,6 +1212,7 @@ boost::optional&lt;boost::posix_time::ptime&gt; creation_date() const;
it will return an empty string. <tt class="docutils literal"><span class="pre">creation_date()</span></tt> returns a <a class="reference" href="http://www.boost.org/libs/date_time/doc/class_ptime.html">boost::posix_time::ptime</a>
object, representing the time when this torrent file was created. If there's no timestamp
in the torrent file, this will return a date of january 1:st 1970.</p>
<p>Both the name and the comment is UTF-8 encoded strings.</p>
<p><tt class="docutils literal"><span class="pre">creator()</span></tt> returns the creator string in the torrent. If there is no creator string
it will return an empty string.</p>
</div>
@ -1156,7 +1238,8 @@ struct torrent_handle
void force_reannounce();
void connect_peer(address const&amp; adr) const;
void set_tracker_login(std::string const&amp; username, std::string const&amp; password);
void set_tracker_login(std::string const&amp; username
, std::string const&amp; password);
std::vector&lt;announce_entry&gt; const&amp; trackers() const;
void replace_trackers(std::vector&lt;announce_entry&gt; const&amp;);
@ -1960,7 +2043,8 @@ to encode this information into the client's peer id.</p>
<pre class="literal-block">
struct fingerprint
{
fingerprint(const char* id_string, int major, int minor, int revision, int tag);
fingerprint(const char* id_string, int major, int minor
, int revision, int tag);
std::string to_string() const;
@ -2009,6 +2093,7 @@ sure not to clash with anybody else. Here are some taken id's:</p>
</tr>
</tbody>
</table>
<p>There's currently an informal directory of client id's <a class="reference" href="http://wiki.theory.org/BitTorrentSpecification#peer_id">here</a>.</p>
<p>The <tt class="docutils literal"><span class="pre">major</span></tt>, <tt class="docutils literal"><span class="pre">minor</span></tt>, <tt class="docutils literal"><span class="pre">revision</span></tt> and <tt class="docutils literal"><span class="pre">tag</span></tt> parameters are used to identify the
version of your client. All these numbers must be within the range [0, 9].</p>
<p><tt class="docutils literal"><span class="pre">to_string()</span></tt> will generate the actual string put in the peer-id, and return it.</p>
@ -2514,14 +2599,15 @@ int main(int argc, char* argv[])
{
std::ifstream in(argv[1], std::ios_base::binary);
in.unsetf(std::ios_base::skipws);
entry e = bdecode(std::istream_iterator&lt;char&gt;(in), std::istream_iterator&lt;char&gt;());
entry e = bdecode(std::istream_iterator&lt;char&gt;(in)
, std::istream_iterator&lt;char&gt;());
torrent_info t(e);
// print info about torrent
std::cout &lt;&lt; &quot;\n\n----- torrent file info -----\n\n&quot;;
std::cout &lt;&lt; &quot;trackers:\n&quot;;
for (std::vector&lt;announce_entry&gt;::const_iterator i = t.trackers().begin();
i != t.trackers().end(); ++i)
for (std::vector&lt;announce_entry&gt;::const_iterator i
= t.trackers().begin(), end(t.trackers().end); i != end; ++i)
{
std::cout &lt;&lt; i-&gt;tier &lt;&lt; &quot;: &quot; &lt;&lt; i-&gt;url &lt;&lt; &quot;\n&quot;;
}
@ -2530,8 +2616,7 @@ int main(int argc, char* argv[])
std::cout &lt;&lt; &quot;piece length: &quot; &lt;&lt; t.piece_length() &lt;&lt; &quot;\n&quot;;
std::cout &lt;&lt; &quot;files:\n&quot;;
for (torrent_info::file_iterator i = t.begin_files();
i != t.end_files();
++i)
i != t.end_files(); ++i)
{
std::cout &lt;&lt; &quot; &quot; &lt;&lt; std::setw(11) &lt;&lt; i-&gt;size
&lt;&lt; &quot; &quot; &lt;&lt; i-&gt;path &lt;&lt; &quot; &quot; &lt;&lt; i-&gt;filename &lt;&lt; &quot;\n&quot;;
@ -2582,7 +2667,8 @@ int main(int argc, char* argv[])
std::ifstream in(argv[1], std::ios_base::binary);
in.unsetf(std::ios_base::skipws);
entry e = bdecode(std::istream_iterator&lt;char&gt;(in), std::istream_iterator&lt;char&gt;());
entry e = bdecode(std::istream_iterator&lt;char&gt;(in)
, std::istream_iterator&lt;char&gt;());
s.add_torrent(e, &quot;&quot;);
// wait for the user to end
@ -2621,10 +2707,7 @@ int main(int argc, char* argv[])
using namespace boost::filesystem;
using namespace libtorrent;
void add_files(
torrent_info&amp; t
, path const&amp; p
, path const&amp; l)
void add_files(torrent_info&amp; t, path const&amp; p, path const&amp; l)
{
path f(p / l);
if (is_directory(f))
@ -2649,8 +2732,8 @@ int main(int argc, char* argv[])
if (argc != 4)
{
std::cerr &lt;&lt; &quot;usage: make_torrent &lt;output torrent-file&gt; &lt;announce url&gt; &quot;
&quot;&lt;file or directory to create torrent from&gt;\n&quot;;
std::cerr &lt;&lt; &quot;usage: make_torrent &lt;output torrent-file&gt; &quot;
&quot;&lt;announce url&gt; &lt;file or directory to create torrent from&gt;\n&quot;;
return 1;
}

View File

@ -2,7 +2,7 @@
libtorrent manual
=================
:Author: Arvid Norberg, c99ang@cs.umu.se
:Author: Arvid Norberg, arvid@rasterbar.com
.. contents:: Table of contents
:depth: 2
@ -82,7 +82,7 @@ libtorrent has been successfully compiled and tested on:
Fails on:
* GCC 2.95.4 (``std::ios_base`` is missing)
* GCC 2.95.4
* msvc6 sp5
libtorrent is released under the BSD-license_.
@ -318,7 +318,15 @@ libtorrent, the examples and the tests will be built.
When libtorrent is built it may be a good idea to run the tests, you do this
my running ``make check``.
Building with other build systems
If you want to build a release version (without debug info, asserts and
invariant checks), you have to rerun the configure script and rebuild, like this::
./configure --disable-debug
make clean
make
building with other build systems
---------------------------------
If you're making your own project file, note that there are two versions of
@ -336,7 +344,7 @@ options "force conformance in for loop scope", "treat wchar_t as built-in
type" and "Enable Run-Time Type Info" to Yes.
Build configurations
build configurations
--------------------
By default libtorrent is built In debug mode, and will have pretty expensive
@ -369,10 +377,20 @@ defines you can use to control the build.
| | UTF-16 before they are passed to the file |
| | operations. |
+--------------------------------+-------------------------------------------------+
| ``LITTLE_ENDIAN`` | This will use the little endian version of the |
| | sha-1 code. If defined on a big-endian system |
| | the sha-1 hashes will be incorrect and fail. |
| | If it is not defined and ``__BIG_ENDIAN__`` |
| | isn't defined either (it is defined by Apple's |
| | GCC) both little-endian and big-endian versions |
| | will be built and the correct code will be |
| | chosen at run-time. |
+--------------------------------+-------------------------------------------------+
If you experience that libtorrent uses unreasonable amounts of cpu, it will definately help to
define ``NDEBUG``, since it will remove the invariant checks within the library.
If you experience that libtorrent uses unreasonable amounts of cpu, it will
definately help to define ``NDEBUG``, since it will remove the invariant checks
within the library.
overview
========
@ -406,7 +424,8 @@ The ``session`` class has the following synopsis::
class session: public boost::noncopyable
{
session(const fingerprint& print = libtorrent::fingerprint("LT", 0, 1, 0, 0));
session(const fingerprint& print
= libtorrent::fingerprint("LT", 0, 1, 0, 0));
session(
const fingerprint& print
@ -808,19 +827,71 @@ The typical code to get info from a torrent file will then look like this::
entry torrent_file;
// ...
// throws if this is not a dictionary
entry::dictionary_type const& dict = torrent_file.dict();
entry::dictionary_type::const_iterator i;
i = dict.find("announce");
if (i != dict.end())
{
std::string tracker_url= i->second.string();
std::string tracker_url = i->second.string();
std::cout << tracker_url << "\n";
}
To make it easier to extract information from a torren file, the class ``torrent_info``
The following code is equivalent, but a little bit shorter::
entry torrent_file;
// ...
// throws if this is not a dictionary
if (entry* i = torrent_file.find_key("announce"))
{
std::string tracker_url = i->string();
std::cout << tracker_url << "\n";
}
To make it easier to extract information from a torrent file, the class torrent_info_
exists.
operator[]
----------
::
entry& operator[](char const* key);
entry& operator[](std::string const& key);
entry const& operator[](char const* key) const;
entry const& operator[](std::string const& key) const;
All of these functions requires the entry to be a dictionary, if it isn't they
will throw ``libtorrent::type_error``.
The non-const versions of the ``operator[]`` will return a reference to either
the existing element at the given key or, if there is no element with the
given key, a reference to a newly inserted element at that key.
The const version of ``operator[]`` will only return a reference to an
existing element at the given key. If the key is not found, it will throw
``libtorrent::type_error``.
find_key()
----------
::
entry* find_key(char const* key);
entry const* find_key(char const* key) const;
These functions requires the entry to be a dictionary, if it isn't they
will throw ``libtorrent::type_error``.
They will look for an element at the given key in the dictionary, if the
element cannot be found, they will return 0. If an element with the given
key is found, the return a pointer to it.
torrent_info
============
@ -844,7 +915,8 @@ The ``torrent_info`` has the following synopsis::
void add_file(boost::filesystem::path file, size_type size);
typedef std::vector<file_entry>::const_iterator file_iterator;
typedef std::vector<file_entry>::const_reverse_iterator reverse_file_iterator;
typedef std::vector<file_entry>::const_reverse_iterator
reverse_file_iterator;
file_iterator begin_files() const;
file_iterator end_files() const;
@ -914,14 +986,14 @@ set_comment() set_piece_size() set_creator() set_hash() add_tracker() add_file()
These files are used when creating a torrent file. ``set_comment()`` will simply set
the comment that belongs to this torrent. The comment can be retrieved with the
``comment()`` member.
``comment()`` member. The string should be UTF-8 encoded.
``set_piece_size()`` will set the size of each piece in this torrent. The piece size must
be an even multiple of 2. i.e. usually something like 256 kiB, 512 kiB, 1024 kiB etc. The
size is given in number of bytes.
``set_creator()`` is an optional attribute that can be used to identify your application
that was used to create the torrent file.
that was used to create the torrent file. The string should be UTF-8 encoded.
``set_hash()`` writes the hash for the piece with the given piece-index. You have to call
this function for every piece in the torrent. Usually the hasher_ is used to calculate
@ -973,6 +1045,7 @@ iterators with the type ``file_entry``.
The ``path`` is the full (relative) path of each file. i.e. if it is a multi-file
torrent, all the files starts with a directory with the same name as ``torrent_info::name()``.
The filenames are encoded with UTF-8.
::
@ -1077,6 +1150,8 @@ it will return an empty string. ``creation_date()`` returns a `boost::posix_time
object, representing the time when this torrent file was created. If there's no timestamp
in the torrent file, this will return a date of january 1:st 1970.
Both the name and the comment is UTF-8 encoded strings.
``creator()`` returns the creator string in the torrent. If there is no creator string
it will return an empty string.
@ -1107,7 +1182,8 @@ Its declaration looks like this::
void force_reannounce();
void connect_peer(address const& adr) const;
void set_tracker_login(std::string const& username, std::string const& password);
void set_tracker_login(std::string const& username
, std::string const& password);
std::vector<announce_entry> const& trackers() const;
void replace_trackers(std::vector<announce_entry> const&);
@ -1981,7 +2057,8 @@ This is the class declaration::
struct fingerprint
{
fingerprint(const char* id_string, int major, int minor, int revision, int tag);
fingerprint(const char* id_string, int major, int minor
, int revision, int tag);
std::string to_string() const;
@ -2015,6 +2092,10 @@ sure not to clash with anybody else. Here are some taken id's:
| 'XT' | Xan Torrent |
+----------+-----------------------+
There's currently an informal directory of client id's here__.
__ http://wiki.theory.org/BitTorrentSpecification#peer_id
The ``major``, ``minor``, ``revision`` and ``tag`` parameters are used to identify the
version of your client. All these numbers must be within the range [0, 9].
@ -2607,14 +2688,15 @@ print information about it to std out::
{
std::ifstream in(argv[1], std::ios_base::binary);
in.unsetf(std::ios_base::skipws);
entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
entry e = bdecode(std::istream_iterator<char>(in)
, std::istream_iterator<char>());
torrent_info t(e);
// print info about torrent
std::cout << "\n\n----- torrent file info -----\n\n";
std::cout << "trackers:\n";
for (std::vector<announce_entry>::const_iterator i = t.trackers().begin();
i != t.trackers().end(); ++i)
for (std::vector<announce_entry>::const_iterator i
= t.trackers().begin(), end(t.trackers().end); i != end; ++i)
{
std::cout << i->tier << ": " << i->url << "\n";
}
@ -2623,8 +2705,7 @@ print information about it to std out::
std::cout << "piece length: " << t.piece_length() << "\n";
std::cout << "files:\n";
for (torrent_info::file_iterator i = t.begin_files();
i != t.end_files();
++i)
i != t.end_files(); ++i)
{
std::cout << " " << std::setw(11) << i->size
<< " " << i->path << " " << i->filename << "\n";
@ -2676,7 +2757,8 @@ This is a simple client. It doesn't have much output to keep it simple::
std::ifstream in(argv[1], std::ios_base::binary);
in.unsetf(std::ios_base::skipws);
entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
entry e = bdecode(std::istream_iterator<char>(in)
, std::istream_iterator<char>());
s.add_torrent(e, "");
// wait for the user to end
@ -2715,10 +2797,7 @@ Shows how to create a torrent from a directory tree::
using namespace boost::filesystem;
using namespace libtorrent;
void add_files(
torrent_info& t
, path const& p
, path const& l)
void add_files(torrent_info& t, path const& p, path const& l)
{
path f(p / l);
if (is_directory(f))
@ -2743,8 +2822,8 @@ Shows how to create a torrent from a directory tree::
if (argc != 4)
{
std::cerr << "usage: make_torrent <output torrent-file> <announce url> "
"<file or directory to create torrent from>\n";
std::cerr << "usage: make_torrent <output torrent-file> "
"<announce url> <file or directory to create torrent from>\n";
return 1;
}

View File

@ -54,7 +54,7 @@ POSSIBILITY OF SUCH DAMAGE.
#endif
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/torrent.hpp"
//#include "libtorrent/torrent.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/torrent_info.hpp"
#include "libtorrent/socket.hpp"
@ -78,6 +78,8 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent
{
class torrent;
namespace detail
{
// workaround for microsofts
@ -128,17 +130,17 @@ namespace libtorrent
// if it is not being processed, then it can be removed from
// the queue without problems, otherwise the abort flag has
// to be set.
volatile bool processing;
bool processing;
// is filled in by storage::initialize_pieces()
// and represents the progress. It should be a
// value in the range [0, 1]
volatile float progress;
float progress;
// abort defaults to false and is typically
// filled in by torrent_handle when the user
// aborts the torrent
volatile bool abort;
bool abort;
};
struct checker_impl: boost::noncopyable
@ -157,7 +159,8 @@ namespace libtorrent
// a list of all torrents that are currently in queue
// or checking their files
std::deque<piece_checker_data> m_torrents;
std::deque<boost::shared_ptr<piece_checker_data> > m_torrents;
std::deque<boost::shared_ptr<piece_checker_data> > m_processing;
bool m_abort;
};

View File

@ -122,11 +122,9 @@ namespace libtorrent
~piece_manager();
void check_pieces(
boost::mutex& mutex
, detail::piece_checker_data& data
, std::vector<bool>& pieces
, bool compact_mode);
bool check_fastresume(detail::piece_checker_data& d
, std::vector<bool>& pieces, bool compact_mode);
std::pair<bool, float> check_files(std::vector<bool>& pieces);
void release_files();

View File

@ -47,6 +47,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/filesystem/path.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/enable_shared_from_this.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
@ -61,6 +62,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/stat.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/resource_request.hpp"
#include "libtorrent/piece_picker.hpp"
namespace libtorrent
{
@ -88,11 +90,13 @@ namespace libtorrent
// for a specific download. It updates itself against
// the tracker
class torrent: public request_callback
, public boost::enable_shared_from_this<torrent>
{
public:
torrent(
detail::session_impl& ses
, detail::checker_impl& checker
, entry const& metadata
, boost::filesystem::path const& save_path
, address const& net_interface
@ -103,6 +107,7 @@ namespace libtorrent
// (the metadata is downloaded from the peers)
torrent(
detail::session_impl& ses
, detail::checker_impl& checker
, char const* tracker_url
, sha1_hash const& info_hash
, boost::filesystem::path const& save_path
@ -135,10 +140,11 @@ namespace libtorrent
// this is called from the peer_connection for
// each piece of metadata it receives
void metadata_progress(int total_size, int received);
void check_files(
detail::piece_checker_data& data
, boost::mutex& mutex, bool lock_session = true);
bool check_fastresume(detail::piece_checker_data&);
std::pair<bool, float> check_files();
void files_checked(std::vector<piece_picker::downloading_piece> const&
unfinished_pieces);
stat statistics() const { return m_stat; }
size_type bytes_left() const;
@ -153,8 +159,8 @@ namespace libtorrent
bool is_piece_filtered(int index) const;
void filtered_pieces(std::vector<bool>& bitmask) const;
//idea from Arvid and MooPolice
//todo refactoring and improving the function body
// idea from Arvid and MooPolice
// todo refactoring and improving the function body
// marks the file with the given index as filtered
// it will not be downloaded
void filter_file(int index, bool filter);
@ -456,6 +462,7 @@ namespace libtorrent
// a back reference to the session
// this torrent belongs to.
detail::session_impl& m_ses;
detail::checker_impl& m_checker;
std::auto_ptr<piece_picker> m_picker;

View File

@ -728,7 +728,7 @@ namespace libtorrent
p->connection->send_choke();
} while (m_num_unchoked > m_torrent->m_uploads_quota.given);
}
else
else if (m_num_unchoked > 0)
{
// optimistic unchoke. trade the 'worst'
// unchoked peer with one of the choked

View File

@ -70,14 +70,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/peer_connection.hpp"
#include "libtorrent/ip_filter.hpp"
#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
using ::srand;
using ::isprint;
};
#endif
using namespace boost::posix_time;
namespace libtorrent { namespace detail
@ -100,81 +92,106 @@ namespace libtorrent { namespace detail
void checker_impl::operator()()
{
eh_initializer();
// if we're currently performing a full file check,
// this is the torrent being processed
boost::shared_ptr<piece_checker_data> processing;
boost::shared_ptr<piece_checker_data> t;
for (;;)
{
piece_checker_data* t = 0;
{
boost::mutex::scoped_lock l(m_mutex);
// if the job queue is empty and
// we shouldn't abort
// wait for a signal
if (m_torrents.empty() && !m_abort)
m_cond.wait(l);
if (m_abort) return;
assert(!m_torrents.empty());
t = &m_torrents.front();
if (t->abort)
{
m_torrents.pop_front();
continue;
}
t->processing = true;
}
// temporary torrent used while checking fastresume data
try
{
assert(t != 0);
std::string error_msg;
t->parse_resume_data(t->resume_data, t->torrent_ptr->torrent_file(), error_msg);
// clear the resume data now that it has been used
// (the fast resume data is now parsed and stored in t)
t->resume_data = entry();
t->torrent_ptr->check_files(*t, m_mutex);
// lock the session to add the new torrent
boost::mutex::scoped_lock l(m_mutex);
if (t->abort)
t.reset();
{
m_torrents.pop_front();
continue;
}
boost::mutex::scoped_lock l2(m_ses.m_mutex);
boost::mutex::scoped_lock l(m_mutex);
if (!error_msg.empty() && m_ses.m_alerts.should_post(alert::warning))
{
m_ses.m_alerts.post_alert(fastresume_rejected_alert(
t->torrent_ptr->get_handle()
, error_msg));
}
m_ses.m_torrents.insert(std::make_pair(t->info_hash, t->torrent_ptr));
if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(torrent_finished_alert(
t->torrent_ptr->get_handle()
, "torrent is complete"));
// if the job queue is empty and
// we shouldn't abort
// wait for a signal
if (m_torrents.empty() && !m_abort && !processing)
m_cond.wait(l);
if (m_abort) return;
if (!m_torrents.empty())
{
t = m_torrents.front();
if (t->abort)
{
m_torrents.pop_front();
continue;
}
}
}
peer_id id;
std::fill(id.begin(), id.end(), 0);
for (std::vector<address>::const_iterator i = t->peers.begin();
i != t->peers.end(); ++i)
if (t)
{
t->torrent_ptr->get_policy().peer_from_tracker(*i, id);
std::string error_msg;
t->parse_resume_data(t->resume_data, t->torrent_ptr->torrent_file(), error_msg);
if (!error_msg.empty() && m_ses.m_alerts.should_post(alert::warning))
{
boost::mutex::scoped_lock l2(m_ses.m_mutex);
m_ses.m_alerts.post_alert(fastresume_rejected_alert(
t->torrent_ptr->get_handle()
, error_msg));
}
// clear the resume data now that it has been used
// (the fast resume data is now parsed and stored in t)
t->resume_data = entry();
bool up_to_date = t->torrent_ptr->check_fastresume(*t);
if (up_to_date)
{
// lock the session to add the new torrent
boost::mutex::scoped_lock l(m_ses.m_mutex);
boost::mutex::scoped_lock l2(m_mutex);
assert(m_torrents.front() == t);
t->torrent_ptr->files_checked(t->unfinished_pieces);
m_torrents.pop_front();
m_ses.m_torrents.insert(std::make_pair(t->info_hash, t->torrent_ptr));
if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(torrent_finished_alert(
t->torrent_ptr->get_handle()
, "torrent is complete"));
}
peer_id id;
std::fill(id.begin(), id.end(), 0);
for (std::vector<address>::const_iterator i = t->peers.begin();
i != t->peers.end(); ++i)
{
t->torrent_ptr->get_policy().peer_from_tracker(*i, id);
}
continue;
}
// lock the checker while we move the torrent from
// m_torrents to m_processing
{
boost::mutex::scoped_lock l(m_mutex);
assert(m_torrents.front() == t);
m_torrents.pop_front();
m_processing.push_back(t);
if (!processing)
{
processing = t;
processing->processing = true;
}
}
}
m_torrents.pop_front();
}
catch(const std::exception& e)
{
// This will happen if the storage fails to initialize
boost::mutex::scoped_lock l(m_mutex);
boost::mutex::scoped_lock l2(m_ses.m_mutex);
boost::mutex::scoped_lock l(m_ses.m_mutex);
boost::mutex::scoped_lock l2(m_mutex);
if (m_ses.m_alerts.should_post(alert::fatal))
{
m_ses.m_alerts.post_alert(
@ -182,41 +199,156 @@ namespace libtorrent { namespace detail
t->torrent_ptr->get_handle()
, e.what()));
}
assert(!m_torrents.empty());
m_torrents.pop_front();
}
catch(...)
{
#ifndef NDEBUG
std::cerr << "error while checking resume data\n";
#endif
boost::mutex::scoped_lock l(m_mutex);
assert(!m_torrents.empty());
m_torrents.pop_front();
assert(false);
}
if (!processing) continue;
try
{
assert(processing);
float finished = false;
float progress = 0.f;
boost::tie(finished, progress) = processing->torrent_ptr->check_files();
{
boost::mutex::scoped_lock l(m_mutex);
processing->progress = progress;
if (processing->abort)
{
assert(!m_processing.empty());
assert(m_processing.front() == processing);
processing.reset();
m_processing.pop_front();
if (!m_processing.empty())
{
processing = m_processing.front();
processing->processing = true;
}
continue;
}
}
if (finished)
{
// lock the session to add the new torrent
boost::mutex::scoped_lock l(m_ses.m_mutex);
boost::mutex::scoped_lock l2(m_mutex);
assert(!m_processing.empty());
assert(m_processing.front() == processing);
processing->torrent_ptr->files_checked(processing->unfinished_pieces);
m_ses.m_torrents.insert(std::make_pair(
processing->info_hash, processing->torrent_ptr));
if (processing->torrent_ptr->is_seed()
&& m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(torrent_finished_alert(
processing->torrent_ptr->get_handle()
, "torrent is complete"));
}
peer_id id;
std::fill(id.begin(), id.end(), 0);
for (std::vector<address>::const_iterator i = processing->peers.begin();
i != processing->peers.end(); ++i)
{
processing->torrent_ptr->get_policy().peer_from_tracker(*i, id);
}
processing.reset();
m_processing.pop_front();
if (!m_processing.empty())
{
processing = m_processing.front();
processing->processing = true;
}
}
}
catch(const std::exception& e)
{
// This will happen if the storage fails to initialize
boost::mutex::scoped_lock l(m_ses.m_mutex);
boost::mutex::scoped_lock l2(m_mutex);
if (m_ses.m_alerts.should_post(alert::fatal))
{
m_ses.m_alerts.post_alert(
file_error_alert(
processing->torrent_ptr->get_handle()
, e.what()));
}
assert(!m_processing.empty());
processing.reset();
m_processing.pop_front();
if (!m_processing.empty())
{
processing = m_processing.front();
processing->processing = true;
}
}
catch(...)
{
#ifndef NDEBUG
std::cerr << "error while checking files\n";
#endif
assert(false);
boost::mutex::scoped_lock l(m_mutex);
m_torrents.pop_front();
assert(!m_processing.empty());
processing.reset();
m_processing.pop_front();
if (!m_processing.empty())
{
processing = m_processing.front();
processing->processing = true;
}
assert(false);
}
}
}
detail::piece_checker_data* checker_impl::find_torrent(sha1_hash const& info_hash)
{
for (std::deque<piece_checker_data>::iterator i
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
= m_torrents.begin(); i != m_torrents.end(); ++i)
{
if (i->info_hash == info_hash) return &(*i);
if ((*i)->info_hash == info_hash) return i->get();
}
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
= m_processing.begin(); i != m_processing.end(); ++i)
{
if ((*i)->info_hash == info_hash) return i->get();
}
return 0;
}
void checker_impl::remove_torrent(sha1_hash const& info_hash)
{
for (std::deque<piece_checker_data>::iterator i
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
= m_torrents.begin(); i != m_torrents.end(); ++i)
{
if (i->info_hash == info_hash)
if ((*i)->info_hash == info_hash)
{
assert((*i)->processing == false);
m_torrents.erase(i);
return;
}
}
assert(false);
}
session_impl::session_impl(
@ -389,8 +521,7 @@ namespace libtorrent { namespace detail
}
for (std::vector<boost::shared_ptr<libtorrent::socket> >::iterator i =
writable_clients.begin(); i != writable_clients.end();
++i)
writable_clients.begin(); i != writable_clients.end(); ++i)
{
assert((*i)->is_writable());
}
@ -969,16 +1100,16 @@ namespace libtorrent
std::vector<torrent_handle> session::get_torrents()
{
boost::mutex::scoped_lock l(m_checker_impl.m_mutex);
boost::mutex::scoped_lock l2(m_impl.m_mutex);
boost::mutex::scoped_lock l(m_impl.m_mutex);
boost::mutex::scoped_lock l2(m_checker_impl.m_mutex);
std::vector<torrent_handle> ret;
for (std::deque<detail::piece_checker_data>::iterator i
for (std::deque<boost::shared_ptr<detail::piece_checker_data> >::iterator i
= m_checker_impl.m_torrents.begin()
, end(m_checker_impl.m_torrents.end()); i != end; ++i)
{
if (i->abort) continue;
if ((*i)->abort) continue;
ret.push_back(torrent_handle(&m_impl, &m_checker_impl
, i->info_hash));
, (*i)->info_hash));
}
for (detail::session_impl::torrent_map::iterator i
@ -1041,14 +1172,15 @@ namespace libtorrent
// the checker thread and store it before starting
// the thread
boost::shared_ptr<torrent> torrent_ptr(
new torrent(m_impl, metadata, save_path, m_impl.m_listen_interface
, compact_mode, block_size));
new torrent(m_impl, m_checker_impl, metadata, save_path
, m_impl.m_listen_interface, compact_mode, block_size));
detail::piece_checker_data d;
d.torrent_ptr = torrent_ptr;
d.save_path = save_path;
d.info_hash = ti.info_hash();
d.resume_data = resume_data;
boost::shared_ptr<detail::piece_checker_data> d(
new detail::piece_checker_data);
d->torrent_ptr = torrent_ptr;
d->save_path = save_path;
d->info_hash = ti.info_hash();
d->resume_data = resume_data;
// add the torrent to the queue to be checked
m_checker_impl.m_torrents.push_back(d);
@ -1105,7 +1237,7 @@ namespace libtorrent
// the checker thread and store it before starting
// the thread
boost::shared_ptr<torrent> torrent_ptr(
new torrent(m_impl, tracker_url, info_hash, save_path
new torrent(m_impl, m_checker_impl, tracker_url, info_hash, save_path
, m_impl.m_listen_interface, compact_mode, block_size));
m_impl.m_torrents.insert(
@ -1222,7 +1354,7 @@ namespace libtorrent
// abort the currently checking torrent
if (!m_checker_impl.m_torrents.empty())
{
m_checker_impl.m_torrents.front().abort = true;
m_checker_impl.m_torrents.front()->abort = true;
}
m_checker_impl.m_cond.notify_one();
}

View File

@ -18,24 +18,26 @@ changelog at the end of the file.
// #include <stdint.h>
#include <boost/cstdint.hpp>
using boost::uint32_t;
using boost::uint8_t;
struct SHA1_CTX
{
boost::uint32_t state[5];
boost::uint32_t count[2];
boost::uint8_t buffer[64];
uint32_t state[5];
uint32_t count[2];
uint8_t buffer[64];
};
void SHA1Init(SHA1_CTX* context);
void SHA1Update(SHA1_CTX* context, boost::uint8_t const* data, boost::uint32_t len);
void SHA1Final(SHA1_CTX* context, boost::uint8_t* digest);
void SHA1Update(SHA1_CTX* context, uint8_t const* data, uint32_t len);
void SHA1Final(SHA1_CTX* context, uint8_t* digest);
namespace
{
union CHAR64LONG16
{
boost::uint8_t c[64];
boost::uint32_t l[16];
uint8_t c[64];
uint32_t l[16];
};
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
@ -44,7 +46,7 @@ namespace
// I got the idea of expanding during the round function from SSLeay
struct little_endian_blk0
{
static boost::uint32_t apply(CHAR64LONG16* block, int i)
static uint32_t apply(CHAR64LONG16* block, int i)
{
return block->l[i] = (rol(block->l[i],24)&0xFF00FF00)
| (rol(block->l[i],8)&0x00FF00FF);
@ -53,7 +55,7 @@ namespace
struct big_endian_blk0
{
static boost::uint32_t apply(CHAR64LONG16* block, int i)
static uint32_t apply(CHAR64LONG16* block, int i)
{
return block->l[i];
}
@ -72,13 +74,13 @@ namespace
// Hash a single 512-bit block. This is the core of the algorithm.
template <class BlkFun>
void SHA1Transform(boost::uint32_t state[5], boost::uint8_t const buffer[64])
void SHA1Transform(uint32_t state[5], uint8_t const buffer[64])
{
using namespace std;
boost::uint32_t a, b, c, d, e;
uint32_t a, b, c, d, e;
CHAR64LONG16* block;
boost::uint8_t workspace[64];
uint8_t workspace[64];
block = (CHAR64LONG16*)workspace;
memcpy(block, buffer, 64);
@ -130,10 +132,10 @@ namespace
}
template <class BlkFun>
void internal_update(SHA1_CTX* context, boost::uint8_t const* data, boost::uint32_t len)
void internal_update(SHA1_CTX* context, uint8_t const* data, uint32_t len)
{
using namespace std;
boost::uint32_t i, j; // JHB
uint32_t i, j; // JHB
#ifdef VERBOSE
SHAPrintContext(context, "before");
@ -163,8 +165,8 @@ namespace
bool is_big_endian()
{
boost::uint32_t test = 1;
return *reinterpret_cast<boost::uint8_t*>(&test) == 0;
uint32_t test = 1;
return *reinterpret_cast<uint8_t*>(&test) == 0;
}
}
@ -184,7 +186,7 @@ void SHA1Init(SHA1_CTX* context)
// Run your data through this.
void SHA1Update(SHA1_CTX* context, boost::uint8_t const* data, boost::uint32_t len)
void SHA1Update(SHA1_CTX* context, uint8_t const* data, uint32_t len)
{
#if defined __BIG_ENDIAN__
internal_update<big_endian_blk0>(context, data, len);
@ -203,24 +205,24 @@ void SHA1Update(SHA1_CTX* context, boost::uint8_t const* data, boost::uint32_t l
// Add padding and return the message digest.
void SHA1Final(SHA1_CTX* context, boost::uint8_t* digest)
void SHA1Final(SHA1_CTX* context, uint8_t* digest)
{
boost::uint8_t finalcount[8];
uint8_t finalcount[8];
for (boost::uint32_t i = 0; i < 8; ++i)
for (uint32_t i = 0; i < 8; ++i)
{
// Endian independent
finalcount[i] = static_cast<boost::uint8_t>(
finalcount[i] = static_cast<uint8_t>(
(context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255);
}
SHA1Update(context, (boost::uint8_t const*)"\200", 1);
SHA1Update(context, (uint8_t const*)"\200", 1);
while ((context->count[0] & 504) != 448)
SHA1Update(context, (boost::uint8_t const*)"\0", 1);
SHA1Update(context, (uint8_t const*)"\0", 1);
SHA1Update(context, finalcount, 8); // Should cause a SHA1Transform()
for (boost::uint32_t i = 0; i < 20; ++i)
for (uint32_t i = 0; i < 20; ++i)
{
digest[i] = static_cast<unsigned char>(
(context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);

View File

@ -790,12 +790,14 @@ namespace libtorrent
const torrent_info& info
, const path& path);
void check_pieces(
boost::mutex& mutex
, detail::piece_checker_data& data
bool check_fastresume(
detail::piece_checker_data& d
, std::vector<bool>& pieces
, bool compact_mode);
std::pair<bool, float> check_files(
std::vector<bool>& pieces);
void release_files();
void allocate_slots(int num_slots);
@ -836,9 +838,6 @@ namespace libtorrent
private:
void post_check(boost::mutex& mutex
, detail::piece_checker_data& data);
// returns the slot currently associated with the given
// piece or assigns the given piece_index to a free slot
@ -904,6 +903,29 @@ namespace libtorrent
bool m_allocating;
boost::mutex m_allocating_monitor;
boost::condition m_allocating_condition;
// these states are used while checking/allocating the torrent
enum {
// the default initial state
state_none,
// the file checking is complete
state_finished,
// creating the directories
state_create_files,
// checking the files
state_full_check,
// allocating files (in non-compact mode)
state_allocating
} m_state;
int m_current_slot;
std::vector<char> m_piece_data;
// this maps a piece hash to piece index. It will be
// build the first time it is used (to save time if it
// isn't needed)
std::multimap<sha1_hash, int> m_hash_to_piece;
};
piece_manager::impl::impl(
@ -1239,31 +1261,12 @@ namespace libtorrent
}
}
void piece_manager::impl::post_check(boost::mutex& mutex
, detail::piece_checker_data& data)
{
if (!m_compact_mode)
{
// if we're not in compact mode, make sure the
// pieces are spread out and placed at their
// final position.
int num_slots = (int)m_unallocated_slots.size();
for (int i = 0; i < num_slots; ++i)
{
allocate_slots(1);
boost::mutex::scoped_lock lock(mutex);
data.progress = (float)i / num_slots;
if (data.abort || (data.torrent_ptr && data.torrent_ptr->is_aborted()))
return;
}
}
}
void piece_manager::impl::check_pieces(
boost::mutex& mutex
, detail::piece_checker_data& data
// check if the fastresume data is up to date
// if it is, use it and return true. If it
// isn't return false and the full check
// will be run
bool piece_manager::impl::check_fastresume(
detail::piece_checker_data& data
, std::vector<bool>& pieces
, bool compact_mode)
{
@ -1325,235 +1328,277 @@ namespace libtorrent
}
}
m_unallocated_slots.reserve(int(pieces.size() - data.piece_map.size()));
for (int i = (int)data.piece_map.size(); i < (int)pieces.size(); ++i)
{
m_unallocated_slots.push_back(i);
}
post_check(mutex, data);
return;
if (!m_compact_mode && !m_unallocated_slots.empty())
{
m_state = state_allocating;
return false;
}
else
{
m_state = state_finished;
return true;
}
}
m_state = state_create_files;
return false;
}
// performs the full check and full allocation
// (if necessary). returns true if finished and
// false if it should be called again
// the second return value is the progress the
// file check is at. 0 is nothing done, and 1
// is finished
std::pair<bool, float> piece_manager::impl::check_files(
std::vector<bool>& pieces)
{
if (m_state == state_allocating)
{
if (m_compact_mode)
{
m_state = state_finished;
return std::make_pair(true, 1.f);
}
// if we're not in compact mode, make sure the
// pieces are spread out and placed at their
// final position.
assert(!m_unallocated_slots.empty());
allocate_slots(1);
if (m_unallocated_slots.empty())
{
m_state = state_finished;
return std::make_pair(true, 1.f);
}
return std::make_pair(false, 1.f - (float)m_unallocated_slots.size()
/ (float)m_slot_to_piece.size());
}
if (m_state == state_create_files)
{
// first, create all missing directories
path last_path;
for (torrent_info::file_iterator file_iter = m_info.begin_files(),
end_iter = m_info.end_files(); file_iter != end_iter; ++file_iter)
{
path dir = (m_save_path / file_iter->path).branch_path();
if (dir == last_path) continue;
last_path = dir;
#if defined(_WIN32) && defined(UNICODE)
if (!exists_win(last_path))
create_directories_win(last_path);
#else
if (!exists(last_path))
create_directories(last_path);
#endif
}
m_current_slot = 0;
m_state = state_full_check;
m_piece_data.resize(int(m_info.piece_length()));
return std::make_pair(false, 0.f);
}
assert(m_state == state_full_check);
// ------------------------
// DO THE FULL CHECK
// ------------------------
// first, create all missing directories
path last_path;
for (torrent_info::file_iterator file_iter = m_info.begin_files(),
end_iter = m_info.end_files(); file_iter != end_iter; ++file_iter)
try
{
path dir = (m_save_path / file_iter->path).branch_path();
if (dir == last_path) continue;
last_path = dir;
#if defined(_WIN32) && defined(UNICODE)
if (!exists_win(last_path))
create_directories_win(last_path);
#else
if (!exists(last_path))
create_directories(last_path);
#endif
}
std::vector<char> piece_data(static_cast<int>(m_info.piece_length()));
// this maps a piece hash to piece index. It will be
// build the first time it is used (to save time if it
// isn't needed)
std::multimap<sha1_hash, int> hash_to_piece;
// build the hash-map, that maps hashes to pieces
for (int current_slot = 0; current_slot < m_info.num_pieces(); ++current_slot)
{
try
{
m_storage.read(
&piece_data[0]
, current_slot
m_storage.read(
&m_piece_data[0]
, m_current_slot
, 0
, static_cast<int>(m_info.piece_size(current_slot)));
, int(m_info.piece_size(m_current_slot)));
if (hash_to_piece.empty())
if (m_hash_to_piece.empty())
{
for (int i = 0; i < m_info.num_pieces(); ++i)
{
for (int i = 0; i < m_info.num_pieces(); ++i)
{
hash_to_piece.insert(std::make_pair(m_info.hash_for_piece(i), i));
}
m_hash_to_piece.insert(std::make_pair(m_info.hash_for_piece(i), i));
}
}
int piece_index = identify_data(
piece_data
, current_slot
int piece_index = identify_data(
m_piece_data
, m_current_slot
, pieces
, hash_to_piece);
, m_hash_to_piece);
assert(piece_index == unassigned || piece_index >= 0);
const bool this_should_move = piece_index >= 0 && m_slot_to_piece[piece_index] != unallocated;
const bool other_should_move = m_piece_to_slot[current_slot] != has_no_slot;
assert(piece_index == unassigned || piece_index >= 0);
// check if this piece should be swapped with any other slot
// this section will ensure that the storage is correctly sorted
// libtorrent will never leave the storage in a state that
// requires this sorting, but other clients may.
const bool this_should_move = piece_index >= 0 && m_slot_to_piece[piece_index] != unallocated;
const bool other_should_move = m_piece_to_slot[m_current_slot] != has_no_slot;
// example of worst case:
// | current_slot = 5
// V
// +---+- - - +---+- - - +---+- -
// | x | | 5 | | 3 | <- piece data in slots
// +---+- - - +---+- - - +---+- -
// 3 y 5 <- slot index
// check if this piece should be swapped with any other slot
// this section will ensure that the storage is correctly sorted
// libtorrent will never leave the storage in a state that
// requires this sorting, but other clients may.
// in this example, the data in the current_slot (5)
// is piece 3. It has to be moved into slot 3. The data
// in slot y (piece 5) should be moved into the current_slot.
// and the data in slot 3 (piece x) should be moved to slot y.
// example of worst case:
// | m_current_slot = 5
// V
// +---+- - - +---+- - - +---+- -
// | x | | 5 | | 3 | <- piece data in slots
// +---+- - - +---+- - - +---+- -
// 3 y 5 <- slot index
// there are three possible cases.
// 1. There's another piece that should be placed into this slot
// 2. This piece should be placed into another slot.
// 3. There's another piece that should be placed into this slot
// and this piece should be placed into another slot
// in this example, the data in the m_current_slot (5)
// is piece 3. It has to be moved into slot 3. The data
// in slot y (piece 5) should be moved into the m_current_slot.
// and the data in slot 3 (piece x) should be moved to slot y.
// swap piece_index with this slot
// there are three possible cases.
// 1. There's another piece that should be placed into this slot
// 2. This piece should be placed into another slot.
// 3. There's another piece that should be placed into this slot
// and this piece should be placed into another slot
// case 1
if (this_should_move && !other_should_move)
// swap piece_index with this slot
// case 1
if (this_should_move && !other_should_move)
{
assert(piece_index != m_current_slot);
const int other_slot = piece_index;
assert(other_slot >= 0);
int other_piece = m_slot_to_piece[other_slot];
m_slot_to_piece[other_slot] = piece_index;
m_slot_to_piece[m_current_slot] = other_piece;
m_piece_to_slot[piece_index] = piece_index;
if (other_piece >= 0) m_piece_to_slot[other_piece] = m_current_slot;
if (other_piece == unassigned)
{
assert(piece_index != current_slot);
const int other_slot = piece_index;
assert(other_slot >= 0);
int other_piece = m_slot_to_piece[other_slot];
m_slot_to_piece[other_slot] = piece_index;
m_slot_to_piece[current_slot] = other_piece;
m_piece_to_slot[piece_index] = piece_index;
if (other_piece >= 0) m_piece_to_slot[other_piece] = current_slot;
if (other_piece == unassigned)
{
std::vector<int>::iterator i =
std::find(m_free_slots.begin(), m_free_slots.end(), other_slot);
assert(i != m_free_slots.end());
m_free_slots.erase(i);
m_free_slots.push_back(current_slot);
}
const int slot1_size = static_cast<int>(m_info.piece_size(piece_index));
const int slot2_size = other_piece >= 0 ? static_cast<int>(m_info.piece_size(other_piece)) : 0;
std::vector<char> buf1(slot1_size);
m_storage.read(&buf1[0], current_slot, 0, slot1_size);
if (slot2_size > 0)
{
std::vector<char> buf2(slot2_size);
m_storage.read(&buf2[0], piece_index, 0, slot2_size);
m_storage.write(&buf2[0], current_slot, 0, slot2_size);
}
m_storage.write(&buf1[0], piece_index, 0, slot1_size);
assert(m_slot_to_piece[current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot);
std::vector<int>::iterator i =
std::find(m_free_slots.begin(), m_free_slots.end(), other_slot);
assert(i != m_free_slots.end());
m_free_slots.erase(i);
m_free_slots.push_back(m_current_slot);
}
// case 2
else if (!this_should_move && other_should_move)
const int slot1_size = static_cast<int>(m_info.piece_size(piece_index));
const int slot2_size = other_piece >= 0 ? static_cast<int>(m_info.piece_size(other_piece)) : 0;
std::vector<char> buf1(slot1_size);
m_storage.read(&buf1[0], m_current_slot, 0, slot1_size);
if (slot2_size > 0)
{
assert(piece_index != current_slot);
const int other_piece = current_slot;
const int other_slot = m_piece_to_slot[other_piece];
assert(other_slot >= 0);
m_slot_to_piece[current_slot] = other_piece;
m_slot_to_piece[other_slot] = piece_index;
m_piece_to_slot[other_piece] = current_slot;
if (piece_index >= 0) m_piece_to_slot[piece_index] = other_slot;
if (piece_index == unassigned)
{
m_free_slots.push_back(other_slot);
}
const int slot1_size = static_cast<int>(m_info.piece_size(other_piece));
const int slot2_size = piece_index >= 0 ? static_cast<int>(m_info.piece_size(piece_index)) : 0;
std::vector<char> buf1(slot1_size);
m_storage.read(&buf1[0], other_slot, 0, slot1_size);
if (slot2_size > 0)
{
std::vector<char> buf2(slot2_size);
m_storage.read(&buf2[0], current_slot, 0, slot2_size);
m_storage.write(&buf2[0], other_slot, 0, slot2_size);
}
m_storage.write(&buf1[0], current_slot, 0, slot1_size);
assert(m_slot_to_piece[current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot);
std::vector<char> buf2(slot2_size);
m_storage.read(&buf2[0], piece_index, 0, slot2_size);
m_storage.write(&buf2[0], m_current_slot, 0, slot2_size);
}
else if (this_should_move && other_should_move)
m_storage.write(&buf1[0], piece_index, 0, slot1_size);
assert(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
}
// case 2
else if (!this_should_move && other_should_move)
{
assert(piece_index != m_current_slot);
const int other_piece = m_current_slot;
const int other_slot = m_piece_to_slot[other_piece];
assert(other_slot >= 0);
m_slot_to_piece[m_current_slot] = other_piece;
m_slot_to_piece[other_slot] = piece_index;
m_piece_to_slot[other_piece] = m_current_slot;
if (piece_index >= 0) m_piece_to_slot[piece_index] = other_slot;
if (piece_index == unassigned)
{
assert(piece_index != current_slot);
assert(piece_index >= 0);
m_free_slots.push_back(other_slot);
}
const int piece1 = m_slot_to_piece[piece_index];
const int piece2 = current_slot;
const int slot1 = piece_index;
const int slot2 = m_piece_to_slot[piece2];
const int slot1_size = static_cast<int>(m_info.piece_size(other_piece));
const int slot2_size = piece_index >= 0 ? static_cast<int>(m_info.piece_size(piece_index)) : 0;
std::vector<char> buf1(slot1_size);
m_storage.read(&buf1[0], other_slot, 0, slot1_size);
if (slot2_size > 0)
{
std::vector<char> buf2(slot2_size);
m_storage.read(&buf2[0], m_current_slot, 0, slot2_size);
m_storage.write(&buf2[0], other_slot, 0, slot2_size);
}
m_storage.write(&buf1[0], m_current_slot, 0, slot1_size);
assert(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
}
else if (this_should_move && other_should_move)
{
assert(piece_index != m_current_slot);
assert(piece_index >= 0);
assert(slot1 >= 0);
assert(slot2 >= 0);
assert(piece2 >= 0);
if (slot1 == slot2)
{
// this means there are only two pieces involved in the swap
assert(piece1 >= 0);
const int piece1 = m_slot_to_piece[piece_index];
const int piece2 = m_current_slot;
const int slot1 = piece_index;
const int slot2 = m_piece_to_slot[piece2];
// movement diagram:
// +-----------------------------+
// | |
// +--> slot1 --> current_slot --+
assert(slot1 >= 0);
assert(slot2 >= 0);
assert(piece2 >= 0);
m_slot_to_piece[slot1] = piece_index;
m_slot_to_piece[current_slot] = piece1;
if (slot1 == slot2)
{
// this means there are only two pieces involved in the swap
assert(piece1 >= 0);
m_piece_to_slot[piece_index] = slot1;
m_piece_to_slot[piece1] = current_slot;
assert(piece1 == current_slot);
assert(piece_index == slot1);
// movement diagram:
// +-------------------------------+
// | |
// +--> slot1 --> m_current_slot --+
const int slot1_size = static_cast<int>(m_info.piece_size(piece1));
const int slot3_size = static_cast<int>(m_info.piece_size(piece_index));
std::vector<char> buf1(static_cast<int>(slot1_size));
std::vector<char> buf2(static_cast<int>(slot3_size));
m_slot_to_piece[slot1] = piece_index;
m_slot_to_piece[m_current_slot] = piece1;
m_storage.read(&buf2[0], current_slot, 0, slot3_size);
m_storage.read(&buf1[0], slot1, 0, slot1_size);
m_storage.write(&buf1[0], current_slot, 0, slot1_size);
m_storage.write(&buf2[0], slot1, 0, slot3_size);
m_piece_to_slot[piece_index] = slot1;
m_piece_to_slot[piece1] = m_current_slot;
assert(m_slot_to_piece[current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot);
assert(piece1 == m_current_slot);
assert(piece_index == slot1);
continue;
}
const int slot1_size = static_cast<int>(m_info.piece_size(piece1));
const int slot3_size = static_cast<int>(m_info.piece_size(piece_index));
std::vector<char> buf1(static_cast<int>(slot1_size));
std::vector<char> buf2(static_cast<int>(slot3_size));
m_storage.read(&buf2[0], m_current_slot, 0, slot3_size);
m_storage.read(&buf1[0], slot1, 0, slot1_size);
m_storage.write(&buf1[0], m_current_slot, 0, slot1_size);
m_storage.write(&buf2[0], slot1, 0, slot3_size);
assert(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
}
else
{
assert(slot1 != slot2);
assert(piece1 != piece2);
// movement diagram:
// +---------------------------------------+
// | |
// +--> slot1 --> slot2 --> current_slot --+
// +-----------------------------------------+
// | |
// +--> slot1 --> slot2 --> m_current_slot --+
m_slot_to_piece[slot1] = piece_index;
m_slot_to_piece[slot2] = piece1;
m_slot_to_piece[current_slot] = piece2;
m_slot_to_piece[m_current_slot] = piece2;
m_piece_to_slot[piece_index] = slot1;
m_piece_to_slot[current_slot] = piece2;
m_piece_to_slot[m_current_slot] = piece2;
if (piece1 >= 0) m_piece_to_slot[piece1] = slot2;
if (piece1 == unassigned)
@ -1572,96 +1617,102 @@ namespace libtorrent
std::vector<char> buf1(static_cast<int>(m_info.piece_length()));
std::vector<char> buf2(static_cast<int>(m_info.piece_length()));
m_storage.read(&buf2[0], current_slot, 0, slot3_size);
m_storage.read(&buf2[0], m_current_slot, 0, slot3_size);
m_storage.read(&buf1[0], slot2, 0, slot2_size);
m_storage.write(&buf1[0], current_slot, 0, slot2_size);
m_storage.write(&buf1[0], m_current_slot, 0, slot2_size);
if (slot1_size > 0)
{
m_storage.read(&buf1[0], slot1, 0, slot1_size);
m_storage.write(&buf1[0], slot2, 0, slot1_size);
}
m_storage.write(&buf2[0], slot1, 0, slot3_size);
assert(m_slot_to_piece[current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot);
}
else
{
assert(m_piece_to_slot[current_slot] == has_no_slot || piece_index != current_slot);
assert(m_slot_to_piece[current_slot] == unallocated);
assert(piece_index == unassigned || m_piece_to_slot[piece_index] == has_no_slot);
// the slot was identified as piece 'piece_index'
if (piece_index != unassigned)
m_piece_to_slot[piece_index] = current_slot;
else
m_free_slots.push_back(current_slot);
m_slot_to_piece[current_slot] = piece_index;
assert(m_slot_to_piece[current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot);
assert(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
}
}
catch (file_error&)
else
{
// find the file that failed, and skip all the blocks in that file
size_type file_offset = 0;
size_type current_offset = current_slot * m_info.piece_length();
for (torrent_info::file_iterator i = m_info.begin_files();
i != m_info.end_files(); ++i)
{
file_offset += i->size;
if (file_offset > current_offset) break;
}
assert(m_piece_to_slot[m_current_slot] == has_no_slot || piece_index != m_current_slot);
assert(m_slot_to_piece[m_current_slot] == unallocated);
assert(piece_index == unassigned || m_piece_to_slot[piece_index] == has_no_slot);
assert(file_offset > current_offset);
int skip_blocks = static_cast<int>(
// the slot was identified as piece 'piece_index'
if (piece_index != unassigned)
m_piece_to_slot[piece_index] = m_current_slot;
else
m_free_slots.push_back(m_current_slot);
m_slot_to_piece[m_current_slot] = piece_index;
assert(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
}
}
catch (file_error&)
{
// find the file that failed, and skip all the blocks in that file
size_type file_offset = 0;
size_type current_offset = m_current_slot * m_info.piece_length();
for (torrent_info::file_iterator i = m_info.begin_files();
i != m_info.end_files(); ++i)
{
file_offset += i->size;
if (file_offset > current_offset) break;
}
assert(file_offset > current_offset);
int skip_blocks = static_cast<int>(
(file_offset - current_offset + m_info.piece_length() - 1)
/ m_info.piece_length());
for (int i = current_slot; i < current_slot + skip_blocks; ++i)
{
assert(m_slot_to_piece[i] == unallocated);
m_unallocated_slots.push_back(i);
}
// current slot will increase by one at the end of the for-loop too
current_slot += skip_blocks - 1;
}
// Update progress meter and check if we've been requested to abort
for (int i = m_current_slot; i < m_current_slot + skip_blocks; ++i)
{
boost::mutex::scoped_lock lock(mutex);
data.progress = (float)current_slot / m_info.num_pieces();
if (data.abort || (data.torrent_ptr && data.torrent_ptr->is_aborted()))
return;
assert(m_slot_to_piece[i] == unallocated);
m_unallocated_slots.push_back(i);
}
// current slot will increase by one at the end of the for-loop too
m_current_slot += skip_blocks - 1;
}
++m_current_slot;
if (m_current_slot >= m_info.num_pieces())
{
assert(m_current_slot == m_info.num_pieces());
// clear the memory we've been using
std::vector<char>().swap(m_piece_data);
std::multimap<sha1_hash, int>().swap(m_hash_to_piece);
m_state = state_allocating;
return std::make_pair(false, 1.f);
}
post_check(mutex, data);
// TODO: sort m_free_slots and m_unallocated_slots?
return std::make_pair(false, (float)m_current_slot / m_info.num_pieces());
}
void piece_manager::check_pieces(
boost::mutex& mutex
, detail::piece_checker_data& data
, std::vector<bool>& pieces
bool piece_manager::check_fastresume(
detail::piece_checker_data& d, std::vector<bool>& pieces
, bool compact_mode)
{
m_pimpl->check_pieces(mutex, data, pieces, compact_mode);
return m_pimpl->check_fastresume(d, pieces, compact_mode);
}
std::pair<bool, float> piece_manager::check_files(
std::vector<bool>& pieces)
{
return m_pimpl->check_files(pieces);
}
int piece_manager::impl::allocate_slot_for_piece(int piece_index)
{
// synchronization ------------------------------------------------------
boost::recursive_mutex::scoped_lock lock(m_mutex);
// ----------------------------------------------------------------------
// INVARIANT_CHECK;
// INVARIANT_CHECK;
assert(piece_index >= 0);
assert(piece_index < (int)m_piece_to_slot.size());
assert(piece_index < (int)m_piece_to_slot.size());
assert(m_piece_to_slot.size() == m_slot_to_piece.size());
int slot_index = m_piece_to_slot[piece_index];
@ -1711,7 +1762,7 @@ namespace libtorrent
m_slot_to_piece[slot_index] = piece_index;
m_piece_to_slot[piece_index] = slot_index;
// there is another piece already assigned to
// the slot we are interested in, swap positions
if (slot_index != piece_index
@ -1762,7 +1813,7 @@ namespace libtorrent
}
assert(slot_index >= 0);
assert(slot_index < (int)m_slot_to_piece.size());
assert(slot_index < (int)m_slot_to_piece.size());
return slot_index;
}
@ -1799,7 +1850,7 @@ namespace libtorrent
boost::condition& m_cond;
boost::mutex& m_monitor;
};
}
void piece_manager::impl::allocate_slots(int num_slots)
@ -1809,18 +1860,18 @@ namespace libtorrent
// this object will syncronize the allocation with
// potential other threads
allocation_syncronization sync_obj(
m_allocating
, m_allocating_condition
, m_allocating_monitor);
m_allocating
, m_allocating_condition
, m_allocating_monitor);
// synchronization ------------------------------------------------------
boost::recursive_mutex::scoped_lock lock(m_mutex);
// ----------------------------------------------------------------------
// INVARIANT_CHECK;
// INVARIANT_CHECK;
assert(!m_unallocated_slots.empty());
const int piece_size = static_cast<int>(m_info.piece_length());
std::vector<char> buffer(piece_size, 0);
@ -1828,7 +1879,7 @@ namespace libtorrent
for (int i = 0; i < num_slots && !m_unallocated_slots.empty(); ++i)
{
int pos = m_unallocated_slots.front();
// int piece_pos = pos;
// int piece_pos = pos;
bool write_back = false;
int new_free_slot = pos;

View File

@ -141,6 +141,7 @@ namespace libtorrent
{
torrent::torrent(
detail::session_impl& ses
, detail::checker_impl& checker
, entry const& metadata
, boost::filesystem::path const& save_path
, address const& net_interface
@ -159,6 +160,7 @@ namespace libtorrent
, m_incomplete(-1)
, m_policy()
, m_ses(ses)
, m_checker(checker)
, m_picker(0)
, m_trackers(m_torrent_file.trackers())
, m_last_working_tracker(-1)
@ -220,6 +222,7 @@ namespace libtorrent
torrent::torrent(
detail::session_impl& ses
, detail::checker_impl& checker
, char const* tracker_url
, sha1_hash const& info_hash
, boost::filesystem::path const& save_path
@ -239,6 +242,7 @@ namespace libtorrent
, m_incomplete(-1)
, m_policy()
, m_ses(ses)
, m_checker(checker)
, m_picker(0)
, m_last_working_tracker(-1)
, m_currently_trying_tracker(0)
@ -1018,30 +1022,27 @@ namespace libtorrent
}
void torrent::check_files(detail::piece_checker_data& data,
boost::mutex& mutex, bool lock_session)
bool torrent::check_fastresume(detail::piece_checker_data& data)
{
assert(m_storage.get());
return m_storage->check_fastresume(data, m_have_pieces, m_compact_mode);
}
std::pair<bool, float> torrent::check_files()
{
assert(m_storage.get());
m_storage->check_pieces(mutex, data, m_have_pieces, m_compact_mode);
return m_storage->check_files(m_have_pieces);
}
// TODO: temporary solution. This function should only
// be called from the checker thread, and then this
// hack can be removed (because the session should always
// be locked then)
boost::mutex temp;
boost::mutex* m = &temp;
if (lock_session) m = &m_ses.m_mutex;
boost::mutex::scoped_lock l(mutex);
if (data.abort) return;
boost::mutex::scoped_lock l2(*m);
void torrent::files_checked(std::vector<piece_picker::downloading_piece> const&
unfinished_pieces)
{
m_num_pieces = std::count(
m_have_pieces.begin()
, m_have_pieces.end()
, true);
m_picker->files_checked(m_have_pieces, data.unfinished_pieces);
m_picker->files_checked(m_have_pieces, unfinished_pieces);
}
alert_manager& torrent::alerts() const
@ -1469,18 +1470,29 @@ namespace libtorrent
return false;
}
m_torrent_file.parse_info_section(bdecode(m_metadata.begin(), m_metadata.end()));
entry metadata = bdecode(m_metadata.begin(), m_metadata.end());
m_torrent_file.parse_info_section(metadata);
init();
{
boost::mutex::scoped_lock(m_checker.m_mutex);
boost::mutex m;
detail::piece_checker_data d;
d.abort = false;
// TODO: this check should be moved to the checker thread
// not really a high priority, since no files would usually
// be available if the metadata wasn't available.
check_files(d, m, false);
boost::shared_ptr<detail::piece_checker_data> d(
new detail::piece_checker_data);
d->torrent_ptr = shared_from_this();
d->save_path = m_save_path;
d->info_hash = m_torrent_file.info_hash();
// add the torrent to the queue to be checked
m_checker.m_torrents.push_back(d);
typedef detail::session_impl::torrent_map torrent_map;
torrent_map::iterator i = m_ses.m_torrents.find(
m_torrent_file.info_hash());
assert(i != m_ses.m_torrents.end());
m_ses.m_torrents.erase(i);
// and notify the thread that it got another
// job in its queue
m_checker.m_cond.notify_one();
}
if (m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(metadata_received_alert(
@ -1489,6 +1501,7 @@ namespace libtorrent
// all peer connections have to initialize themselves now that the metadata
// is available
// TODO: is it ok to initialize the connections before the file check?
typedef std::map<address, peer_connection*> conn_map;
for (conn_map::iterator i = m_connections.begin()
, end(m_connections.end()); i != end; ++i)

View File

@ -236,8 +236,11 @@ namespace libtorrent
{
torrent_status st;
if (d == &m_chk->m_torrents.front())
if (d->processing)
{
// TODO: this could be both checking or allocating
st.state = torrent_status::checking_files;
}
else
st.state = torrent_status::queued_for_checking;
st.progress = d->progress;

View File

@ -79,7 +79,11 @@ int test_main()
libtorrent::detail::piece_checker_data d;
std::vector<bool> pieces;
pm.check_pieces(lock, d, pieces, true);
TEST_CHECK(pm.check_fastresume(d, pieces, true) == false);
bool finished = false;
float progress;
while (!finished)
boost::tie(finished, progress) = pm.check_files(pieces);
pm.read(piece, 0, 0, piece_size);
TEST_CHECK(std::equal(piece, piece + piece_size, piece0));