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 * changed the way libtorrent identifies support for its excentions
to look for 'ext' at the end of the peer-id. to look for 'ext' at the end of the peer-id.
* improved performance by adding a circle buffer for the send buffer * 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 http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.3.8: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils 0.3.8: http://docutils.sourceforge.net/" />
<title>libtorrent manual</title> <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" /> <link rel="stylesheet" href="style.css" type="text/css" />
</head> </head>
<body> <body>
@@ -16,143 +16,145 @@
<col class="docinfo-content" /> <col class="docinfo-content" />
<tbody valign="top"> <tbody valign="top">
<tr><th class="docinfo-name">Author:</th> <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> </tbody>
</table> </table>
<div class="contents topic" id="table-of-contents"> <div class="contents topic" id="table-of-contents">
<p class="topic-title first"><a name="table-of-contents">Table of contents</a></p> <p class="topic-title first"><a name="table-of-contents">Table of contents</a></p>
<ul class="simple"> <ul class="simple">
<li><a class="reference" href="#introduction" id="id20" name="id20">introduction</a></li> <li><a class="reference" href="#introduction" id="id21" name="id21">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="#downloading-and-building" id="id22" name="id22">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-bbv2" id="id23" name="id23">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-autotools" id="id24" name="id24">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="#building-with-other-build-systems" id="id25" name="id25">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="#build-configurations" id="id26" name="id26">build configurations</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#overview" id="id26" name="id26">overview</a></li> <li><a class="reference" href="#overview" id="id27" name="id27">overview</a></li>
<li><a class="reference" href="#session" id="id27" name="id27">session</a><ul> <li><a class="reference" href="#session" id="id28" name="id28">session</a><ul>
<li><a class="reference" href="#id7" id="id28" name="id28">session()</a></li> <li><a class="reference" href="#id7" id="id29" name="id29">session()</a></li>
<li><a class="reference" href="#id8" 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="id30" name="id30">add_torrent()</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="id31" name="id31">remove_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="id32" name="id32">disable_extensions() enable_extension()</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="id33" name="id33">set_upload_rate_limit() set_download_rate_limit()</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="id34" name="id34">set_max_uploads() set_max_connections()</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="id35" name="id35">set_ip_filter()</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="id36" name="id36">status()</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="id37" name="id37">is_listening() listen_port() listen_on()</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="id38" name="id38">pop_alert() set_severity_level()</a></li> <li><a class="reference" href="#pop-alert-set-severity-level" id="id39" name="id39">pop_alert() set_severity_level()</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#entry" id="id39" name="id39">entry</a><ul> <li><a class="reference" href="#entry" id="id40" name="id40">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="#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> </ul>
</li> </li>
<li><a class="reference" href="#torrent-info" id="id41" name="id41">torrent_info</a><ul> <li><a class="reference" href="#torrent-info" id="id44" name="id44">torrent_info</a><ul>
<li><a class="reference" href="#id9" id="id42" name="id42">torrent_info()</a></li> <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="id43" name="id43">set_comment() set_piece_size() set_creator() set_hash() add_tracker() add_file()</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="id44" name="id44">create_torrent()</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="id45" name="id45">begin_files() end_files() rbegin_files() rend_files()</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="id46" name="id46">num_files() file_at()</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="id47" name="id47">print()</a></li> <li><a class="reference" href="#print" id="id50" name="id50">print()</a></li>
<li><a class="reference" href="#trackers" id="id48" name="id48">trackers()</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="id49" name="id49">total_size() piece_length() piece_size() num_pieces()</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="id50" name="id50">hash_for_piece() info_hash()</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="id51" name="id51">name() comment() creation_date() creator()</a></li> <li><a class="reference" href="#name-comment-creation-date-creator" id="id54" name="id54">name() comment() creation_date() creator()</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#torrent-handle" id="id52" name="id52">torrent_handle</a><ul> <li><a class="reference" href="#torrent-handle" id="id55" name="id55">torrent_handle</a><ul>
<li><a class="reference" href="#save-path" id="id53" name="id53">save_path()</a></li> <li><a class="reference" href="#save-path" id="id56" name="id56">save_path()</a></li>
<li><a class="reference" href="#move-storage" id="id54" name="id54">move_storage()</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="id55" name="id55">force_reannounce()</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="id56" name="id56">connect_peer()</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="id57" name="id57">set_ratio()</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="id58" name="id58">set_upload_limit() set_download_limit()</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="id59" name="id59">pause() resume() is_paused()</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="id60" name="id60">is_seed()</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="id61" name="id61">has_metadata()</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="id62" name="id62">set_tracker_login()</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="id63" name="id63">trackers() replace_trackers()</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="id64" name="id64">use_interface()</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="id65" name="id65">info_hash()</a></li> <li><a class="reference" href="#info-hash" id="id68" name="id68">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="#id11" id="id69" name="id69">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="#write-resume-data" id="id70" name="id70">write_resume_data()</a></li>
<li><a class="reference" href="#metadata" id="id68" name="id68">metadata()</a></li> <li><a class="reference" href="#metadata" id="id71" name="id71">metadata()</a></li>
<li><a class="reference" href="#id12" id="id69" name="id69">status()</a></li> <li><a class="reference" href="#id12" id="id72" name="id72">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-download-queue" id="id73" name="id73">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-peer-info" id="id74" name="id74">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="#get-torrent-info" id="id75" name="id75">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="#is-valid" id="id76" name="id76">is_valid()</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#torrent-status" id="id74" name="id74">torrent_status</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="id75" name="id75">peer_info</a></li> <li><a class="reference" href="#peer-info" id="id78" name="id78">peer_info</a></li>
<li><a class="reference" href="#address" id="id76" name="id76">address</a></li> <li><a class="reference" href="#address" id="id79" name="id79">address</a></li>
<li><a class="reference" href="#http-settings" id="id77" name="id77">http_settings</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="id78" name="id78">ip_filter</a><ul> <li><a class="reference" href="#ip-filter" id="id81" name="id81">ip_filter</a><ul>
<li><a class="reference" href="#id14" id="id79" name="id79">ip_filter()</a></li> <li><a class="reference" href="#id14" id="id82" name="id82">ip_filter()</a></li>
<li><a class="reference" href="#add-rule" id="id80" name="id80">add_rule()</a></li> <li><a class="reference" href="#add-rule" id="id83" name="id83">add_rule()</a></li>
<li><a class="reference" href="#access" id="id81" name="id81">access()</a></li> <li><a class="reference" href="#access" id="id84" name="id84">access()</a></li>
<li><a class="reference" href="#export-filter" id="id82" name="id82">export_filter()</a></li> <li><a class="reference" href="#export-filter" id="id85" name="id85">export_filter()</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#big-number" id="id83" name="id83">big_number</a></li> <li><a class="reference" href="#big-number" id="id86" name="id86">big_number</a></li>
<li><a class="reference" href="#hasher" id="id84" name="id84">hasher</a></li> <li><a class="reference" href="#hasher" id="id87" name="id87">hasher</a></li>
<li><a class="reference" href="#fingerprint" id="id85" name="id85">fingerprint</a></li> <li><a class="reference" href="#fingerprint" id="id88" name="id88">fingerprint</a></li>
<li><a class="reference" href="#free-functions" id="id86" name="id86">free functions</a><ul> <li><a class="reference" href="#free-functions" id="id89" name="id89">free functions</a><ul>
<li><a class="reference" href="#identify-client" id="id87" name="id87">identify_client()</a></li> <li><a class="reference" href="#identify-client" id="id90" name="id90">identify_client()</a></li>
<li><a class="reference" href="#bdecode-bencode" id="id88" name="id88">bdecode() bencode()</a></li> <li><a class="reference" href="#bdecode-bencode" id="id91" name="id91">bdecode() bencode()</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#alerts" id="id89" name="id89">alerts</a><ul> <li><a class="reference" href="#alerts" id="id92" name="id92">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="#listen-failed-alert" id="id93" name="id93">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="#file-error-alert" id="id94" name="id94">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-announce-alert" id="id95" name="id95">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-alert" id="id96" name="id96">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-reply-alert" id="id97" name="id97">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="#tracker-warning-alert" id="id98" name="id98">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="#hash-failed-alert" id="id99" name="id99">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-ban-alert" id="id100" name="id100">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="#peer-error-alert" id="id101" name="id101">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="#invalid-request-alert" id="id102" name="id102">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="#torrent-finished-alert" id="id103" name="id103">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="#metadata-received-alert" id="id104" name="id104">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="#fastresume-rejected-alert" id="id105" name="id105">fastresume_rejected_alert</a></li>
<li><a class="reference" href="#dispatcher" id="id103" name="id103">dispatcher</a></li> <li><a class="reference" href="#dispatcher" id="id106" name="id106">dispatcher</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#exceptions" id="id104" name="id104">exceptions</a><ul> <li><a class="reference" href="#exceptions" id="id107" name="id107">exceptions</a><ul>
<li><a class="reference" href="#invalid-handle" id="id105" name="id105">invalid_handle</a></li> <li><a class="reference" href="#invalid-handle" id="id108" name="id108">invalid_handle</a></li>
<li><a class="reference" href="#duplicate-torrent" id="id106" name="id106">duplicate_torrent</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="id107" name="id107">invalid_encoding</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="id108" name="id108">type_error</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="id109" name="id109">invalid_torrent_file</a></li> <li><a class="reference" href="#invalid-torrent-file" id="id112" name="id112">invalid_torrent_file</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#examples" id="id110" name="id110">examples</a><ul> <li><a class="reference" href="#examples" id="id113" name="id113">examples</a><ul>
<li><a class="reference" href="#dump-torrent" id="id111" name="id111">dump_torrent</a></li> <li><a class="reference" href="#dump-torrent" id="id114" name="id114">dump_torrent</a></li>
<li><a class="reference" href="#simple-client" id="id112" name="id112">simple client</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="id113" name="id113">make_torrent</a></li> <li><a class="reference" href="#make-torrent" id="id116" name="id116">make_torrent</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#fast-resume" id="id114" name="id114">fast resume</a><ul> <li><a class="reference" href="#fast-resume" id="id117" name="id117">fast resume</a><ul>
<li><a class="reference" href="#file-format" id="id115" name="id115">file format</a></li> <li><a class="reference" href="#file-format" id="id118" name="id118">file format</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#threads" id="id116" name="id116">threads</a></li> <li><a class="reference" href="#threads" id="id119" name="id119">threads</a></li>
<li><a class="reference" href="#storage-allocation" id="id117" name="id117">storage allocation</a><ul> <li><a class="reference" href="#storage-allocation" id="id120" name="id120">storage allocation</a><ul>
<li><a class="reference" href="#full-allocation" id="id118" name="id118">full allocation</a></li> <li><a class="reference" href="#full-allocation" id="id121" name="id121">full allocation</a></li>
<li><a class="reference" href="#compact-allocation" id="id119" name="id119">compact allocation</a></li> <li><a class="reference" href="#compact-allocation" id="id122" name="id122">compact allocation</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#extensions" id="id120" name="id120">extensions</a><ul> <li><a class="reference" href="#extensions" id="id123" name="id123">extensions</a><ul>
<li><a class="reference" href="#chat-messages" id="id121" name="id121">chat messages</a></li> <li><a class="reference" href="#chat-messages" id="id124" name="id124">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="#metadata-from-peers" id="id125" name="id125">metadata from peers</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#filename-checks" id="id123" name="id123">filename checks</a></li> <li><a class="reference" href="#filename-checks" id="id126" name="id126">filename checks</a></li>
<li><a class="reference" href="#acknowledgements" id="id124" name="id124">acknowledgements</a></li> <li><a class="reference" href="#acknowledgements" id="id127" name="id127">acknowledgements</a></li>
</ul> </ul>
</div> </div>
<div class="section" id="introduction"> <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> <p>Fails on:</p>
<blockquote> <blockquote>
<ul class="simple"> <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> <li>msvc6 sp5</li>
</ul> </ul>
</blockquote> </blockquote>
@@ -400,11 +402,30 @@ checking for main in -lboost_thread... yes
directory contains spaces. Make sure you either rename the directories with 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> spaces in their names to remove the spaces or move the libtorrent directory.</p>
</div> </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"> <div class="section" id="step-2-building-libtorrent">
<h3><a name="step-2-building-libtorrent">Step 2: Building libtorrent</a></h3> <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 <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> 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> 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 <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> invariant checks), you have to rerun the configure script and rebuild, like this:</p>
@@ -416,7 +437,7 @@ make
</div> </div>
</div> </div>
<div class="section" id="building-with-other-build-systems"> <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 <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 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 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> type&quot; and &quot;Enable Run-Time Type Info&quot; to Yes.</p>
</div> </div>
<div class="section" id="build-configurations"> <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 <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 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 (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 UTF-16 before they are passed to the file
operations.</td> operations.</td>
</tr> </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> </tbody>
</table> </table>
<p>If you experience that libtorrent uses unreasonable amounts of cpu, it will definately help to <p>If you experience that libtorrent uses unreasonable amounts of cpu, it will
define <tt class="docutils literal"><span class="pre">NDEBUG</span></tt>, since it will remove the invariant checks within the library.</p> 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> </div>
<div class="section" id="overview"> <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 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( session(
const fingerprint&amp; print const fingerprint&amp; print
@@ -888,6 +921,7 @@ can assign the value you want it to have.</p>
entry torrent_file; entry torrent_file;
// ... // ...
// throws if this is not a dictionary
entry::dictionary_type const&amp; dict = torrent_file.dict(); entry::dictionary_type const&amp; dict = torrent_file.dict();
entry::dictionary_type::const_iterator i; entry::dictionary_type::const_iterator i;
i = dict.find(&quot;announce&quot;); i = dict.find(&quot;announce&quot;);
@@ -897,9 +931,54 @@ if (i != dict.end())
std::cout &lt;&lt; tracker_url &lt;&lt; &quot;\n&quot;; std::cout &lt;&lt; tracker_url &lt;&lt; &quot;\n&quot;;
} }
</pre> </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> exists.</p>
</div> </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>
<div class="section" id="torrent-info"> <div class="section" id="torrent-info">
<h1><a name="torrent-info">torrent_info</a></h1> <h1><a name="torrent-info">torrent_info</a></h1>
@@ -922,7 +1001,8 @@ public:
void add_file(boost::filesystem::path file, size_type size); 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_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 begin_files() const;
file_iterator end_files() const; file_iterator end_files() const;
@@ -990,12 +1070,12 @@ void add_file(boost::filesystem::path file, size_type size);
</blockquote> </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 <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 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 <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 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> 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 <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 <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 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> 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 <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> 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 <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"> <pre class="literal-block">
struct file_entry 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> 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 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> 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 <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> it will return an empty string.</p>
</div> </div>
@@ -1156,7 +1238,8 @@ struct torrent_handle
void force_reannounce(); void force_reannounce();
void connect_peer(address const&amp; adr) const; 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; std::vector&lt;announce_entry&gt; const&amp; trackers() const;
void replace_trackers(std::vector&lt;announce_entry&gt; const&amp;); 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"> <pre class="literal-block">
struct fingerprint 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; std::string to_string() const;
@@ -2009,6 +2093,7 @@ sure not to clash with anybody else. Here are some taken id's:</p>
</tr> </tr>
</tbody> </tbody>
</table> </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 <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> 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> <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); std::ifstream in(argv[1], std::ios_base::binary);
in.unsetf(std::ios_base::skipws); 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); torrent_info t(e);
// print info about torrent // print info about torrent
std::cout &lt;&lt; &quot;\n\n----- torrent file info -----\n\n&quot;; std::cout &lt;&lt; &quot;\n\n----- torrent file info -----\n\n&quot;;
std::cout &lt;&lt; &quot;trackers:\n&quot;; std::cout &lt;&lt; &quot;trackers:\n&quot;;
for (std::vector&lt;announce_entry&gt;::const_iterator i = t.trackers().begin(); for (std::vector&lt;announce_entry&gt;::const_iterator i
i != t.trackers().end(); ++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;; 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;piece length: &quot; &lt;&lt; t.piece_length() &lt;&lt; &quot;\n&quot;;
std::cout &lt;&lt; &quot;files:\n&quot;; std::cout &lt;&lt; &quot;files:\n&quot;;
for (torrent_info::file_iterator i = t.begin_files(); for (torrent_info::file_iterator i = t.begin_files();
i != t.end_files(); i != t.end_files(); ++i)
++i)
{ {
std::cout &lt;&lt; &quot; &quot; &lt;&lt; std::setw(11) &lt;&lt; i-&gt;size 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;; &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); std::ifstream in(argv[1], std::ios_base::binary);
in.unsetf(std::ios_base::skipws); 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;); s.add_torrent(e, &quot;&quot;);
// wait for the user to end // wait for the user to end
@@ -2621,10 +2707,7 @@ int main(int argc, char* argv[])
using namespace boost::filesystem; using namespace boost::filesystem;
using namespace libtorrent; using namespace libtorrent;
void add_files( void add_files(torrent_info&amp; t, path const&amp; p, path const&amp; l)
torrent_info&amp; t
, path const&amp; p
, path const&amp; l)
{ {
path f(p / l); path f(p / l);
if (is_directory(f)) if (is_directory(f))
@@ -2649,8 +2732,8 @@ int main(int argc, char* argv[])
if (argc != 4) if (argc != 4)
{ {
std::cerr &lt;&lt; &quot;usage: make_torrent &lt;output torrent-file&gt; &lt;announce url&gt; &quot; std::cerr &lt;&lt; &quot;usage: make_torrent &lt;output torrent-file&gt; &quot;
&quot;&lt;file or directory to create torrent from&gt;\n&quot;; &quot;&lt;announce url&gt; &lt;file or directory to create torrent from&gt;\n&quot;;
return 1; return 1;
} }

View File

@@ -2,7 +2,7 @@
libtorrent manual libtorrent manual
================= =================
:Author: Arvid Norberg, c99ang@cs.umu.se :Author: Arvid Norberg, arvid@rasterbar.com
.. contents:: Table of contents .. contents:: Table of contents
:depth: 2 :depth: 2
@@ -82,7 +82,7 @@ libtorrent has been successfully compiled and tested on:
Fails on: Fails on:
* GCC 2.95.4 (``std::ios_base`` is missing) * GCC 2.95.4
* msvc6 sp5 * msvc6 sp5
libtorrent is released under the BSD-license_. 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 When libtorrent is built it may be a good idea to run the tests, you do this
my running ``make check``. 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 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. 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 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 | | | UTF-16 before they are passed to the file |
| | operations. | | | 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 If you experience that libtorrent uses unreasonable amounts of cpu, it will
define ``NDEBUG``, since it will remove the invariant checks within the library. definately help to define ``NDEBUG``, since it will remove the invariant checks
within the library.
overview overview
======== ========
@@ -406,7 +424,8 @@ The ``session`` class has the following synopsis::
class session: public boost::noncopyable 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( session(
const fingerprint& print const fingerprint& print
@@ -808,6 +827,7 @@ The typical code to get info from a torrent file will then look like this::
entry torrent_file; entry torrent_file;
// ... // ...
// throws if this is not a dictionary
entry::dictionary_type const& dict = torrent_file.dict(); entry::dictionary_type const& dict = torrent_file.dict();
entry::dictionary_type::const_iterator i; entry::dictionary_type::const_iterator i;
i = dict.find("announce"); i = dict.find("announce");
@@ -817,10 +837,61 @@ The typical code to get info from a torrent file will then look like this::
std::cout << tracker_url << "\n"; 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. 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 torrent_info
============ ============
@@ -844,7 +915,8 @@ The ``torrent_info`` has the following synopsis::
void add_file(boost::filesystem::path file, size_type size); 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_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 begin_files() const;
file_iterator end_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 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 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 ``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 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. size is given in number of bytes.
``set_creator()`` is an optional attribute that can be used to identify your application ``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 ``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 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 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()``. 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 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. 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 ``creator()`` returns the creator string in the torrent. If there is no creator string
it will return an empty string. it will return an empty string.
@@ -1107,7 +1182,8 @@ Its declaration looks like this::
void force_reannounce(); void force_reannounce();
void connect_peer(address const& adr) const; 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; std::vector<announce_entry> const& trackers() const;
void replace_trackers(std::vector<announce_entry> const&); void replace_trackers(std::vector<announce_entry> const&);
@@ -1981,7 +2057,8 @@ This is the class declaration::
struct fingerprint 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; 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 | | '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 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]. 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); std::ifstream in(argv[1], std::ios_base::binary);
in.unsetf(std::ios_base::skipws); 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); torrent_info t(e);
// print info about torrent // print info about torrent
std::cout << "\n\n----- torrent file info -----\n\n"; std::cout << "\n\n----- torrent file info -----\n\n";
std::cout << "trackers:\n"; std::cout << "trackers:\n";
for (std::vector<announce_entry>::const_iterator i = t.trackers().begin(); for (std::vector<announce_entry>::const_iterator i
i != t.trackers().end(); ++i) = t.trackers().begin(), end(t.trackers().end); i != end; ++i)
{ {
std::cout << i->tier << ": " << i->url << "\n"; 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 << "piece length: " << t.piece_length() << "\n";
std::cout << "files:\n"; std::cout << "files:\n";
for (torrent_info::file_iterator i = t.begin_files(); for (torrent_info::file_iterator i = t.begin_files();
i != t.end_files(); i != t.end_files(); ++i)
++i)
{ {
std::cout << " " << std::setw(11) << i->size std::cout << " " << std::setw(11) << i->size
<< " " << i->path << " " << i->filename << "\n"; << " " << 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); std::ifstream in(argv[1], std::ios_base::binary);
in.unsetf(std::ios_base::skipws); 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, ""); s.add_torrent(e, "");
// wait for the user to end // 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 boost::filesystem;
using namespace libtorrent; using namespace libtorrent;
void add_files( void add_files(torrent_info& t, path const& p, path const& l)
torrent_info& t
, path const& p
, path const& l)
{ {
path f(p / l); path f(p / l);
if (is_directory(f)) if (is_directory(f))
@@ -2743,8 +2822,8 @@ Shows how to create a torrent from a directory tree::
if (argc != 4) if (argc != 4)
{ {
std::cerr << "usage: make_torrent <output torrent-file> <announce url> " std::cerr << "usage: make_torrent <output torrent-file> "
"<file or directory to create torrent from>\n"; "<announce url> <file or directory to create torrent from>\n";
return 1; return 1;
} }

View File

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

View File

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

View File

@@ -47,6 +47,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple.hpp>
#include <boost/enable_shared_from_this.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
@@ -61,6 +62,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/stat.hpp" #include "libtorrent/stat.hpp"
#include "libtorrent/alert.hpp" #include "libtorrent/alert.hpp"
#include "libtorrent/resource_request.hpp" #include "libtorrent/resource_request.hpp"
#include "libtorrent/piece_picker.hpp"
namespace libtorrent namespace libtorrent
{ {
@@ -88,11 +90,13 @@ namespace libtorrent
// for a specific download. It updates itself against // for a specific download. It updates itself against
// the tracker // the tracker
class torrent: public request_callback class torrent: public request_callback
, public boost::enable_shared_from_this<torrent>
{ {
public: public:
torrent( torrent(
detail::session_impl& ses detail::session_impl& ses
, detail::checker_impl& checker
, entry const& metadata , entry const& metadata
, boost::filesystem::path const& save_path , boost::filesystem::path const& save_path
, address const& net_interface , address const& net_interface
@@ -103,6 +107,7 @@ namespace libtorrent
// (the metadata is downloaded from the peers) // (the metadata is downloaded from the peers)
torrent( torrent(
detail::session_impl& ses detail::session_impl& ses
, detail::checker_impl& checker
, char const* tracker_url , char const* tracker_url
, sha1_hash const& info_hash , sha1_hash const& info_hash
, boost::filesystem::path const& save_path , boost::filesystem::path const& save_path
@@ -136,9 +141,10 @@ namespace libtorrent
// each piece of metadata it receives // each piece of metadata it receives
void metadata_progress(int total_size, int received); void metadata_progress(int total_size, int received);
void check_files( bool check_fastresume(detail::piece_checker_data&);
detail::piece_checker_data& data std::pair<bool, float> check_files();
, boost::mutex& mutex, bool lock_session = true); void files_checked(std::vector<piece_picker::downloading_piece> const&
unfinished_pieces);
stat statistics() const { return m_stat; } stat statistics() const { return m_stat; }
size_type bytes_left() const; size_type bytes_left() const;
@@ -456,6 +462,7 @@ namespace libtorrent
// a back reference to the session // a back reference to the session
// this torrent belongs to. // this torrent belongs to.
detail::session_impl& m_ses; detail::session_impl& m_ses;
detail::checker_impl& m_checker;
std::auto_ptr<piece_picker> m_picker; std::auto_ptr<piece_picker> m_picker;

View File

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

View File

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

View File

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

View File

@@ -790,12 +790,14 @@ namespace libtorrent
const torrent_info& info const torrent_info& info
, const path& path); , const path& path);
void check_pieces( bool check_fastresume(
boost::mutex& mutex detail::piece_checker_data& d
, detail::piece_checker_data& data
, std::vector<bool>& pieces , std::vector<bool>& pieces
, bool compact_mode); , bool compact_mode);
std::pair<bool, float> check_files(
std::vector<bool>& pieces);
void release_files(); void release_files();
void allocate_slots(int num_slots); void allocate_slots(int num_slots);
@@ -836,9 +838,6 @@ namespace libtorrent
private: private:
void post_check(boost::mutex& mutex
, detail::piece_checker_data& data);
// returns the slot currently associated with the given // returns the slot currently associated with the given
// piece or assigns the given piece_index to a free slot // piece or assigns the given piece_index to a free slot
@@ -904,6 +903,29 @@ namespace libtorrent
bool m_allocating; bool m_allocating;
boost::mutex m_allocating_monitor; boost::mutex m_allocating_monitor;
boost::condition m_allocating_condition; 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( piece_manager::impl::impl(
@@ -1239,31 +1261,12 @@ namespace libtorrent
} }
} }
void piece_manager::impl::post_check(boost::mutex& mutex // check if the fastresume data is up to date
, detail::piece_checker_data& data) // if it is, use it and return true. If it
{ // isn't return false and the full check
if (!m_compact_mode) // will be run
{ bool piece_manager::impl::check_fastresume(
// if we're not in compact mode, make sure the detail::piece_checker_data& data
// 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
, std::vector<bool>& pieces , std::vector<bool>& pieces
, bool compact_mode) , bool compact_mode)
{ {
@@ -1325,22 +1328,62 @@ 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) for (int i = (int)data.piece_map.size(); i < (int)pieces.size(); ++i)
{ {
m_unallocated_slots.push_back(i); m_unallocated_slots.push_back(i);
} }
post_check(mutex, data); if (!m_compact_mode && !m_unallocated_slots.empty())
{
return; m_state = state_allocating;
return false;
}
else
{
m_state = state_finished;
return true;
}
} }
// ------------------------ m_state = state_create_files;
// DO THE FULL CHECK 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 // first, create all missing directories
path last_path; path last_path;
for (torrent_info::file_iterator file_iter = m_info.begin_files(), for (torrent_info::file_iterator file_iter = m_info.begin_files(),
@@ -1358,42 +1401,45 @@ namespace libtorrent
create_directories(last_path); create_directories(last_path);
#endif #endif
} }
std::vector<char> piece_data(static_cast<int>(m_info.piece_length())); 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
// ------------------------
// 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 try
{ {
m_storage.read( m_storage.read(
&piece_data[0] &m_piece_data[0]
, current_slot , m_current_slot
, 0 , 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( int piece_index = identify_data(
piece_data m_piece_data
, current_slot , m_current_slot
, pieces , pieces
, hash_to_piece); , m_hash_to_piece);
assert(piece_index == unassigned || piece_index >= 0); assert(piece_index == unassigned || piece_index >= 0);
const bool this_should_move = piece_index >= 0 && m_slot_to_piece[piece_index] != unallocated; 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; const bool other_should_move = m_piece_to_slot[m_current_slot] != has_no_slot;
// check if this piece should be swapped with any other slot // check if this piece should be swapped with any other slot
// this section will ensure that the storage is correctly sorted // this section will ensure that the storage is correctly sorted
@@ -1401,16 +1447,16 @@ namespace libtorrent
// requires this sorting, but other clients may. // requires this sorting, but other clients may.
// example of worst case: // example of worst case:
// | current_slot = 5 // | m_current_slot = 5
// V // V
// +---+- - - +---+- - - +---+- - // +---+- - - +---+- - - +---+- -
// | x | | 5 | | 3 | <- piece data in slots // | x | | 5 | | 3 | <- piece data in slots
// +---+- - - +---+- - - +---+- - // +---+- - - +---+- - - +---+- -
// 3 y 5 <- slot index // 3 y 5 <- slot index
// in this example, the data in the current_slot (5) // in this example, the data in the m_current_slot (5)
// is piece 3. It has to be moved into slot 3. The data // 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. // 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. // and the data in slot 3 (piece x) should be moved to slot y.
// there are three possible cases. // there are three possible cases.
@@ -1424,16 +1470,16 @@ namespace libtorrent
// case 1 // case 1
if (this_should_move && !other_should_move) if (this_should_move && !other_should_move)
{ {
assert(piece_index != current_slot); assert(piece_index != m_current_slot);
const int other_slot = piece_index; const int other_slot = piece_index;
assert(other_slot >= 0); assert(other_slot >= 0);
int other_piece = m_slot_to_piece[other_slot]; int other_piece = m_slot_to_piece[other_slot];
m_slot_to_piece[other_slot] = piece_index; m_slot_to_piece[other_slot] = piece_index;
m_slot_to_piece[current_slot] = other_piece; m_slot_to_piece[m_current_slot] = other_piece;
m_piece_to_slot[piece_index] = piece_index; m_piece_to_slot[piece_index] = piece_index;
if (other_piece >= 0) m_piece_to_slot[other_piece] = current_slot; if (other_piece >= 0) m_piece_to_slot[other_piece] = m_current_slot;
if (other_piece == unassigned) if (other_piece == unassigned)
{ {
@@ -1441,35 +1487,35 @@ namespace libtorrent
std::find(m_free_slots.begin(), m_free_slots.end(), other_slot); std::find(m_free_slots.begin(), m_free_slots.end(), other_slot);
assert(i != m_free_slots.end()); assert(i != m_free_slots.end());
m_free_slots.erase(i); m_free_slots.erase(i);
m_free_slots.push_back(current_slot); m_free_slots.push_back(m_current_slot);
} }
const int slot1_size = static_cast<int>(m_info.piece_size(piece_index)); 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; const int slot2_size = other_piece >= 0 ? static_cast<int>(m_info.piece_size(other_piece)) : 0;
std::vector<char> buf1(slot1_size); std::vector<char> buf1(slot1_size);
m_storage.read(&buf1[0], current_slot, 0, slot1_size); m_storage.read(&buf1[0], m_current_slot, 0, slot1_size);
if (slot2_size > 0) if (slot2_size > 0)
{ {
std::vector<char> buf2(slot2_size); std::vector<char> buf2(slot2_size);
m_storage.read(&buf2[0], piece_index, 0, 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(&buf2[0], m_current_slot, 0, slot2_size);
} }
m_storage.write(&buf1[0], piece_index, 0, slot1_size); m_storage.write(&buf1[0], piece_index, 0, slot1_size);
assert(m_slot_to_piece[current_slot] == unassigned assert(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot); || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
} }
// case 2 // case 2
else if (!this_should_move && other_should_move) else if (!this_should_move && other_should_move)
{ {
assert(piece_index != current_slot); assert(piece_index != m_current_slot);
const int other_piece = current_slot; const int other_piece = m_current_slot;
const int other_slot = m_piece_to_slot[other_piece]; const int other_slot = m_piece_to_slot[other_piece];
assert(other_slot >= 0); assert(other_slot >= 0);
m_slot_to_piece[current_slot] = other_piece; m_slot_to_piece[m_current_slot] = other_piece;
m_slot_to_piece[other_slot] = piece_index; m_slot_to_piece[other_slot] = piece_index;
m_piece_to_slot[other_piece] = current_slot; m_piece_to_slot[other_piece] = m_current_slot;
if (piece_index >= 0) m_piece_to_slot[piece_index] = other_slot; if (piece_index >= 0) m_piece_to_slot[piece_index] = other_slot;
if (piece_index == unassigned) if (piece_index == unassigned)
@@ -1484,20 +1530,20 @@ namespace libtorrent
if (slot2_size > 0) if (slot2_size > 0)
{ {
std::vector<char> buf2(slot2_size); std::vector<char> buf2(slot2_size);
m_storage.read(&buf2[0], current_slot, 0, 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(&buf2[0], other_slot, 0, slot2_size);
} }
m_storage.write(&buf1[0], current_slot, 0, slot1_size); m_storage.write(&buf1[0], m_current_slot, 0, slot1_size);
assert(m_slot_to_piece[current_slot] == unassigned assert(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot); || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
} }
else if (this_should_move && other_should_move) else if (this_should_move && other_should_move)
{ {
assert(piece_index != current_slot); assert(piece_index != m_current_slot);
assert(piece_index >= 0); assert(piece_index >= 0);
const int piece1 = m_slot_to_piece[piece_index]; const int piece1 = m_slot_to_piece[piece_index];
const int piece2 = current_slot; const int piece2 = m_current_slot;
const int slot1 = piece_index; const int slot1 = piece_index;
const int slot2 = m_piece_to_slot[piece2]; const int slot2 = m_piece_to_slot[piece2];
@@ -1511,17 +1557,17 @@ namespace libtorrent
assert(piece1 >= 0); assert(piece1 >= 0);
// movement diagram: // movement diagram:
// +-----------------------------+ // +-------------------------------+
// | | // | |
// +--> slot1 --> current_slot --+ // +--> slot1 --> m_current_slot --+
m_slot_to_piece[slot1] = piece_index; m_slot_to_piece[slot1] = piece_index;
m_slot_to_piece[current_slot] = piece1; m_slot_to_piece[m_current_slot] = piece1;
m_piece_to_slot[piece_index] = slot1; m_piece_to_slot[piece_index] = slot1;
m_piece_to_slot[piece1] = current_slot; m_piece_to_slot[piece1] = m_current_slot;
assert(piece1 == current_slot); assert(piece1 == m_current_slot);
assert(piece_index == slot1); assert(piece_index == slot1);
const int slot1_size = static_cast<int>(m_info.piece_size(piece1)); const int slot1_size = static_cast<int>(m_info.piece_size(piece1));
@@ -1529,31 +1575,30 @@ namespace libtorrent
std::vector<char> buf1(static_cast<int>(slot1_size)); std::vector<char> buf1(static_cast<int>(slot1_size));
std::vector<char> buf2(static_cast<int>(slot3_size)); std::vector<char> buf2(static_cast<int>(slot3_size));
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], slot1, 0, slot1_size); m_storage.read(&buf1[0], slot1, 0, slot1_size);
m_storage.write(&buf1[0], current_slot, 0, slot1_size); m_storage.write(&buf1[0], m_current_slot, 0, slot1_size);
m_storage.write(&buf2[0], slot1, 0, slot3_size); m_storage.write(&buf2[0], slot1, 0, slot3_size);
assert(m_slot_to_piece[current_slot] == unassigned assert(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot); || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
continue;
} }
else
{
assert(slot1 != slot2); assert(slot1 != slot2);
assert(piece1 != piece2); assert(piece1 != piece2);
// movement diagram: // movement diagram:
// +---------------------------------------+ // +-----------------------------------------+
// | | // | |
// +--> slot1 --> slot2 --> current_slot --+ // +--> slot1 --> slot2 --> m_current_slot --+
m_slot_to_piece[slot1] = piece_index; m_slot_to_piece[slot1] = piece_index;
m_slot_to_piece[slot2] = piece1; 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[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 >= 0) m_piece_to_slot[piece1] = slot2;
if (piece1 == unassigned) if (piece1 == unassigned)
@@ -1572,41 +1617,42 @@ namespace libtorrent
std::vector<char> buf1(static_cast<int>(m_info.piece_length())); std::vector<char> buf1(static_cast<int>(m_info.piece_length()));
std::vector<char> buf2(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.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) if (slot1_size > 0)
{ {
m_storage.read(&buf1[0], slot1, 0, slot1_size); m_storage.read(&buf1[0], slot1, 0, slot1_size);
m_storage.write(&buf1[0], slot2, 0, slot1_size); m_storage.write(&buf1[0], slot2, 0, slot1_size);
} }
m_storage.write(&buf2[0], slot1, 0, slot3_size); m_storage.write(&buf2[0], slot1, 0, slot3_size);
assert(m_slot_to_piece[current_slot] == unassigned assert(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot); || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
}
} }
else else
{ {
assert(m_piece_to_slot[current_slot] == has_no_slot || piece_index != current_slot); assert(m_piece_to_slot[m_current_slot] == has_no_slot || piece_index != m_current_slot);
assert(m_slot_to_piece[current_slot] == unallocated); assert(m_slot_to_piece[m_current_slot] == unallocated);
assert(piece_index == unassigned || m_piece_to_slot[piece_index] == has_no_slot); assert(piece_index == unassigned || m_piece_to_slot[piece_index] == has_no_slot);
// the slot was identified as piece 'piece_index' // the slot was identified as piece 'piece_index'
if (piece_index != unassigned) if (piece_index != unassigned)
m_piece_to_slot[piece_index] = current_slot; m_piece_to_slot[piece_index] = m_current_slot;
else else
m_free_slots.push_back(current_slot); m_free_slots.push_back(m_current_slot);
m_slot_to_piece[current_slot] = piece_index; m_slot_to_piece[m_current_slot] = piece_index;
assert(m_slot_to_piece[current_slot] == unassigned assert(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[current_slot]] == current_slot); || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
} }
} }
catch (file_error&) catch (file_error&)
{ {
// find the file that failed, and skip all the blocks in that file // find the file that failed, and skip all the blocks in that file
size_type file_offset = 0; size_type file_offset = 0;
size_type current_offset = current_slot * m_info.piece_length(); size_type current_offset = m_current_slot * m_info.piece_length();
for (torrent_info::file_iterator i = m_info.begin_files(); for (torrent_info::file_iterator i = m_info.begin_files();
i != m_info.end_files(); ++i) i != m_info.end_files(); ++i)
{ {
@@ -1619,37 +1665,42 @@ namespace libtorrent
(file_offset - current_offset + m_info.piece_length() - 1) (file_offset - current_offset + m_info.piece_length() - 1)
/ m_info.piece_length()); / m_info.piece_length());
for (int i = current_slot; i < current_slot + skip_blocks; ++i) for (int i = m_current_slot; i < m_current_slot + skip_blocks; ++i)
{ {
assert(m_slot_to_piece[i] == unallocated); assert(m_slot_to_piece[i] == unallocated);
m_unallocated_slots.push_back(i); m_unallocated_slots.push_back(i);
} }
// current slot will increase by one at the end of the for-loop too // current slot will increase by one at the end of the for-loop too
current_slot += skip_blocks - 1; m_current_slot += skip_blocks - 1;
} }
++m_current_slot;
// Update progress meter and check if we've been requested to abort if (m_current_slot >= m_info.num_pieces())
{ {
boost::mutex::scoped_lock lock(mutex); assert(m_current_slot == m_info.num_pieces());
data.progress = (float)current_slot / m_info.num_pieces();
if (data.abort || (data.torrent_ptr && data.torrent_ptr->is_aborted())) // clear the memory we've been using
return; 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); return std::make_pair(false, (float)m_current_slot / m_info.num_pieces());
// TODO: sort m_free_slots and m_unallocated_slots?
} }
void piece_manager::check_pieces( bool piece_manager::check_fastresume(
boost::mutex& mutex detail::piece_checker_data& d, std::vector<bool>& pieces
, detail::piece_checker_data& data
, std::vector<bool>& pieces
, bool compact_mode) , 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) int piece_manager::impl::allocate_slot_for_piece(int piece_index)

View File

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

View File

@@ -236,8 +236,11 @@ namespace libtorrent
{ {
torrent_status st; 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; st.state = torrent_status::checking_files;
}
else else
st.state = torrent_status::queued_for_checking; st.state = torrent_status::queued_for_checking;
st.progress = d->progress; st.progress = d->progress;

View File

@@ -79,7 +79,11 @@ int test_main()
libtorrent::detail::piece_checker_data d; libtorrent::detail::piece_checker_data d;
std::vector<bool> pieces; 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); pm.read(piece, 0, 0, piece_size);
TEST_CHECK(std::equal(piece, piece + piece_size, piece0)); TEST_CHECK(std::equal(piece, piece + piece_size, piece0));