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:
@@ -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
|
||||||
|
349
docs/manual.html
349
docs/manual.html
@@ -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@cs.umu.se" />
|
<meta name="author" content="Arvid Norberg, arvid@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@cs.umu.se">c99ang@cs.umu.se</a></td></tr>
|
<td>Arvid Norberg, <a class="last reference" href="mailto:arvid@rasterbar.com">arvid@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 "force conformance in for loop scope", "treat wchar_t as
|
|||||||
type" and "Enable Run-Time Type Info" to Yes.</p>
|
type" and "Enable Run-Time Type Info" 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& 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
|
||||||
@@ -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& 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");
|
||||||
@@ -897,9 +931,54 @@ if (i != dict.end())
|
|||||||
std::cout << tracker_url << "\n";
|
std::cout << tracker_url << "\n";
|
||||||
}
|
}
|
||||||
</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("announce"))
|
||||||
|
{
|
||||||
|
std::string tracker_url = i->string();
|
||||||
|
std::cout << tracker_url << "\n";
|
||||||
|
}
|
||||||
|
</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& 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;
|
||||||
|
</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<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;
|
||||||
@@ -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<boost::posix_time::ptime> 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& 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&);
|
||||||
@@ -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<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";
|
||||||
}
|
}
|
||||||
@@ -2530,8 +2616,7 @@ int main(int argc, char* argv[])
|
|||||||
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";
|
||||||
@@ -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<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
|
||||||
@@ -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& 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))
|
||||||
@@ -2649,8 +2732,8 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
129
docs/manual.rst
129
docs/manual.rst
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
@@ -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();
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
244
src/session.cpp
244
src/session.cpp
@@ -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();
|
||||||
}
|
}
|
||||||
|
50
src/sha1.cpp
50
src/sha1.cpp
@@ -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);
|
||||||
|
289
src/storage.cpp
289
src/storage.cpp
@@ -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)
|
||||||
|
@@ -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)
|
||||||
|
@@ -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;
|
||||||
|
@@ -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));
|
||||||
|
Reference in New Issue
Block a user