refactored extensions and added a plugin interface. fixed file.cpp for windows

This commit is contained in:
Arvid Norberg 2006-11-14 00:08:16 +00:00
parent b5e6c66e64
commit e35fc5c4be
43 changed files with 2094 additions and 1145 deletions

View File

@ -1,3 +1,12 @@
* fixed uninitialized private flag in torrent_info
* fixed long standing issue with file.cpp on windows. Replaced the low level
io functions used on windows.
* made it possible to associate a name with torrents without metadata.
* improved http-downloading performance by requesting entire pieces via
http.
* added plugin interface for extensions. And changed the interface for
enabling extensions.
release 0.11
* added support for incorrectly encoded paths in torrent files

View File

@ -53,6 +53,8 @@ SOURCES =
http_tracker_connection.cpp
udp_tracker_connection.cpp
sha1.cpp
metadata_transfer.cpp
logger.cpp
;
KADEMLIA_SOURCES =

View File

@ -1,7 +1,7 @@
AC_PREREQ(2.59)
AC_INIT(src/torrent.cpp)
AM_INIT_AUTOMAKE(libtorrent, 0.11)
AM_INIT_AUTOMAKE(libtorrent, 0.12)
AM_CONFIG_HEADER(config.h)

View File

@ -32,49 +32,49 @@
<li><a class="reference" href="#abort" id="id20" name="id20">abort()</a></li>
<li><a class="reference" href="#add-torrent" id="id21" name="id21">add_torrent()</a></li>
<li><a class="reference" href="#remove-torrent" id="id22" name="id22">remove_torrent()</a></li>
<li><a class="reference" href="#disable-extensions-enable-extension" id="id23" name="id23">disable_extensions() enable_extension()</a></li>
<li><a class="reference" href="#set-upload-rate-limit-set-download-rate-limit" id="id24" name="id24">set_upload_rate_limit() set_download_rate_limit()</a></li>
<li><a class="reference" href="#set-max-uploads-set-max-connections" id="id25" name="id25">set_max_uploads() set_max_connections()</a></li>
<li><a class="reference" href="#set-max-half-open-connections" id="id26" name="id26">set_max_half_open_connections()</a></li>
<li><a class="reference" href="#set-ip-filter" id="id27" name="id27">set_ip_filter()</a></li>
<li><a class="reference" href="#status" id="id28" name="id28">status()</a></li>
<li><a class="reference" href="#is-listening-listen-port-listen-on" id="id29" name="id29">is_listening() listen_port() listen_on()</a></li>
<li><a class="reference" href="#pop-alert-set-severity-level" id="id30" name="id30">pop_alert() set_severity_level()</a></li>
<li><a class="reference" href="#start-dht-stop-dht-set-dht-settings-dht-state" id="id31" name="id31">start_dht() stop_dht() set_dht_settings() dht_state()</a></li>
<li><a class="reference" href="#add-dht-node-add-dht-router" id="id32" name="id32">add_dht_node() add_dht_router()</a></li>
<li><a class="reference" href="#set-upload-rate-limit-set-download-rate-limit" id="id23" name="id23">set_upload_rate_limit() set_download_rate_limit()</a></li>
<li><a class="reference" href="#set-max-uploads-set-max-connections" id="id24" name="id24">set_max_uploads() set_max_connections()</a></li>
<li><a class="reference" href="#set-max-half-open-connections" id="id25" name="id25">set_max_half_open_connections()</a></li>
<li><a class="reference" href="#set-ip-filter" id="id26" name="id26">set_ip_filter()</a></li>
<li><a class="reference" href="#status" id="id27" name="id27">status()</a></li>
<li><a class="reference" href="#is-listening-listen-port-listen-on" id="id28" name="id28">is_listening() listen_port() listen_on()</a></li>
<li><a class="reference" href="#pop-alert-set-severity-level" id="id29" name="id29">pop_alert() set_severity_level()</a></li>
<li><a class="reference" href="#start-dht-stop-dht-set-dht-settings-dht-state" id="id30" name="id30">start_dht() stop_dht() set_dht_settings() dht_state()</a></li>
<li><a class="reference" href="#add-dht-node-add-dht-router" id="id31" name="id31">add_dht_node() add_dht_router()</a></li>
</ul>
</li>
<li><a class="reference" href="#entry" id="id33" name="id33">entry</a><ul>
<li><a class="reference" href="#integer-string-list-dict-type" id="id34" name="id34">integer() string() list() dict() type()</a></li>
<li><a class="reference" href="#operator" id="id35" name="id35">operator[]</a></li>
<li><a class="reference" href="#find-key" id="id36" name="id36">find_key()</a></li>
<li><a class="reference" href="#entry" id="id32" name="id32">entry</a><ul>
<li><a class="reference" href="#integer-string-list-dict-type" id="id33" name="id33">integer() string() list() dict() type()</a></li>
<li><a class="reference" href="#operator" id="id34" name="id34">operator[]</a></li>
<li><a class="reference" href="#find-key" id="id35" name="id35">find_key()</a></li>
</ul>
</li>
<li><a class="reference" href="#torrent-info" id="id37" name="id37">torrent_info</a><ul>
<li><a class="reference" href="#id3" id="id38" name="id38">torrent_info()</a></li>
<li><a class="reference" href="#set-comment-set-piece-size-set-creator-set-hash-add-tracker-add-file" id="id39" name="id39">set_comment() set_piece_size() set_creator() set_hash() add_tracker() add_file()</a></li>
<li><a class="reference" href="#create-torrent" id="id40" name="id40">create_torrent()</a></li>
<li><a class="reference" href="#begin-files-end-files-rbegin-files-rend-files" id="id41" name="id41">begin_files() end_files() rbegin_files() rend_files()</a></li>
<li><a class="reference" href="#num-files-file-at" id="id42" name="id42">num_files() file_at()</a></li>
<li><a class="reference" href="#map-block" id="id43" name="id43">map_block()</a></li>
<li><a class="reference" href="#map-file" id="id44" name="id44">map_file()</a></li>
<li><a class="reference" href="#url-seeds" id="id45" name="id45">url_seeds()</a></li>
<li><a class="reference" href="#print" id="id46" name="id46">print()</a></li>
<li><a class="reference" href="#trackers" id="id47" name="id47">trackers()</a></li>
<li><a class="reference" href="#total-size-piece-length-piece-size-num-pieces" id="id48" name="id48">total_size() piece_length() piece_size() num_pieces()</a></li>
<li><a class="reference" href="#hash-for-piece-info-hash" id="id49" name="id49">hash_for_piece() info_hash()</a></li>
<li><a class="reference" href="#name-comment-creation-date-creator" id="id50" name="id50">name() comment() creation_date() creator()</a></li>
<li><a class="reference" href="#priv-set-priv" id="id51" name="id51">priv() set_priv()</a></li>
<li><a class="reference" href="#nodes" id="id52" name="id52">nodes()</a></li>
<li><a class="reference" href="#add-node" id="id53" name="id53">add_node()</a></li>
<li><a class="reference" href="#torrent-info" id="id36" name="id36">torrent_info</a><ul>
<li><a class="reference" href="#id3" id="id37" name="id37">torrent_info()</a></li>
<li><a class="reference" href="#set-comment-set-piece-size-set-creator-set-hash-add-tracker-add-file" id="id38" name="id38">set_comment() set_piece_size() set_creator() set_hash() add_tracker() add_file()</a></li>
<li><a class="reference" href="#create-torrent" id="id39" name="id39">create_torrent()</a></li>
<li><a class="reference" href="#begin-files-end-files-rbegin-files-rend-files" id="id40" name="id40">begin_files() end_files() rbegin_files() rend_files()</a></li>
<li><a class="reference" href="#num-files-file-at" id="id41" name="id41">num_files() file_at()</a></li>
<li><a class="reference" href="#map-block" id="id42" name="id42">map_block()</a></li>
<li><a class="reference" href="#map-file" id="id43" name="id43">map_file()</a></li>
<li><a class="reference" href="#url-seeds" id="id44" name="id44">url_seeds()</a></li>
<li><a class="reference" href="#print" id="id45" name="id45">print()</a></li>
<li><a class="reference" href="#trackers" id="id46" name="id46">trackers()</a></li>
<li><a class="reference" href="#total-size-piece-length-piece-size-num-pieces" id="id47" name="id47">total_size() piece_length() piece_size() num_pieces()</a></li>
<li><a class="reference" href="#hash-for-piece-info-hash" id="id48" name="id48">hash_for_piece() info_hash()</a></li>
<li><a class="reference" href="#name-comment-creation-date-creator" id="id49" name="id49">name() comment() creation_date() creator()</a></li>
<li><a class="reference" href="#priv-set-priv" id="id50" name="id50">priv() set_priv()</a></li>
<li><a class="reference" href="#nodes" id="id51" name="id51">nodes()</a></li>
<li><a class="reference" href="#add-node" id="id52" name="id52">add_node()</a></li>
</ul>
</li>
<li><a class="reference" href="#torrent-handle" id="id54" name="id54">torrent_handle</a><ul>
<li><a class="reference" href="#file-progress" id="id55" name="id55">file_progress()</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="id57" name="id57">move_storage()</a></li>
<li><a class="reference" href="#force-reannounce" id="id58" name="id58">force_reannounce()</a></li>
<li><a class="reference" href="#connect-peer" id="id59" name="id59">connect_peer()</a></li>
<li><a class="reference" href="#torrent-handle" id="id53" name="id53">torrent_handle</a><ul>
<li><a class="reference" href="#file-progress" id="id54" name="id54">file_progress()</a></li>
<li><a class="reference" href="#save-path" id="id55" name="id55">save_path()</a></li>
<li><a class="reference" href="#move-storage" id="id56" name="id56">move_storage()</a></li>
<li><a class="reference" href="#force-reannounce" id="id57" name="id57">force_reannounce()</a></li>
<li><a class="reference" href="#connect-peer" id="id58" name="id58">connect_peer()</a></li>
<li><a class="reference" href="#name" id="id59" name="id59">name()</a></li>
<li><a class="reference" href="#set-ratio" id="id60" name="id60">set_ratio()</a></li>
<li><a class="reference" href="#set-upload-limit-set-download-limit" id="id61" name="id61">set_upload_limit() set_download_limit()</a></li>
<li><a class="reference" href="#set-sequenced-download-threshold" id="id62" name="id62">set_sequenced_download_threshold()</a></li>
@ -89,78 +89,77 @@
<li><a class="reference" href="#info-hash" id="id71" name="id71">info_hash()</a></li>
<li><a class="reference" href="#id5" id="id72" name="id72">set_max_uploads() set_max_connections()</a></li>
<li><a class="reference" href="#write-resume-data" id="id73" name="id73">write_resume_data()</a></li>
<li><a class="reference" href="#metadata" id="id74" name="id74">metadata()</a></li>
<li><a class="reference" href="#id6" id="id75" name="id75">status()</a></li>
<li><a class="reference" href="#get-download-queue" id="id76" name="id76">get_download_queue()</a></li>
<li><a class="reference" href="#get-peer-info" id="id77" name="id77">get_peer_info()</a></li>
<li><a class="reference" href="#get-torrent-info" id="id78" name="id78">get_torrent_info()</a></li>
<li><a class="reference" href="#is-valid" id="id79" name="id79">is_valid()</a></li>
<li><a class="reference" href="#id6" id="id74" name="id74">status()</a></li>
<li><a class="reference" href="#get-download-queue" id="id75" name="id75">get_download_queue()</a></li>
<li><a class="reference" href="#get-peer-info" id="id76" name="id76">get_peer_info()</a></li>
<li><a class="reference" href="#get-torrent-info" id="id77" name="id77">get_torrent_info()</a></li>
<li><a class="reference" href="#is-valid" id="id78" name="id78">is_valid()</a></li>
</ul>
</li>
<li><a class="reference" href="#torrent-status" id="id80" name="id80">torrent_status</a></li>
<li><a class="reference" href="#peer-info" id="id81" name="id81">peer_info</a></li>
<li><a class="reference" href="#session-settings" id="id82" name="id82">session_settings</a></li>
<li><a class="reference" href="#ip-filter" id="id83" name="id83">ip_filter</a><ul>
<li><a class="reference" href="#id8" id="id84" name="id84">ip_filter()</a></li>
<li><a class="reference" href="#add-rule" id="id85" name="id85">add_rule()</a></li>
<li><a class="reference" href="#access" id="id86" name="id86">access()</a></li>
<li><a class="reference" href="#export-filter" id="id87" name="id87">export_filter()</a></li>
<li><a class="reference" href="#torrent-status" id="id79" name="id79">torrent_status</a></li>
<li><a class="reference" href="#peer-info" id="id80" name="id80">peer_info</a></li>
<li><a class="reference" href="#session-settings" id="id81" name="id81">session_settings</a></li>
<li><a class="reference" href="#ip-filter" id="id82" name="id82">ip_filter</a><ul>
<li><a class="reference" href="#id8" id="id83" name="id83">ip_filter()</a></li>
<li><a class="reference" href="#add-rule" id="id84" name="id84">add_rule()</a></li>
<li><a class="reference" href="#access" id="id85" name="id85">access()</a></li>
<li><a class="reference" href="#export-filter" id="id86" name="id86">export_filter()</a></li>
</ul>
</li>
<li><a class="reference" href="#big-number" id="id88" name="id88">big_number</a></li>
<li><a class="reference" href="#hasher" id="id89" name="id89">hasher</a></li>
<li><a class="reference" href="#fingerprint" id="id90" name="id90">fingerprint</a></li>
<li><a class="reference" href="#free-functions" id="id91" name="id91">free functions</a><ul>
<li><a class="reference" href="#identify-client" id="id92" name="id92">identify_client()</a></li>
<li><a class="reference" href="#client-fingerprint" id="id93" name="id93">client_fingerprint()</a></li>
<li><a class="reference" href="#bdecode-bencode" id="id94" name="id94">bdecode() bencode()</a></li>
<li><a class="reference" href="#big-number" id="id87" name="id87">big_number</a></li>
<li><a class="reference" href="#hasher" id="id88" name="id88">hasher</a></li>
<li><a class="reference" href="#fingerprint" id="id89" name="id89">fingerprint</a></li>
<li><a class="reference" href="#free-functions" id="id90" name="id90">free functions</a><ul>
<li><a class="reference" href="#identify-client" id="id91" name="id91">identify_client()</a></li>
<li><a class="reference" href="#client-fingerprint" id="id92" name="id92">client_fingerprint()</a></li>
<li><a class="reference" href="#bdecode-bencode" id="id93" name="id93">bdecode() bencode()</a></li>
</ul>
</li>
<li><a class="reference" href="#alerts" id="id95" name="id95">alerts</a><ul>
<li><a class="reference" href="#listen-failed-alert" id="id96" name="id96">listen_failed_alert</a></li>
<li><a class="reference" href="#file-error-alert" id="id97" name="id97">file_error_alert</a></li>
<li><a class="reference" href="#tracker-announce-alert" id="id98" name="id98">tracker_announce_alert</a></li>
<li><a class="reference" href="#tracker-alert" id="id99" name="id99">tracker_alert</a></li>
<li><a class="reference" href="#tracker-reply-alert" id="id100" name="id100">tracker_reply_alert</a></li>
<li><a class="reference" href="#tracker-warning-alert" id="id101" name="id101">tracker_warning_alert</a></li>
<li><a class="reference" href="#url-seed-alert" id="id102" name="id102">url_seed_alert</a></li>
<li><a class="reference" href="#hash-failed-alert" id="id103" name="id103">hash_failed_alert</a></li>
<li><a class="reference" href="#peer-ban-alert" id="id104" name="id104">peer_ban_alert</a></li>
<li><a class="reference" href="#peer-error-alert" id="id105" name="id105">peer_error_alert</a></li>
<li><a class="reference" href="#invalid-request-alert" id="id106" name="id106">invalid_request_alert</a></li>
<li><a class="reference" href="#torrent-finished-alert" id="id107" name="id107">torrent_finished_alert</a></li>
<li><a class="reference" href="#metadata-failed-alert" id="id108" name="id108">metadata_failed_alert</a></li>
<li><a class="reference" href="#metadata-received-alert" id="id109" name="id109">metadata_received_alert</a></li>
<li><a class="reference" href="#fastresume-rejected-alert" id="id110" name="id110">fastresume_rejected_alert</a></li>
<li><a class="reference" href="#dispatcher" id="id111" name="id111">dispatcher</a></li>
<li><a class="reference" href="#alerts" id="id94" name="id94">alerts</a><ul>
<li><a class="reference" href="#listen-failed-alert" id="id95" name="id95">listen_failed_alert</a></li>
<li><a class="reference" href="#file-error-alert" id="id96" name="id96">file_error_alert</a></li>
<li><a class="reference" href="#tracker-announce-alert" id="id97" name="id97">tracker_announce_alert</a></li>
<li><a class="reference" href="#tracker-alert" id="id98" name="id98">tracker_alert</a></li>
<li><a class="reference" href="#tracker-reply-alert" id="id99" name="id99">tracker_reply_alert</a></li>
<li><a class="reference" href="#tracker-warning-alert" id="id100" name="id100">tracker_warning_alert</a></li>
<li><a class="reference" href="#url-seed-alert" id="id101" name="id101">url_seed_alert</a></li>
<li><a class="reference" href="#hash-failed-alert" id="id102" name="id102">hash_failed_alert</a></li>
<li><a class="reference" href="#peer-ban-alert" id="id103" name="id103">peer_ban_alert</a></li>
<li><a class="reference" href="#peer-error-alert" id="id104" name="id104">peer_error_alert</a></li>
<li><a class="reference" href="#invalid-request-alert" id="id105" name="id105">invalid_request_alert</a></li>
<li><a class="reference" href="#torrent-finished-alert" id="id106" name="id106">torrent_finished_alert</a></li>
<li><a class="reference" href="#metadata-failed-alert" id="id107" name="id107">metadata_failed_alert</a></li>
<li><a class="reference" href="#metadata-received-alert" id="id108" name="id108">metadata_received_alert</a></li>
<li><a class="reference" href="#fastresume-rejected-alert" id="id109" name="id109">fastresume_rejected_alert</a></li>
<li><a class="reference" href="#dispatcher" id="id110" name="id110">dispatcher</a></li>
</ul>
</li>
<li><a class="reference" href="#exceptions" id="id112" name="id112">exceptions</a><ul>
<li><a class="reference" href="#invalid-handle" id="id113" name="id113">invalid_handle</a></li>
<li><a class="reference" href="#duplicate-torrent" id="id114" name="id114">duplicate_torrent</a></li>
<li><a class="reference" href="#invalid-encoding" id="id115" name="id115">invalid_encoding</a></li>
<li><a class="reference" href="#type-error" id="id116" name="id116">type_error</a></li>
<li><a class="reference" href="#invalid-torrent-file" id="id117" name="id117">invalid_torrent_file</a></li>
<li><a class="reference" href="#exceptions" id="id111" name="id111">exceptions</a><ul>
<li><a class="reference" href="#invalid-handle" id="id112" name="id112">invalid_handle</a></li>
<li><a class="reference" href="#duplicate-torrent" id="id113" name="id113">duplicate_torrent</a></li>
<li><a class="reference" href="#invalid-encoding" id="id114" name="id114">invalid_encoding</a></li>
<li><a class="reference" href="#type-error" id="id115" name="id115">type_error</a></li>
<li><a class="reference" href="#invalid-torrent-file" id="id116" name="id116">invalid_torrent_file</a></li>
</ul>
</li>
<li><a class="reference" href="#fast-resume" id="id118" name="id118">fast resume</a><ul>
<li><a class="reference" href="#file-format" id="id119" name="id119">file format</a></li>
<li><a class="reference" href="#fast-resume" id="id117" name="id117">fast resume</a><ul>
<li><a class="reference" href="#file-format" id="id118" name="id118">file format</a></li>
</ul>
</li>
<li><a class="reference" href="#threads" id="id120" name="id120">threads</a></li>
<li><a class="reference" href="#storage-allocation" id="id121" name="id121">storage allocation</a><ul>
<li><a class="reference" href="#full-allocation" id="id122" name="id122">full allocation</a></li>
<li><a class="reference" href="#compact-allocation" id="id123" name="id123">compact allocation</a></li>
<li><a class="reference" href="#threads" id="id119" name="id119">threads</a></li>
<li><a class="reference" href="#storage-allocation" id="id120" name="id120">storage allocation</a><ul>
<li><a class="reference" href="#full-allocation" id="id121" name="id121">full allocation</a></li>
<li><a class="reference" href="#compact-allocation" id="id122" name="id122">compact allocation</a></li>
</ul>
</li>
<li><a class="reference" href="#extensions" id="id124" name="id124">extensions</a><ul>
<li><a class="reference" href="#chat-messages" id="id125" name="id125">chat messages</a></li>
<li><a class="reference" href="#metadata-from-peers" id="id126" name="id126">metadata from peers</a></li>
<li><a class="reference" href="#http-seeding" id="id127" name="id127">HTTP seeding</a></li>
<li><a class="reference" href="#extensions" id="id123" name="id123">extensions</a><ul>
<li><a class="reference" href="#chat-messages" id="id124" name="id124">chat messages</a></li>
<li><a class="reference" href="#metadata-from-peers" id="id125" name="id125">metadata from peers</a></li>
<li><a class="reference" href="#http-seeding" id="id126" name="id126">HTTP seeding</a></li>
</ul>
</li>
<li><a class="reference" href="#filename-checks" id="id128" name="id128">filename checks</a></li>
<li><a class="reference" href="#acknowledgments" id="id129" name="id129">acknowledgments</a></li>
<li><a class="reference" href="#filename-checks" id="id127" name="id127">filename checks</a></li>
<li><a class="reference" href="#acknowledgments" id="id128" name="id128">acknowledgments</a></li>
</ul>
</div>
<div class="section" id="overview">
@ -236,6 +235,7 @@ class session: public boost::noncopyable
torrent_handle add_torrent(
char const* tracker_url
, sha1_hash const&amp; info_hash
, char const* name
, boost::filesystem::path const&amp; save_path
, entry const&amp; resume_data = entry()
, bool compact_mode = true
@ -245,10 +245,6 @@ class session: public boost::noncopyable
void remove_torrent(torrent_handle const&amp; h);
void disable_extensions();
void enable_extension(
peer_connection::extension_index);
void set_settings(
session_settings const&amp; settings);
@ -349,6 +345,7 @@ torrent_handle add_torrent(
torrent_handle add_torrent(
char const* tracker_url
, sha1_hash const&amp; info_hash
, char const* name
, boost::filesystem::path const&amp; save_path
, entry const&amp; resume_data = entry()
, bool compact_mode = true
@ -380,7 +377,10 @@ about the torrent's progress, its peers etc. It is also used to abort a torrent.
<p>The second overload that takes a tracker url and an info-hash instead of metadata
(<tt class="docutils literal"><span class="pre">torrent_info</span></tt>) can be used with torrents where (at least some) peers support
the metadata extension. For the overload to be available, libtorrent must be built
with extensions enabled (<tt class="docutils literal"><span class="pre">TORRENT_ENABLE_EXTENSIONS</span></tt> defined).</p>
with extensions enabled (<tt class="docutils literal"><span class="pre">TORRENT_ENABLE_EXTENSIONS</span></tt> defined). It also takes an
optional <tt class="docutils literal"><span class="pre">name</span></tt> argument. This may be 0 in case no name should be assigned to the
torrent. In case it's not 0, the name is used for the torrent as long as it doesn't
have metadata. See <tt class="docutils literal"><span class="pre">torrent_handle::name</span></tt>.</p>
</div>
<div class="section" id="remove-torrent">
<h2><a name="remove-torrent">remove_torrent()</a></h2>
@ -392,31 +392,6 @@ void remove_torrent(torrent_handle const&amp; h);
<p><tt class="docutils literal"><span class="pre">remove_torrent()</span></tt> will close all peer connections associated with the torrent and tell
the tracker that we've stopped participating in the swarm.</p>
</div>
<div class="section" id="disable-extensions-enable-extension">
<h2><a name="disable-extensions-enable-extension">disable_extensions() enable_extension()</a></h2>
<blockquote>
<pre class="literal-block">
void disable_extensions();
void enable_extension(peer_connection::extension_index);
</pre>
</blockquote>
<p><tt class="docutils literal"><span class="pre">disable_extensions()</span></tt> will disable all extensions available in libtorrent.
<tt class="docutils literal"><span class="pre">enable_extension()</span></tt> will enable a single extension. The available extensions
are enumerated in the <tt class="docutils literal"><span class="pre">peer_connection</span></tt> class. These are the available extensions:</p>
<pre class="literal-block">
enum extension_index
{
extended_chat_message,
extended_metadata_message,
extended_peer_exchange_message,
extended_listen_port_message,
num_supported_extensions
};
</pre>
<p><em>peer_exchange is not implemented yet</em></p>
<p>By default, all extensions are enabled.
For more information about the extensions, see the <a class="reference" href="#extensions">extensions</a> section.</p>
</div>
<div class="section" id="set-upload-rate-limit-set-download-rate-limit">
<h2><a name="set-upload-rate-limit-set-download-rate-limit">set_upload_rate_limit() set_download_rate_limit()</a></h2>
<blockquote>
@ -596,6 +571,8 @@ address followed by a 2 bytes port number (also network byte order).</dd>
to start up the node again, passing this entry to <tt class="docutils literal"><span class="pre">start_dht</span></tt>. It is a good
idea to save this to disk when the session is closed, and read it up again
when starting.</p>
<p>If the port the DHT is supposed to listen on is already in use, and exception
is thrown, <tt class="docutils literal"><span class="pre">asio::error</span></tt>.</p>
<p><tt class="docutils literal"><span class="pre">stop_dht</span></tt> stops the dht node.</p>
<p><tt class="docutils literal"><span class="pre">add_dht_node</span></tt> adds a node to the routing table. This can be used if your
client has its own source of bootstrapping nodes.</p>
@ -1175,8 +1152,9 @@ struct torrent_handle
torrent_info const&amp; get_torrent_info() const;
bool is_valid() const;
std::string name() const;
entry write_resume_data() const;
std::vector&lt;char&gt; const&amp; metadata() const;
void force_reannounce() const;
void connect_peer(asio::ip::tcp::endpoint const&amp; adr) const;
@ -1295,6 +1273,17 @@ be disconnected. No harm can be done by using this other than an unnecessary con
attempt is made. If the torrent is uninitialized or in queued or checking mode, this
will throw <a class="reference" href="#invalid-handle">invalid_handle</a>.</p>
</div>
<div class="section" id="name">
<h2><a name="name">name()</a></h2>
<blockquote>
<pre class="literal-block">
std::string name() const;
</pre>
</blockquote>
<p>Returns the name of the torrent. i.e. the name from the metadata associated with it. In
case the torrent was started without metadata, and hasn't completely received it yet,
it returns the name given to it when added to the session. See <tt class="docutils literal"><span class="pre">session::add_torrent</span></tt>.</p>
</div>
<div class="section" id="set-ratio">
<h2><a name="set-ratio">set_ratio()</a></h2>
<blockquote>
@ -1489,17 +1478,6 @@ not be ready to write resume data.</li>
is still downloading! The recommended practice is to first pause the torrent, then generate the
fast resume data, and then close it down.</p>
</div>
<div class="section" id="metadata">
<h2><a name="metadata">metadata()</a></h2>
<blockquote>
<pre class="literal-block">
std::vector&lt;char&gt; const&amp; metadata() const;
</pre>
</blockquote>
<p><tt class="docutils literal"><span class="pre">metadata()</span></tt> will return a reference to a buffer containing the exact info part of the
.torrent file. This buffer will be valid as long as the torrent is still running. When hashed,
it will produce the same hash as the info-hash.</p>
</div>
<div class="section" id="id6">
<h2><a name="id6">status()</a></h2>
<blockquote>
@ -2577,9 +2555,9 @@ automatically retry to fetch it in this case. This is only relevant when running
torrent-less download, with the metadata extension provided by libtorrent.
It is generated at severity level <tt class="docutils literal"><span class="pre">info</span></tt>.</p>
<pre class="literal-block">
struct metadata_received_alert: alert
struct metadata_failed_alert: alert
{
metadata_received_alert(
metadata_failed_alert(
const torrent_handle&amp; h
, const std::string&amp; msg);

View File

@ -80,6 +80,7 @@ The ``session`` class has the following synopsis::
torrent_handle add_torrent(
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, boost::filesystem::path const& save_path
, entry const& resume_data = entry()
, bool compact_mode = true
@ -89,10 +90,6 @@ The ``session`` class has the following synopsis::
void remove_torrent(torrent_handle const& h);
void disable_extensions();
void enable_extension(
peer_connection::extension_index);
void set_settings(
session_settings const& settings);
@ -198,6 +195,7 @@ add_torrent()
torrent_handle add_torrent(
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, boost::filesystem::path const& save_path
, entry const& resume_data = entry()
, bool compact_mode = true
@ -234,7 +232,10 @@ about the torrent's progress, its peers etc. It is also used to abort a torrent.
The second overload that takes a tracker url and an info-hash instead of metadata
(``torrent_info``) can be used with torrents where (at least some) peers support
the metadata extension. For the overload to be available, libtorrent must be built
with extensions enabled (``TORRENT_ENABLE_EXTENSIONS`` defined).
with extensions enabled (``TORRENT_ENABLE_EXTENSIONS`` defined). It also takes an
optional ``name`` argument. This may be 0 in case no name should be assigned to the
torrent. In case it's not 0, the name is used for the torrent as long as it doesn't
have metadata. See ``torrent_handle::name``.
remove_torrent()
----------------
@ -247,32 +248,6 @@ remove_torrent()
the tracker that we've stopped participating in the swarm.
disable_extensions() enable_extension()
---------------------------------------
::
void disable_extensions();
void enable_extension(peer_connection::extension_index);
``disable_extensions()`` will disable all extensions available in libtorrent.
``enable_extension()`` will enable a single extension. The available extensions
are enumerated in the ``peer_connection`` class. These are the available extensions::
enum extension_index
{
extended_chat_message,
extended_metadata_message,
extended_peer_exchange_message,
extended_listen_port_message,
num_supported_extensions
};
*peer_exchange is not implemented yet*
By default, all extensions are enabled.
For more information about the extensions, see the extensions_ section.
set_upload_rate_limit() set_download_rate_limit()
-------------------------------------------------
@ -469,6 +444,9 @@ to start up the node again, passing this entry to ``start_dht``. It is a good
idea to save this to disk when the session is closed, and read it up again
when starting.
If the port the DHT is supposed to listen on is already in use, and exception
is thrown, ``asio::error``.
``stop_dht`` stops the dht node.
``add_dht_node`` adds a node to the routing table. This can be used if your
@ -500,6 +478,7 @@ that are ready to replace a failing node, it will be replaced immediately,
this limit is only used to clear out nodes that don't have any node that can
replace them.
add_dht_node() add_dht_router()
-------------------------------
@ -1112,8 +1091,9 @@ Its declaration looks like this::
torrent_info const& get_torrent_info() const;
bool is_valid() const;
std::string name() const;
entry write_resume_data() const;
std::vector<char> const& metadata() const;
void force_reannounce() const;
void connect_peer(asio::ip::tcp::endpoint const& adr) const;
@ -1236,6 +1216,18 @@ attempt is made. If the torrent is uninitialized or in queued or checking mode,
will throw invalid_handle_.
name()
------
::
std::string name() const;
Returns the name of the torrent. i.e. the name from the metadata associated with it. In
case the torrent was started without metadata, and hasn't completely received it yet,
it returns the name given to it when added to the session. See ``session::add_torrent``.
set_ratio()
-----------
@ -1444,18 +1436,6 @@ is still downloading! The recommended practice is to first pause the torrent, th
fast resume data, and then close it down.
metadata()
-------------------
::
std::vector<char> const& metadata() const;
``metadata()`` will return a reference to a buffer containing the exact info part of the
.torrent file. This buffer will be valid as long as the torrent is still running. When hashed,
it will produce the same hash as the info-hash.
status()
--------
@ -2644,9 +2624,9 @@ It is generated at severity level ``info``.
::
struct metadata_received_alert: alert
struct metadata_failed_alert: alert
{
metadata_received_alert(
metadata_failed_alert(
const torrent_handle& h
, const std::string& msg);

View File

@ -51,6 +51,8 @@ POSSIBILITY OF SUCH DAMAGE.
#pragma warning(pop)
#endif
#include "libtorrent/extensions/metadata_transfer.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/session.hpp"
@ -567,6 +569,7 @@ int main(int ac, char* av[])
// monitor when they're not in the directory anymore.
handles_t handles;
session ses;
ses.add_extension(&create_metadata_plugin);
#ifndef TORRENT_DISABLE_DHT
dht_settings s;
@ -668,7 +671,7 @@ int main(int ac, char* av[])
sha1_hash info_hash = boost::lexical_cast<sha1_hash>(what[1]);
torrent_handle h = ses.add_torrent(std::string(what[2]).c_str()
, info_hash, save_path, entry(), compact_allocation_mode);
, info_hash, 0, save_path, entry(), compact_allocation_mode);
handles.insert(std::make_pair(std::string(), h));
h.set_max_connections(60);

View File

@ -7,6 +7,7 @@ libtorrent/config.hpp \
libtorrent/debug.hpp \
libtorrent/entry.hpp \
libtorrent/escape_string.hpp \
libtorrent/extensions.hpp \
libtorrent/file.hpp \
libtorrent/fingerprint.hpp \
libtorrent/hasher.hpp \
@ -43,6 +44,8 @@ libtorrent/utf8.hpp \
libtorrent/version.hpp \
libtorrent/aux_/allocate_resources_impl.hpp \
libtorrent/aux_/session_impl.hpp \
libtorrent/extensions/metadata_transfer.hpp \
libtorrent/extensions/logger.hpp \
\
libtorrent/kademlia/closest_nodes.hpp \
libtorrent/kademlia/dht_tracker.hpp \
@ -61,7 +64,6 @@ libtorrent/asio.hpp \
libtorrent/asio/basic_datagram_socket.hpp \
libtorrent/asio/basic_deadline_timer.hpp \
libtorrent/asio/basic_io_object.hpp \
libtorrent/asio/basic_resolver.hpp \
libtorrent/asio/basic_socket.hpp \
libtorrent/asio/basic_socket_acceptor.hpp \
libtorrent/asio/basic_socket_iostream.hpp \
@ -91,11 +93,12 @@ libtorrent/asio/detail/epoll_reactor_fwd.hpp \
libtorrent/asio/detail/event.hpp \
libtorrent/asio/detail/fd_set_adapter.hpp \
libtorrent/asio/detail/handler_alloc_helpers.hpp \
libtorrent/asio/detail/handler_invoke_helpers.hpp \
libtorrent/asio/detail/hash_map.hpp \
libtorrent/asio/detail/io_control.hpp \
libtorrent/asio/detail/kqueue_reactor.hpp \
libtorrent/asio/detail/kqueue_reactor_fwd.hpp \
libtorrent/asio/detail/handler_invoke_helpers.hpp \
libtorrent/asio/detail/local_free_on_block_exit.hpp \
libtorrent/asio/detail/mutex.hpp \
libtorrent/asio/detail/noncopyable.hpp \
libtorrent/asio/detail/null_event.hpp \
@ -132,6 +135,7 @@ libtorrent/asio/detail/strand_service.hpp \
libtorrent/asio/detail/task_io_service.hpp \
libtorrent/asio/detail/task_io_service_fwd.hpp \
libtorrent/asio/detail/thread.hpp \
libtorrent/asio/detail/throw_error.hpp \
libtorrent/asio/detail/timer_queue.hpp \
libtorrent/asio/detail/timer_queue_base.hpp \
libtorrent/asio/detail/tss_ptr.hpp \
@ -141,7 +145,6 @@ libtorrent/asio/detail/win_iocp_io_service.hpp \
libtorrent/asio/detail/win_iocp_io_service_fwd.hpp \
libtorrent/asio/detail/win_iocp_operation.hpp \
libtorrent/asio/detail/win_iocp_socket_service.hpp \
libtorrent/asio/detail/win_local_free_on_block_exit.hpp \
libtorrent/asio/detail/win_mutex.hpp \
libtorrent/asio/detail/win_signal_blocker.hpp \
libtorrent/asio/detail/win_thread.hpp \
@ -149,9 +152,10 @@ libtorrent/asio/detail/win_tss_ptr.hpp \
libtorrent/asio/detail/winsock_init.hpp \
libtorrent/asio/detail/wrapped_handler.hpp \
libtorrent/asio/error.hpp \
libtorrent/asio/error_handler.hpp \
libtorrent/asio/error_code.hpp \
libtorrent/asio/handler_alloc_hook.hpp \
libtorrent/asio/handler_invoke_hook.hpp \
libtorrent/asio/impl/error_code.ipp \
libtorrent/asio/impl/io_service.ipp \
libtorrent/asio/impl/read.ipp \
libtorrent/asio/impl/read_until.ipp \
@ -161,6 +165,7 @@ libtorrent/asio/ip/address.hpp \
libtorrent/asio/ip/address_v4.hpp \
libtorrent/asio/ip/address_v6.hpp \
libtorrent/asio/ip/basic_endpoint.hpp \
libtorrent/asio/ip/basic_resolver.hpp \
libtorrent/asio/ip/basic_resolver_entry.hpp \
libtorrent/asio/ip/basic_resolver_iterator.hpp \
libtorrent/asio/ip/basic_resolver_query.hpp \
@ -168,6 +173,7 @@ libtorrent/asio/ip/detail/socket_option.hpp \
libtorrent/asio/ip/host_name.hpp \
libtorrent/asio/ip/multicast.hpp \
libtorrent/asio/ip/resolver_query_base.hpp \
libtorrent/asio/ip/resolver_service.hpp \
libtorrent/asio/ip/tcp.hpp \
libtorrent/asio/ip/udp.hpp \
libtorrent/asio/is_read_buffered.hpp \
@ -175,7 +181,6 @@ libtorrent/asio/is_write_buffered.hpp \
libtorrent/asio/placeholders.hpp \
libtorrent/asio/read.hpp \
libtorrent/asio/read_until.hpp \
libtorrent/asio/resolver_service.hpp \
libtorrent/asio/socket_acceptor_service.hpp \
libtorrent/asio/socket_base.hpp \
libtorrent/asio/ssl/basic_context.hpp \
@ -194,9 +199,8 @@ libtorrent/asio/ssl.hpp \
libtorrent/asio/strand.hpp \
libtorrent/asio/stream_socket_service.hpp \
libtorrent/asio/streambuf.hpp \
libtorrent/asio/system_exception.hpp \
libtorrent/asio/system_error.hpp \
libtorrent/asio/thread.hpp \
libtorrent/asio/time_traits.hpp \
libtorrent/asio/write.hpp

View File

@ -170,13 +170,16 @@ namespace libtorrent
, char const* listen_interface = "0.0.0.0");
~session_impl();
#ifndef TORRENT_DISABLE_EXTENSIONS
void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*)> ext);
#endif
void operator()();
void open_listen_port();
void async_accept();
void on_incoming_connection(boost::shared_ptr<stream_socket> const& s
, boost::weak_ptr<socket_acceptor> const& as, asio::error const& e);
, boost::weak_ptr<socket_acceptor> const& as, asio::error_code const& e);
// must be locked to access the data
// in this struct
@ -228,6 +231,7 @@ namespace libtorrent
torrent_handle add_torrent(
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, boost::filesystem::path const& save_path
, entry const& resume_data
, bool compact_mode
@ -235,12 +239,6 @@ namespace libtorrent
void remove_torrent(torrent_handle const& h);
void disable_extensions();
void enable_extension(extension_index i);
bool extensions_enabled() const;
bool extension_enabled(int i) const
{ return m_extension_enabled[i]; }
std::vector<torrent_handle> get_torrents();
void set_severity_level(alert::severity_t s);
@ -259,6 +257,9 @@ namespace libtorrent
void abort();
torrent_handle find_torrent_handle(sha1_hash const& info_hash);
// handles delayed alerts
alert_manager m_alerts;
@ -310,10 +311,6 @@ namespace libtorrent
boost::shared_ptr<socket_acceptor> m_listen_socket;
// the entries in this array maps the
// extension index (as specified in peer_connection)
bool m_extension_enabled[num_supported_extensions];
// the settings for the client
session_settings m_settings;
@ -344,7 +341,7 @@ namespace libtorrent
// does the actual disconnections
// that are queued up in m_disconnect_peer
void second_tick(asio::error const& e);
void second_tick(asio::error_code const& e);
boost::posix_time::ptime m_last_tick;
#ifndef TORRENT_DISABLE_DHT
@ -363,6 +360,13 @@ namespace libtorrent
private:
#endif
#ifndef TORRENT_DISABLE_EXTENSIONS
typedef std::list<boost::function<boost::shared_ptr<
torrent_plugin>(torrent*)> > extension_list_t;
extension_list_t m_extensions;
#endif
// data shared between the main thread
// and the checker thread
checker_impl m_checker_impl;

View File

@ -102,22 +102,49 @@ namespace libtorrent
~bt_peer_connection();
enum message_type
{
// standard messages
msg_choke = 0,
msg_unchoke,
msg_interested,
msg_not_interested,
msg_have,
msg_bitfield,
msg_request,
msg_piece,
msg_cancel,
msg_dht_port,
// extension protocol message
msg_extended = 20,
num_supported_messages
};
// called from the main loop when this connection has any
// work to do.
void on_sent(asio::error const& error
void on_sent(asio::error_code const& error
, std::size_t bytes_transferred);
void on_receive(asio::error const& error
void on_receive(asio::error_code const& error
, std::size_t bytes_transferred);
virtual void get_peer_info(peer_info& p) const;
#ifndef TORRENT_DISABLE_EXTENSIONS
bool support_extensions() const { return m_supports_extensions; }
bool supports_extension(extension_index ex) const
{ return m_extension_messages[ex] > 0; }
bool has_metadata() const;
template <class T>
T* supports_extension() const
{
for (extension_list_t::const_iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
T* ret = dynamic_cast<T*>(i->get());
if (ret) return ret;
}
return 0;
}
#endif
// the message handlers are called
// each time a recv() returns some new
@ -142,9 +169,6 @@ namespace libtorrent
void on_extended(int received);
void on_extended_handshake();
void on_chat();
void on_metadata();
void on_peer_exchange();
typedef void (bt_peer_connection::*message_handler)(int received);
@ -160,14 +184,16 @@ namespace libtorrent
void write_have(int index);
void write_piece(peer_request const& r);
void write_handshake();
#ifndef TORRENT_DISABLE_EXTENSIONS
void write_extensions();
#endif
void write_chat_message(const std::string& msg);
void write_metadata(std::pair<int, int> req);
void write_metadata_request(std::pair<int, int> req);
void write_keepalive();
void write_dht_port(int listen_port);
void on_connected() {}
void on_tick();
void on_metadata();
#ifndef NDEBUG
void check_invariant() const;
@ -184,11 +210,6 @@ namespace libtorrent
// will be invalid.
boost::optional<piece_block_progress> downloading_piece_progress() const;
// if we don't have all metadata
// this function will request a part of it
// from this peer
void request_metadata();
enum state
{
read_protocol_length = 0,
@ -207,25 +228,6 @@ namespace libtorrent
// the timeout in seconds
int m_timeout;
enum message_type
{
// standard messages
msg_choke = 0,
msg_unchoke,
msg_interested,
msg_not_interested,
msg_have,
msg_bitfield,
msg_request,
msg_piece,
msg_cancel,
msg_dht_port,
// extension protocol message
msg_extended = 20,
num_supported_messages
};
static const message_handler m_message_handler[num_supported_messages];
// this is a queue of ranges that describes
@ -249,43 +251,19 @@ namespace libtorrent
{ return r.start < 0; }
std::deque<range> m_payloads;
#ifndef TORRENT_DISABLE_EXTENSIONS
// this is set to true if the handshake from
// the peer indicated that it supports the
// extension protocol
bool m_supports_extensions;
#endif
bool m_supports_dht_port;
static const char* extension_names[num_supported_extensions];
// contains the indices of the extension messages for each extension
// supported by the other end. A value of <= 0 means that the extension
// is not supported.
int m_extension_messages[num_supported_extensions];
// this is set to the current time each time we get a
// "I don't have metadata" message.
boost::posix_time::ptime m_no_metadata;
// this is set to the time when we last sent
// a request for metadata to this peer
boost::posix_time::ptime m_metadata_request;
// this is set to true when we send a metadata
// request to this peer, and reset to false when
// we receive a reply to our request.
bool m_waiting_metadata_request;
// if we're waiting for a metadata request
// this was the request we sent
std::pair<int, int> m_last_metadata_request;
// the number of bytes of metadata we have received
// so far from this per, only counting the current
// request. Any previously finished requests
// that have been forwarded to the torrent object
// do not count.
int m_metadata_progress;
#ifndef NDEBUG
// this is set to true when the client's
// bitfield is sent to this peer
bool m_sent_bitfield;
bool m_in_constructor;
#endif
};

View File

@ -128,14 +128,14 @@ namespace libtorrent
data_type type() const;
entry(const dictionary_type&);
entry(const string_type&);
entry(const list_type&);
entry(const integer_type&);
entry(dictionary_type const&);
entry(string_type const&);
entry(list_type const&);
entry(integer_type const&);
entry();
entry(data_type t);
entry(const entry& e);
entry(entry const& e);
~entry();
bool operator==(entry const& e) const;
@ -221,6 +221,7 @@ namespace libtorrent
inline entry::integer_type& entry::integer()
{
if (m_type == undefined_t) construct(int_t);
if (m_type != int_t) throw type_error("invalid type requested from entry");
return *reinterpret_cast<integer_type*>(data);
}
@ -233,6 +234,7 @@ namespace libtorrent
inline entry::string_type& entry::string()
{
if (m_type == undefined_t) construct(string_t);
if (m_type != string_t) throw type_error("invalid type requested from entry");
return *reinterpret_cast<string_type*>(data);
}
@ -245,6 +247,7 @@ namespace libtorrent
inline entry::list_type& entry::list()
{
if (m_type == undefined_t) construct(list_t);
if (m_type != list_t) throw type_error("invalid type requested from entry");
return *reinterpret_cast<list_type*>(data);
}
@ -257,6 +260,7 @@ namespace libtorrent
inline entry::dictionary_type& entry::dict()
{
if (m_type == undefined_t) construct(dictionary_t);
if (m_type != dictionary_t) throw type_error("invalid type requested from entry");
return *reinterpret_cast<dictionary_type*>(data);
}

View File

@ -0,0 +1,167 @@
/*
Copyright (c) 2006, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_EXTENSIONS_HPP_INCLUDED
#define TORRENT_EXTENSIONS_HPP_INCLUDED
#ifndef TORRENT_DISABLE_EXTENSIONS
#ifdef _MSC_VER
#pragma warning(push, 1)
#endif
#include <boost/shared_ptr.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include <vector>
#include "libtorrent/config.hpp"
#include "libtorrent/buffer.hpp"
namespace libtorrent
{
struct peer_plugin;
class bt_peer_connection;
struct peer_request;
class peer_connection;
class entry;
struct TORRENT_EXPORT torrent_plugin
{
virtual ~torrent_plugin() {}
// throwing an exception closes the connection
// returning a 0 pointer is valid and will not add
// the peer_plugin to the peer_connection
virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection*)
{ return boost::shared_ptr<peer_plugin>(); }
virtual void on_piece_pass(int index) {}
virtual void on_piece_failed(int index) {}
// called aproximately once every second
virtual void tick() {}
// if true is returned, it means the handler handled the event,
// and no other plugins will have their handlers called, and the
// default behavior will be skipped
virtual bool on_pause() { return false; }
virtual bool on_resume() { return false;}
};
struct TORRENT_EXPORT peer_plugin
{
virtual ~peer_plugin() {}
// can add entries to the extension handshake
virtual void add_handshake(entry&) {}
// throwing an exception from any of the handlers (except add_handshake)
// closes the connection
// this is called when the initial BT handshake is received. Returning false
// means that the other end doesn't support this extension and will remove
// it from the list of plugins.
virtual bool on_handshake() { return true; }
// called when the extension handshake from the other end is received
// if this returns false, it means that this extension isn't
// supported by this peer. It will result in this peer_plugin
// being removed from the peer_connection and destructed.
virtual bool on_extension_handshake(entry const& h) { return true; }
// returning true from any of the message handlers
// indicates that the plugin has handeled the message.
// it will break the plugin chain traversing and not let
// anyone else handle the message, including the default
// handler.
virtual bool on_choke()
{ return false; }
virtual bool on_unchoke()
{ return false; }
virtual bool on_interested()
{ return false; }
virtual bool on_not_interested()
{ return false; }
virtual bool on_have(int index)
{ return false; }
virtual bool on_bitfield(std::vector<bool> const& bitfield)
{ return false; }
virtual bool on_request(peer_request const& req)
{ return false; }
virtual bool on_piece(peer_request const& piece, char const* data)
{ return false; }
virtual bool on_cancel(peer_request const& req)
{ return false; }
// called when an extended message is received. If returning true,
// the message is not processed by any other plugin and if false
// is returned the next plugin in the chain will receive it to
// be able to handle it
virtual bool on_extended(int length
, int msg, buffer::const_interval body)
{ return false; }
virtual bool on_unknown_message(int length, int msg
, buffer::const_interval body)
{ return false; }
// called when a piece that this peer participated in either
// fails or passes the hash_check
virtual void on_piece_pass(int index) {}
virtual void on_piece_failed(int index) {}
// called aproximately once every second
virtual void tick() {}
// called each time a request message is to be sent. If true
// is returned, the original request message won't be sent and
// no other plugin will have this function called.
virtual bool write_request(peer_request const& r) { return false; }
};
}
#endif
#endif // TORRENT_EXTENSIONS_HPP_INCLUDED

View File

@ -0,0 +1,54 @@
/*
Copyright (c) 2006, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_LOGGER_HPP_INCLUDED
#define TORRENT_LOGGER_HPP_INCLUDED
#ifdef _MSC_VER
#pragma warning(push, 1)
#endif
#include <boost/shared_ptr.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
namespace libtorrent
{
struct torrent_plugin;
class torrent;
boost::shared_ptr<torrent_plugin> create_logger_plugin(torrent*);
}
#endif // TORRENT_LOGGER_HPP_INCLUDED

View File

@ -0,0 +1,54 @@
/*
Copyright (c) 2006, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_METADATA_TRANSFER_HPP_INCLUDED
#define TORRENT_METADATA_TRANSFER_HPP_INCLUDED
#ifdef _MSC_VER
#pragma warning(push, 1)
#endif
#include <boost/shared_ptr.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
namespace libtorrent
{
struct torrent_plugin;
class torrent;
boost::shared_ptr<torrent_plugin> create_metadata_plugin(torrent*);
}
#endif // TORRENT_METADATA_TRANSFER_HPP_INCLUDED

View File

@ -132,10 +132,10 @@ namespace libtorrent
std::string const& hostname
, std::string const& request);
void name_lookup(asio::error const& error, tcp::resolver::iterator i);
void connected(asio::error const& error);
void sent(asio::error const& error);
void receive(asio::error const& error
void name_lookup(asio::error_code const& error, tcp::resolver::iterator i);
void connected(asio::error_code const& error);
void sent(asio::error_code const& error);
void receive(asio::error_code const& error
, std::size_t bytes_transferred);
virtual void on_timeout();

View File

@ -81,17 +81,17 @@ namespace libtorrent { namespace dht
private:
void on_name_lookup(asio::error const& e
void on_name_lookup(asio::error_code const& e
, udp::resolver::iterator host);
void on_router_name_lookup(asio::error const& e
void on_router_name_lookup(asio::error_code const& e
, udp::resolver::iterator host);
void connection_timeout(asio::error const& e);
void refresh_timeout(asio::error const& e);
void tick(asio::error const& e);
void connection_timeout(asio::error_code const& e);
void refresh_timeout(asio::error_code const& e);
void tick(asio::error_code const& e);
// translate bittorrent kademlia message into the generice kademlia message
// used by the library
void on_receive(asio::error const& error, size_t bytes_transferred);
void on_receive(asio::error_code const& error, size_t bytes_transferred);
void on_bootstrap();
void send_packet(msg const& m);

View File

@ -79,6 +79,7 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent
{
class torrent;
struct peer_plugin;
namespace detail
{
@ -116,16 +117,36 @@ namespace libtorrent
aux::session_impl& ses
, boost::shared_ptr<stream_socket> s);
virtual ~peer_connection();
#ifndef TORRENT_DISABLE_EXTENSIONS
void add_extension(boost::shared_ptr<peer_plugin>);
#endif
// this function is called once the torrent associated
// with this peer connection has retrieved the meta-
// data. If the torrent was spawned with metadata
// this is called from the constructor.
void init();
// this is called when the metadata is retrieved
// and the files has been checked
virtual void on_metadata() {}
void set_upload_limit(int limit);
void set_download_limit(int limit);
virtual ~peer_connection();
bool prefer_whole_pieces() const
{ return m_prefer_whole_pieces; }
void prefer_whole_pieces(bool b)
{ m_prefer_whole_pieces = b; }
bool request_large_blocks() const
{ return m_request_large_blocks; }
void request_large_blocks(bool b)
{ m_request_large_blocks = b; }
// this adds an announcement in the announcement queue
// it will let the peer know that we have the given piece
@ -185,7 +206,7 @@ namespace libtorrent
// this is called when the connection attempt has succeeded
// and the peer_connection is supposed to set m_connecting
// to false, and stop monitor writability
void on_connection_complete(asio::error const& e);
void on_connection_complete(asio::error_code const& e);
// returns true if this connection is still waiting to
// finish the connection attempt
@ -212,8 +233,8 @@ namespace libtorrent
void add_free_upload(size_type free_upload);
// trust management.
void received_valid_data();
void received_invalid_data();
void received_valid_data(int index);
void received_invalid_data(int index);
int trust_points() const;
size_type share_diff() const;
@ -290,6 +311,10 @@ namespace libtorrent
return boost::optional<piece_block_progress>();
}
void send_buffer(char const* begin, char const* end);
buffer::interval allocate_send_buffer(int size);
void setup_send();
protected:
virtual void write_choke() = 0;
@ -305,13 +330,11 @@ namespace libtorrent
virtual void on_connected() = 0;
virtual void on_tick() {}
virtual void on_receive(asio::error const& error
virtual void on_receive(asio::error_code const& error
, std::size_t bytes_transferred) = 0;
virtual void on_sent(asio::error const& error
virtual void on_sent(asio::error_code const& error
, std::size_t bytes_transferred) = 0;
void send_buffer(char const* begin, char const* end);
buffer::interval allocate_send_buffer(int size);
int send_buffer_size() const
{
return (int)m_send_buffer[0].size()
@ -336,7 +359,6 @@ namespace libtorrent
return m_packet_size == m_recv_pos;
}
void setup_send();
void setup_receive();
void attach_to_torrent(sha1_hash const& ih);
@ -357,9 +379,9 @@ namespace libtorrent
// called from the main loop when this connection has any
// work to do.
void on_send_data(asio::error const& error
void on_send_data(asio::error_code const& error
, std::size_t bytes_transferred);
void on_receive_data(asio::error const& error
void on_receive_data(asio::error_code const& error
, std::size_t bytes_transferred);
// this is the limit on the number of outstanding requests
@ -372,6 +394,11 @@ namespace libtorrent
void set_timeout(int s) { m_timeout = s; }
#ifndef TORRENT_DISABLE_EXTENSIONS
typedef std::list<boost::shared_ptr<peer_plugin> > extension_list_t;
extension_list_t m_extensions;
#endif
private:
void fill_send_buffer();
@ -543,6 +570,22 @@ namespace libtorrent
int m_last_write_size;
bool m_reading;
int m_last_read_size;
// if set to true, this peer will always prefer
// to request entire pieces, rather than blocks.
// if it is false, the download rate limit setting
// will be used to determine if whole pieces
// are preferred.
bool m_prefer_whole_pieces;
// if this is true, the blocks picked by the piece
// picker will be merged before passed to the
// request function. i.e. subsequent blocks are
// merged into larger blocks. This is used by
// the http-downloader, to request whole pieces
// at a time.
bool m_request_large_blocks;
// reference counter for intrusive_ptr
mutable boost::detail::atomic_count m_refs;

View File

@ -68,17 +68,10 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent
{
struct torrent_plugin;
class torrent;
class ip_filter;
enum extension_index
{
extended_handshake,
extended_chat_message,
extended_metadata_message,
extended_peer_exchange_message,
num_supported_extensions
};
namespace aux
{
@ -130,7 +123,11 @@ namespace libtorrent
~session();
// returns a list of all torrents in this session
std::vector<torrent_handle> get_torrents() const;
// returns an invalid handle in case the torrent doesn't exist
torrent_handle find_torrent(sha1_hash const& info_hash) const;
// all torrent_handles must be destructed before the session is destructed!
torrent_handle add_torrent(
@ -155,6 +152,7 @@ namespace libtorrent
torrent_handle add_torrent(
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, boost::filesystem::path const& save_path
, entry const& resume_data = entry()
, bool compact_mode = true
@ -173,8 +171,11 @@ namespace libtorrent
void add_dht_router(std::pair<std::string, int> const& node);
#endif
void enable_extension(extension_index i);
void disable_extensions();
#ifndef TORRENT_DISABLE_EXTENSIONS
void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*)> ext);
#endif
void set_ip_filter(ip_filter const& f);
void set_peer_id(peer_id const& pid);

View File

@ -74,6 +74,7 @@ namespace libtorrent
#endif
class piece_manager;
struct torrent_plugin;
namespace aux
{
@ -81,10 +82,6 @@ namespace libtorrent
struct piece_checker_data;
}
int div_round_up(int numerator, int denominator);
std::pair<int, int> req_to_offset(std::pair<int, int> req, int total_size);
std::pair<int, int> offset_to_req(std::pair<int, int> offset, int total_size);
// a torrent is a class that holds information
// for a specific download. It updates itself against
// the tracker
@ -110,6 +107,7 @@ namespace libtorrent
, aux::checker_impl& checker
, char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, boost::filesystem::path const& save_path
, tcp::endpoint const& net_interface
, bool compact_mode
@ -118,6 +116,10 @@ namespace libtorrent
~torrent();
#ifndef TORRENT_DISABLE_EXTENSIONS
void add_extension(boost::shared_ptr<torrent_plugin>);
#endif
// this is called when the torrent has metadata.
// it will initialize the storage and the piece-picker
void init();
@ -146,10 +148,8 @@ namespace libtorrent
// debug purpose only
void print(std::ostream& os) const;
// this is called from the peer_connection for
// each piece of metadata it receives
void metadata_progress(int total_size, int received);
std::string name() const;
bool check_fastresume(aux::piece_checker_data&);
std::pair<bool, float> check_files();
void files_checked(std::vector<piece_picker::downloading_piece> const&
@ -324,7 +324,7 @@ namespace libtorrent
// this is the asio callback that is called when a name
// lookup for a web seed is completed.
void on_name_lookup(asio::error const& e, tcp::resolver::iterator i
void on_name_lookup(asio::error_code const& e, tcp::resolver::iterator i
, std::string url);
// this is called when the torrent has finished. i.e.
@ -419,19 +419,13 @@ namespace libtorrent
{ return m_connections_initialized; }
bool valid_metadata() const
{ return m_storage.get() != 0; }
std::vector<char> const& metadata() const;
bool received_metadata(
char const* buf
, int size
, int offset
, int total_size);
// returns a range of the metadata that
// we should request.
std::pair<int, int> metadata_request();
void cancel_metadata_request(std::pair<int, int> req);
// parses the info section from the given
// bencoded tree and moves the torrent
// to the checker thread for initial checking
// of the storage.
void set_metadata(entry const&);
private:
void try_next_tracker();
@ -501,7 +495,7 @@ namespace libtorrent
static void on_dht_announce_response_disp(boost::weak_ptr<torrent> t
, std::vector<tcp::endpoint> const& peers);
deadline_timer m_dht_announce_timer;
void on_dht_announce(asio::error const& e);
void on_dht_announce(asio::error_code const& e);
void on_dht_announce_response(std::vector<tcp::endpoint> const& peers);
#endif
@ -574,30 +568,11 @@ namespace libtorrent
int m_upload_bandwidth_limit;
int m_download_bandwidth_limit;
// this buffer is filled with the info-section of
// the metadata file while downloading it from
// peers, and while sending it.
// it is mutable because it's generated lazily
mutable std::vector<char> m_metadata;
// this is a bitfield of size 256, each bit represents
// a piece of the metadata. It is set to one if we
// have that piece. This vector may be empty
// (size 0) if we haven't received any metadata
// or if we already have all metadata
std::vector<bool> m_have_metadata;
// this vector keeps track of how many times each meatdata
// block has been requested
std::vector<int> m_requested_metadata;
boost::filesystem::path m_save_path;
// determines the storage state for this torrent.
const bool m_compact_mode;
int m_metadata_progress;
int m_metadata_size;
// defaults to 16 kiB, but can be set by the user
// when creating the torrent
const int m_default_block_size;
@ -613,7 +588,18 @@ namespace libtorrent
// has been initialized with files_checked().
bool m_connections_initialized;
// if the torrent is started without metadata, it may
// still be given a name until the metadata is received
// once the metadata is received this field will no
// longer be used and will be reset
boost::scoped_ptr<std::string> m_name;
session_settings const& m_settings;
#ifndef TORRENT_DISABLE_EXTENSIONS
typedef std::list<boost::shared_ptr<torrent_plugin> > extension_list_t;
extension_list_t m_extensions;
#endif
#ifndef NDEBUG
// this is the amount downloaded when this torrent

View File

@ -218,7 +218,7 @@ namespace libtorrent
friend struct aux::session_impl;
friend class torrent;
torrent_handle(): m_ses(0), m_chk(0) {}
torrent_handle(): m_ses(0), m_chk(0), m_info_hash(0) {}
void get_peer_info(std::vector<peer_info>& v) const;
bool send_chat_message(tcp::endpoint ip, std::string message) const;
@ -261,13 +261,6 @@ namespace libtorrent
entry write_resume_data() const;
// kind of similar to get_torrent_info() but this
// is lower level, returning the exact info-part of
// the .torrent file. When hashed, this buffer
// will produce the info hash. The reference is valid
// only as long as the torrent is running.
std::vector<char> const& metadata() const;
// forces this torrent to reannounce
// (make a rerequest from the tracker)
void force_reannounce() const;
@ -278,6 +271,11 @@ namespace libtorrent
// timed out.
void force_reannounce(boost::posix_time::time_duration) const;
// returns the name of this torrent, in case it doesn't
// have metadata it returns the name assigned to it
// when it was added.
std::string name() const;
// TODO: add a feature where the user can tell the torrent
// to finish all pieces currently in the pipeline, and then
// abort the torrent.

View File

@ -167,7 +167,7 @@ namespace libtorrent
private:
void timeout_callback(asio::error const&);
void timeout_callback(asio::error_code const&);
boost::intrusive_ptr<timeout_handler> self()
{ return boost::intrusive_ptr<timeout_handler>(this); }

View File

@ -87,17 +87,17 @@ namespace libtorrent
boost::intrusive_ptr<udp_tracker_connection> self()
{ return boost::intrusive_ptr<udp_tracker_connection>(this); }
void name_lookup(asio::error const& error, tcp::resolver::iterator i);
void timeout(asio::error const& error);
void name_lookup(asio::error_code const& error, tcp::resolver::iterator i);
void timeout(asio::error_code const& error);
void send_udp_connect();
void connect_response(asio::error const& error, std::size_t bytes_transferred);
void connect_response(asio::error_code const& error, std::size_t bytes_transferred);
void send_udp_announce();
void announce_response(asio::error const& error, std::size_t bytes_transferred);
void announce_response(asio::error_code const& error, std::size_t bytes_transferred);
void send_udp_scrape();
void scrape_response(asio::error const& error, std::size_t bytes_transferred);
void scrape_response(asio::error_code const& error, std::size_t bytes_transferred);
virtual void on_timeout();

View File

@ -34,8 +34,8 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_VERSION_HPP_INCLUDED
#define LIBTORRENT_VERSION_MAJOR 0
#define LIBTORRENT_VERSION_MINOR 11
#define LIBTORRENT_VERSION_MINOR 12
#define LIBTORRENT_VERSION "0.11.0.0"
#define LIBTORRENT_VERSION "0.12.0.0"
#endif

View File

@ -104,9 +104,9 @@ namespace libtorrent
// called from the main loop when this connection has any
// work to do.
void on_sent(asio::error const& error
void on_sent(asio::error_code const& error
, std::size_t bytes_transferred);
void on_receive(asio::error const& error
void on_receive(asio::error_code const& error
, std::size_t bytes_transferred);
std::string const& url() const { return m_url; }

View File

@ -7,7 +7,8 @@ piece_picker.cpp policy.cpp session.cpp session_impl.cpp sha1.cpp stat.cpp \
storage.cpp torrent.cpp torrent_handle.cpp \
torrent_info.cpp tracker_manager.cpp \
http_tracker_connection.cpp udp_tracker_connection.cpp \
alert.cpp identify_client.cpp ip_filter.cpp file.cpp \
alert.cpp identify_client.cpp ip_filter.cpp file.cpp metadata_transfer.cpp \
logger.cpp \
\
kademlia/closest_nodes.cpp \
kademlia/dht_tracker.cpp \

View File

@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/version.hpp"
#include "libtorrent/extensions.hpp"
#include "libtorrent/aux_/session_impl.hpp"
using namespace boost::posix_time;
@ -55,11 +56,6 @@ using libtorrent::aux::session_impl;
namespace libtorrent
{
// the names of the extensions to look for in
// the extensions-message
const char* bt_peer_connection::extension_names[] =
{ "", "LT_chat", "LT_metadata", "LT_peer_exchange" };
const bt_peer_connection::message_handler
bt_peer_connection::m_message_handler[] =
{
@ -85,17 +81,12 @@ namespace libtorrent
, tcp::endpoint const& remote)
: peer_connection(ses, tor, s, remote)
, m_state(read_protocol_length)
#ifndef TORRENT_DISABLE_EXTENSIONS
, m_supports_extensions(false)
#endif
, m_supports_dht_port(false)
, m_no_metadata(
boost::gregorian::date(1970, boost::date_time::Jan, 1)
, boost::posix_time::seconds(0))
, m_metadata_request(
boost::gregorian::date(1970, boost::date_time::Jan, 1)
, boost::posix_time::seconds(0))
, m_waiting_metadata_request(false)
, m_metadata_progress(0)
#ifndef NDEBUG
, m_sent_bitfield(false)
, m_in_constructor(true)
#endif
{
@ -103,11 +94,6 @@ namespace libtorrent
(*m_logger) << "*** bt_peer_connection\n";
#endif
// initialize the extension list to zero, since
// we don't know which extensions the other
// end supports yet
std::fill(m_extension_messages, m_extension_messages + num_supported_extensions, 0);
write_handshake();
// start in the state where we are trying to read the
@ -133,25 +119,15 @@ namespace libtorrent
, boost::shared_ptr<stream_socket> s)
: peer_connection(ses, s)
, m_state(read_protocol_length)
#ifndef TORRENT_DISABLE_EXTENSIONS
, m_supports_extensions(false)
#endif
, m_supports_dht_port(false)
, m_no_metadata(
boost::gregorian::date(1970, boost::date_time::Jan, 1)
, boost::posix_time::seconds(0))
, m_metadata_request(
boost::gregorian::date(1970, boost::date_time::Jan, 1)
, boost::posix_time::seconds(0))
, m_waiting_metadata_request(false)
, m_metadata_progress(0)
#ifndef NDEBUG
, m_sent_bitfield(false)
, m_in_constructor(true)
#endif
{
// initialize the extension list to zero, since
// we don't know which extensions the other
// end supports yet
std::fill(m_extension_messages, m_extension_messages + num_supported_extensions, 0);
// we are not attached to any torrent yet.
// we have to wait for the handshake to see
// which torrent the connector want's to connect to
@ -169,6 +145,13 @@ namespace libtorrent
{
}
void bt_peer_connection::on_metadata()
{
boost::shared_ptr<torrent> t = associated_torrent().lock();
assert(t);
write_bitfield(t->pieces());
}
void bt_peer_connection::write_dht_port(int listen_port)
{
INVARIANT_CHECK;
@ -268,18 +251,17 @@ namespace libtorrent
i.begin += string_len;
// 8 zeroes
std::fill(
i.begin
, i.begin + 8
, 0);
std::fill(i.begin, i.begin + 8, 0);
#ifndef TORRENT_DISABLE_DHT
// indicate that we support the DHT messages
*(i.begin + 7) = 0x01;
#endif
#ifndef TORRENT_DISABLE_EXTENSIONS
// we support extensions
*(i.begin + 5) = 0x10;
#endif
i.begin += 8;
@ -369,6 +351,14 @@ namespace libtorrent
m_statistics.received_bytes(0, received);
if (!packet_finished()) return;
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_choke()) return;
}
#endif
incoming_choke();
}
@ -386,6 +376,14 @@ namespace libtorrent
m_statistics.received_bytes(0, received);
if (!packet_finished()) return;
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_unchoke()) return;
}
#endif
incoming_unchoke();
}
@ -403,6 +401,14 @@ namespace libtorrent
m_statistics.received_bytes(0, received);
if (!packet_finished()) return;
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_interested()) return;
}
#endif
incoming_interested();
}
@ -420,6 +426,14 @@ namespace libtorrent
m_statistics.received_bytes(0, received);
if (!packet_finished()) return;
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_not_interested()) return;
}
#endif
incoming_not_interested();
}
@ -442,6 +456,14 @@ namespace libtorrent
const char* ptr = recv_buffer.begin + 1;
int index = detail::read_int32(ptr);
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_have(index)) return;
}
#endif
incoming_have(index);
}
@ -482,6 +504,15 @@ namespace libtorrent
// (since it doesn't exist yet)
for (int i = 0; i < (int)bitfield.size(); ++i)
bitfield[i] = (recv_buffer[1 + (i>>3)] & (1 << (7 - (i&7)))) != 0;
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_bitfield(bitfield)) return;
}
#endif
incoming_bitfield(bitfield);
}
@ -507,6 +538,14 @@ namespace libtorrent
r.start = detail::read_int32(ptr);
r.length = detail::read_int32(ptr);
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_request(r)) return;
}
#endif
incoming_request(r);
}
@ -551,6 +590,14 @@ namespace libtorrent
p.start = detail::read_int32(ptr);
p.length = packet_size() - 9;
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_piece(p, recv_buffer.begin + 9)) return;
}
#endif
incoming_piece(p, recv_buffer.begin + 9);
}
@ -576,6 +623,14 @@ namespace libtorrent
r.start = detail::read_int32(ptr);
r.length = detail::read_int32(ptr);
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_cancel(r)) return;
}
#endif
incoming_cancel(r);
}
@ -618,33 +673,33 @@ namespace libtorrent
throw protocol_error("'extended' message sent before proper handshake");
buffer::const_interval recv_buffer = receive_buffer();
if (recv_buffer.end - recv_buffer.begin < 2) return;
if (recv_buffer.left() < 2) return;
assert(*recv_buffer.begin == msg_extended);
++recv_buffer.begin;
int extended_id = detail::read_uint8(recv_buffer.begin);
if (extended_id > 0 && extended_id < num_supported_extensions
&& !m_ses.extension_enabled(extended_id))
throw protocol_error("'extended' message using disabled extension");
switch (extended_id)
if (extended_id == 0)
{
case extended_handshake:
on_extended_handshake(); break;
case extended_chat_message:
on_chat(); break;
case extended_metadata_message:
on_metadata(); break;
case extended_peer_exchange_message:
on_peer_exchange(); break;
default:
throw protocol_error("unknown extended message id: "
+ boost::lexical_cast<std::string>(extended_id));
};
}
on_extended_handshake();
return;
}
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_extended(packet_size() - 2, extended_id
, recv_buffer))
return;
}
#endif
throw protocol_error("unknown extended message id: "
+ boost::lexical_cast<std::string>(extended_id));
}
/*
void bt_peer_connection::write_chat_message(const std::string& msg)
{
INVARIANT_CHECK;
@ -669,9 +724,9 @@ namespace libtorrent
assert(i.begin == i.end);
setup_send();
}
*/
void bt_peer_connection::on_extended_handshake() try
void bt_peer_connection::on_extended_handshake()
{
if (!packet_finished()) return;
@ -679,35 +734,38 @@ namespace libtorrent
assert(t);
buffer::const_interval recv_buffer = receive_buffer();
entry root = bdecode(recv_buffer.begin + 2, recv_buffer.end);
#ifdef TORRENT_VERBOSE_LOGGING
entry root;
try
{
root = bdecode(recv_buffer.begin + 2, recv_buffer.end);
}
catch (std::exception& exc)
{
#ifdef TORRENT_VERBOSE_LOGGIGN
(*m_logger) << "invalid extended handshake: " << exc.what() << "\n";
#endif
return;
}
#ifdef TORRENT_VERBOSE_LOGGIGN
std::stringstream ext;
root.print(ext);
(*m_logger) << "<== EXTENDED HANDSHAKE: \n" << ext.str();
#endif
if (entry* msgs = root.find_key("m"))
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end;)
{
if (msgs->type() == entry::dictionary_t)
{
// this must be the initial handshake message
// lets see if any of our extensions are supported
// if not, we will signal no extensions support to the upper layer
for (int i = 1; i < num_supported_extensions; ++i)
{
if (entry* f = msgs->find_key(extension_names[i]))
{
m_extension_messages[i] = (int)f->integer();
}
else
{
m_extension_messages[i] = 0;
}
}
}
// a false return value means that the extension
// isn't supported by the other end. So, it is removed.
if (!(*i)->on_extension_handshake(root))
i = m_extensions.erase(i);
else
++i;
}
#endif
// there is supposed to be a remote listen port
if (entry* listen_port = root.find_key("p"))
@ -736,154 +794,6 @@ namespace libtorrent
m_max_out_request_queue = 1;
}
}
catch (std::exception& exc)
{
#ifdef TORRENT_VERBOSE_LOGGIGN
(*m_logger) << "invalid extended handshake: " << exc.what() << "\n";
#endif
}
// -----------------------------
// ----------- CHAT ------------
// -----------------------------
void bt_peer_connection::on_chat()
{
if (packet_size() > 2 * 1024)
throw protocol_error("CHAT message larger than 2 kB");
if (!packet_finished()) return;
try
{
boost::shared_ptr<torrent> t = associated_torrent().lock();
assert(t);
buffer::const_interval recv_buffer = receive_buffer();
entry d = bdecode(recv_buffer.begin + 2, recv_buffer.end);
const std::string& str = d["msg"].string();
if (t->alerts().should_post(alert::critical))
{
t->alerts().post_alert(
chat_message_alert(
t->get_handle()
, remote(), str));
}
}
catch (invalid_encoding&)
{
// TODO: post an alert about the invalid chat message
return;
// throw protocol_error("invalid bencoding in CHAT message");
}
catch (type_error&)
{
// TODO: post an alert about the invalid chat message
return;
// throw protocol_error("invalid types in bencoded CHAT message");
}
return;
}
// -----------------------------
// --------- METADATA ----------
// -----------------------------
void bt_peer_connection::on_metadata()
{
boost::shared_ptr<torrent> t = associated_torrent().lock();
assert(t);
if (packet_size() > 500 * 1024)
throw protocol_error("metadata message larger than 500 kB");
if (!packet_finished()) return;
buffer::const_interval recv_buffer = receive_buffer();
recv_buffer.begin += 2;
int type = detail::read_uint8(recv_buffer.begin);
switch (type)
{
case 0: // request
{
int start = detail::read_uint8(recv_buffer.begin);
int size = detail::read_uint8(recv_buffer.begin) + 1;
if (packet_size() != 5)
{
// invalid metadata request
throw protocol_error("invalid metadata request");
}
write_metadata(std::make_pair(start, size));
}
break;
case 1: // data
{
if (recv_buffer.end - recv_buffer.begin < 8) return;
int total_size = detail::read_int32(recv_buffer.begin);
int offset = detail::read_int32(recv_buffer.begin);
int data_size = packet_size() - 2 - 9;
if (total_size > 500 * 1024)
throw protocol_error("metadata size larger than 500 kB");
if (total_size <= 0)
throw protocol_error("invalid metadata size");
if (offset > total_size || offset < 0)
throw protocol_error("invalid metadata offset");
if (offset + data_size > total_size)
throw protocol_error("invalid metadata message");
t->metadata_progress(total_size
, recv_buffer.left() - m_metadata_progress);
m_metadata_progress = recv_buffer.left();
if (!packet_finished()) return;
#ifdef TORRENT_VERBOSE_LOGGING
using namespace boost::posix_time;
(*m_logger) << to_simple_string(second_clock::universal_time())
<< " <== METADATA [ tot: " << total_size << " offset: "
<< offset << " size: " << data_size << " ]\n";
#endif
m_waiting_metadata_request = false;
t->received_metadata(recv_buffer.begin, data_size
, offset, total_size);
m_metadata_progress = 0;
}
break;
case 2: // have no data
if (!packet_finished()) return;
m_no_metadata = second_clock::universal_time();
if (m_waiting_metadata_request)
t->cancel_metadata_request(m_last_metadata_request);
m_waiting_metadata_request = false;
break;
default:
throw protocol_error("unknown metadata extension message: "
+ boost::lexical_cast<std::string>(type));
}
}
// -----------------------------
// ------ PEER EXCHANGE --------
// -----------------------------
void bt_peer_connection::on_peer_exchange()
{
}
bool bt_peer_connection::has_metadata() const
{
using namespace boost::posix_time;
return second_clock::universal_time() - m_no_metadata > minutes(5);
}
bool bt_peer_connection::dispatch_message(int received)
{
@ -901,6 +811,17 @@ namespace libtorrent
|| packet_type >= num_supported_messages
|| m_message_handler[packet_type] == 0)
{
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_unknown_message(packet_size(), packet_type
, buffer::const_interval(recv_buffer.begin+1
, recv_buffer.end)))
return packet_finished();
}
#endif
throw protocol_error("unknown message id: "
+ boost::lexical_cast<std::string>(packet_type)
+ " size: " + boost::lexical_cast<std::string>(packet_size()));
@ -911,9 +832,7 @@ namespace libtorrent
// call the correct handler for this packet type
(this->*m_message_handler[packet_type])(received);
if (!packet_finished()) return false;
return true;
return packet_finished();
}
void bt_peer_connection::write_keepalive()
@ -972,103 +891,14 @@ namespace libtorrent
setup_send();
}
void bt_peer_connection::write_metadata(std::pair<int, int> req)
{
assert(req.first >= 0);
assert(req.second > 0);
assert(req.second <= 256);
assert(req.first + req.second <= 256);
assert(!associated_torrent().expired());
INVARIANT_CHECK;
// abort if the peer doesn't support the metadata extension
if (!supports_extension(extended_metadata_message)) return;
boost::shared_ptr<torrent> t = associated_torrent().lock();
assert(t);
if (t->valid_metadata())
{
std::pair<int, int> offset
= req_to_offset(req, (int)t->metadata().size());
buffer::interval i = allocate_send_buffer(15 + offset.second);
// yes, we have metadata, send it
detail::write_uint32(11 + offset.second, i.begin);
detail::write_uint8(msg_extended, i.begin);
detail::write_uint8(m_extension_messages[extended_metadata_message]
, i.begin);
// means 'data packet'
detail::write_uint8(1, i.begin);
detail::write_uint32((int)t->metadata().size(), i.begin);
detail::write_uint32(offset.first, i.begin);
std::vector<char> const& metadata = t->metadata();
std::copy(metadata.begin() + offset.first
, metadata.begin() + offset.first + offset.second, i.begin);
i.begin += offset.second;
assert(i.begin == i.end);
}
else
{
buffer::interval i = allocate_send_buffer(4 + 3);
// we don't have the metadata, reply with
// don't have-message
detail::write_uint32(1 + 2, i.begin);
detail::write_uint8(msg_extended, i.begin);
detail::write_uint8(m_extension_messages[extended_metadata_message]
, i.begin);
// means 'have no data'
detail::write_uint8(2, i.begin);
assert(i.begin == i.end);
}
setup_send();
}
void bt_peer_connection::write_metadata_request(std::pair<int, int> req)
{
assert(req.first >= 0);
assert(req.second > 0);
assert(req.first + req.second <= 256);
assert(!associated_torrent().expired());
assert(!associated_torrent().lock()->valid_metadata());
INVARIANT_CHECK;
int start = req.first;
int size = req.second;
// abort if the peer doesn't support the metadata extension
if (!supports_extension(extended_metadata_message)) return;
#ifdef TORRENT_VERBOSE_LOGGING
using namespace boost::posix_time;
(*m_logger) << to_simple_string(second_clock::universal_time())
<< " ==> METADATA_REQUEST [ start: " << req.first
<< " size: " << req.second << " ]\n";
#endif
buffer::interval i = allocate_send_buffer(9);
detail::write_uint32(1 + 1 + 3, i.begin);
detail::write_uint8(msg_extended, i.begin);
detail::write_uint8(m_extension_messages[extended_metadata_message]
, i.begin);
// means 'request data'
detail::write_uint8(0, i.begin);
detail::write_uint8(start, i.begin);
detail::write_uint8(size - 1, i.begin);
assert(i.begin == i.end);
setup_send();
}
void bt_peer_connection::write_bitfield(std::vector<bool> const& bitfield)
{
INVARIANT_CHECK;
boost::shared_ptr<torrent> t = associated_torrent().lock();
assert(t);
if (t->num_pieces() == 0) return;
assert(m_sent_bitfield == false);
assert(t->valid_metadata());
#ifdef TORRENT_VERBOSE_LOGGING
using namespace boost::posix_time;
@ -1096,9 +926,13 @@ namespace libtorrent
i.begin[c >> 3] |= 1 << (7 - (c & 7));
}
assert(i.end - i.begin == ((int)bitfield.size() + 7) / 8);
#ifndef NDEBUG
m_sent_bitfield = true;
#endif
setup_send();
}
#ifndef TORRENT_DISABLE_EXTENSIONS
void bt_peer_connection::write_extensions()
{
INVARIANT_CHECK;
@ -1113,14 +947,6 @@ namespace libtorrent
entry handshake(entry::dictionary_t);
entry extension_list(entry::dictionary_t);
for (int i = 1; i < num_supported_extensions; ++i)
{
// if this specific extension is disabled
// just don't add it to the supported set
if (!m_ses.extension_enabled(i)) continue;
extension_list[extension_names[i]] = i;
}
handshake["m"] = extension_list;
handshake["p"] = m_ses.listen_port();
handshake["v"] = m_ses.settings().user_agent;
@ -1130,6 +956,14 @@ namespace libtorrent
handshake["ip"] = remote_address;
handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue;
// loop backwards, to make the first extension be the last
// to fill in the handshake (i.e. give the first extensions priority)
for (extension_list_t::reverse_iterator i = m_extensions.rbegin()
, end(m_extensions.rend()); i != end; ++i)
{
(*i)->add_handshake(handshake);
}
std::vector<char> msg;
bencode(std::back_inserter(msg), handshake);
@ -1140,7 +974,7 @@ namespace libtorrent
detail::write_int32((int)msg.size() + 2, i.begin);
detail::write_uint8(msg_extended, i.begin);
// signal handshake message
detail::write_uint8(extended_handshake, i.begin);
detail::write_uint8(0, i.begin);
std::copy(msg.begin(), msg.end(), i.begin);
i.begin += msg.size();
@ -1154,6 +988,7 @@ namespace libtorrent
setup_send();
}
#endif
void bt_peer_connection::write_choke()
{
@ -1232,7 +1067,7 @@ namespace libtorrent
// --------------------------
// throws exception when the client should be disconnected
void bt_peer_connection::on_receive(const asio::error& error
void bt_peer_connection::on_receive(asio::error_code const& error
, std::size_t bytes_transferred)
{
INVARIANT_CHECK;
@ -1330,8 +1165,10 @@ namespace libtorrent
(*m_logger) << "supports LT/uT extensions\n";
#endif
if ((recv_buffer[5] & 0x10) && m_ses.extensions_enabled())
#ifndef DISABLE_EXTENSIONS
if ((recv_buffer[5] & 0x10))
m_supports_extensions = true;
#endif
if (recv_buffer[7] & 0x01)
m_supports_dht_port = true;
@ -1354,7 +1191,8 @@ namespace libtorrent
// yes, we found the torrent
// reply with our handshake
write_handshake();
write_bitfield(t->pieces());
if (t->valid_metadata())
write_bitfield(t->pieces());
}
else
{
@ -1369,6 +1207,8 @@ namespace libtorrent
}
}
#ifndef TORRENT_DISABLE_DHT
if (m_supports_dht_port && m_ses.m_dht)
write_dht_port(m_ses.kad_settings().service_port);
@ -1422,7 +1262,23 @@ namespace libtorrent
if (pid == m_ses.get_peer_id())
throw std::runtime_error("closing connection to ourself");
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end;)
{
if (!(*i)->on_handshake())
{
i = m_extensions.erase(i);
}
else
{
++i;
}
}
if (m_supports_extensions) write_extensions();
#endif
/*
if (!m_active)
{
@ -1487,7 +1343,7 @@ namespace libtorrent
// --------------------------
// throws exception when the client should be disconnected
void bt_peer_connection::on_sent(asio::error const& error
void bt_peer_connection::on_sent(asio::error_code const& error
, std::size_t bytes_transferred)
{
INVARIANT_CHECK;
@ -1528,7 +1384,7 @@ namespace libtorrent
m_statistics.sent_bytes(amount_payload, bytes_transferred - amount_payload);
}
/*
void bt_peer_connection::on_tick()
{
boost::shared_ptr<torrent> t = associated_torrent().lock();
@ -1549,7 +1405,7 @@ namespace libtorrent
m_metadata_request = second_clock::universal_time();
}
}
*/
#ifndef NDEBUG
void bt_peer_connection::check_invariant() const
{

View File

@ -34,8 +34,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <iomanip>
#include "libtorrent/entry.hpp"
#include "libtorrent/config.hpp"
#include <boost/bind.hpp>
#include <boost/next_prior.hpp>
#if defined(_MSC_VER)
namespace std
@ -139,52 +137,52 @@ namespace libtorrent
return (*this)[key.c_str()];
}
entry::entry(const dictionary_type& v)
entry::entry(dictionary_type const& v)
{
new(data) dictionary_type(v);
m_type = dictionary_t;
}
entry::entry(const string_type& v)
entry::entry(string_type const& v)
{
new(data) string_type(v);
m_type = string_t;
}
entry::entry(const list_type& v)
entry::entry(list_type const& v)
{
new(data) list_type(v);
m_type = list_t;
}
entry::entry(const integer_type& v)
entry::entry(integer_type const& v)
{
new(data) integer_type(v);
m_type = int_t;
}
void entry::operator=(const dictionary_type& v)
void entry::operator=(dictionary_type const& v)
{
destruct();
new(data) dictionary_type(v);
m_type = dictionary_t;
}
void entry::operator=(const string_type& v)
void entry::operator=(string_type const& v)
{
destruct();
new(data) string_type(v);
m_type = string_t;
}
void entry::operator=(const list_type& v)
void entry::operator=(list_type const& v)
{
destruct();
new(data) list_type(v);
m_type = list_t;
}
void entry::operator=(const integer_type& v)
void entry::operator=(integer_type const& v)
{
destruct();
new(data) integer_type(v);
@ -234,7 +232,7 @@ namespace libtorrent
}
}
void entry::copy(const entry& e)
void entry::copy(entry const& e)
{
m_type = e.m_type;
switch(m_type)

View File

@ -163,8 +163,12 @@ namespace libtorrent
wpath.c_str()
, map_open_mode(mode)
, S_IREAD | S_IWRITE);
#else
#ifdef _WIN32
m_fd = ::_open(
#else
m_fd = ::open(
#endif
utf8_native(path.native_file_string()).c_str()
, map_open_mode(mode)
#ifdef _WIN32
@ -187,7 +191,11 @@ namespace libtorrent
{
if (m_fd == -1) return;
#ifdef _WIN32
::_close(m_fd);
#else
::close(m_fd);
#endif
m_fd = -1;
m_open_mode = 0;
}
@ -197,7 +205,11 @@ namespace libtorrent
assert(m_open_mode & mode_in);
assert(m_fd != -1);
#ifdef _WIN32
size_type ret = ::_read(m_fd, buf, num_bytes);
#else
size_type ret = ::read(m_fd, buf, num_bytes);
#endif
if (ret == -1)
{
std::stringstream msg;
@ -217,7 +229,11 @@ namespace libtorrent
// if ((rand() % 100) > 80)
// throw file_error("debug");
#ifdef _WIN32
size_type ret = ::_write(m_fd, buf, num_bytes);
#else
size_type ret = ::write(m_fd, buf, num_bytes);
#endif
if (ret == -1)
{
std::stringstream msg;

View File

@ -389,7 +389,7 @@ namespace libtorrent
fail_timeout();
}
void http_tracker_connection::name_lookup(asio::error const& error
void http_tracker_connection::name_lookup(asio::error_code const& error
, tcp::resolver::iterator i) try
{
if (error == asio::error::operation_aborted) return;
@ -397,7 +397,7 @@ namespace libtorrent
if (error || i == tcp::resolver::iterator())
{
fail(-1, error.what());
fail(-1, error.message().c_str());
return;
}
@ -416,13 +416,13 @@ namespace libtorrent
fail(-1, e.what());
};
void http_tracker_connection::connected(asio::error const& error) try
void http_tracker_connection::connected(asio::error_code const& error) try
{
if (error == asio::error::operation_aborted) return;
if (m_timed_out) return;
if (error)
{
fail(-1, error.what());
fail(-1, error.message().c_str());
return;
}
@ -441,13 +441,13 @@ namespace libtorrent
fail(-1, e.what());
}
void http_tracker_connection::sent(asio::error const& error) try
void http_tracker_connection::sent(asio::error_code const& error) try
{
if (error == asio::error::operation_aborted) return;
if (m_timed_out) return;
if (error)
{
fail(-1, error.what());
fail(-1, error.message().c_str());
return;
}
@ -467,7 +467,7 @@ namespace libtorrent
}; // msvc 7.1 seems to require this semi-colon
void http_tracker_connection::receive(asio::error const& error
void http_tracker_connection::receive(asio::error_code const& error
, std::size_t bytes_transferred) try
{
if (error == asio::error::operation_aborted) return;
@ -482,7 +482,7 @@ namespace libtorrent
return;
}
fail(-1, error.what());
fail(-1, error.message().c_str());
return;
}

View File

@ -208,7 +208,7 @@ namespace libtorrent { namespace dht
s.m_dht_torrents = m_dht.data_size();
}
void dht_tracker::connection_timeout(asio::error const& e)
void dht_tracker::connection_timeout(asio::error_code const& e)
try
{
if (e) return;
@ -216,12 +216,12 @@ namespace libtorrent { namespace dht
m_connection_timer.expires_from_now(d);
m_connection_timer.async_wait(bind(&dht_tracker::connection_timeout, this, _1));
}
catch (std::exception&)
catch (std::exception& exc)
{
assert(false);
};
void dht_tracker::refresh_timeout(asio::error const& e)
void dht_tracker::refresh_timeout(asio::error_code const& e)
try
{
if (e) return;
@ -241,7 +241,7 @@ namespace libtorrent { namespace dht
m_socket.bind(udp::endpoint(listen_interface, listen_port));
}
void dht_tracker::tick(asio::error const& e)
void dht_tracker::tick(asio::error_code const& e)
try
{
if (e) return;
@ -346,7 +346,7 @@ namespace libtorrent { namespace dht
// translate bittorrent kademlia message into the generice kademlia message
// used by the library
void dht_tracker::on_receive(asio::error const& error, size_t bytes_transferred)
void dht_tracker::on_receive(asio::error_code const& error, size_t bytes_transferred)
try
{
if (error == asio::error::operation_aborted) return;
@ -652,7 +652,7 @@ namespace libtorrent { namespace dht
, this, _1, _2));
}
void dht_tracker::on_name_lookup(asio::error const& e
void dht_tracker::on_name_lookup(asio::error_code const& e
, udp::resolver::iterator host) try
{
if (e || host == udp::resolver::iterator()) return;
@ -670,7 +670,7 @@ namespace libtorrent { namespace dht
, this, _1, _2));
}
void dht_tracker::on_router_name_lookup(asio::error const& e
void dht_tracker::on_router_name_lookup(asio::error_code const& e
, udp::resolver::iterator host) try
{
if (e || host == udp::resolver::iterator()) return;

231
src/logger.cpp Normal file
View File

@ -0,0 +1,231 @@
/*
Copyright (c) 2006, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef _MSC_VER
#pragma warning(push, 1)
#endif
#include <boost/shared_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include <vector>
#include "libtorrent/extensions/logger.hpp"
#include "libtorrent/extensions.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/peer_connection.hpp"
namespace libtorrent { namespace
{
struct logger_peer_plugin : peer_plugin
{
logger_peer_plugin(std::string const& filename)
{
using namespace boost::filesystem;
path dir(complete("libtorrent_ext_logs"));
if (!exists(dir)) create_directories(dir);
m_file.open(dir / filename, std::ios_base::out | std::ios_base::out);
m_file << "\n\n\n";
log_timestamp();
m_file << "*** starting log ***\n";
}
void log_timestamp()
{
using namespace boost::posix_time;
std::string now(to_simple_string(second_clock::universal_time()));
m_file << now << ": ";
}
// can add entries to the extension handshake
virtual void add_handshake(entry&) {}
// called when the extension handshake from the other end is received
virtual bool on_extension_handshake(entry const& h)
{
log_timestamp();
m_file << "<== EXTENSION_HANDSHAKE\n";
h.print(m_file);
return true;
}
// returning true from any of the message handlers
// indicates that the plugin has handeled the message.
// it will break the plugin chain traversing and not let
// anyone else handle the message, including the default
// handler.
virtual bool on_choke()
{
log_timestamp();
m_file << "<== CHOKE\n";
m_file.flush();
return false;
}
virtual bool on_unchoke()
{
log_timestamp();
m_file << "<== UNCHOKE\n";
m_file.flush();
return false;
}
virtual bool on_interested()
{
log_timestamp();
m_file << "<== INTERESTED\n";
m_file.flush();
return false;
}
virtual bool on_not_interested()
{
log_timestamp();
m_file << "<== NOT_INTERESTED\n";
m_file.flush();
return false;
}
virtual bool on_have(int index)
{
log_timestamp();
m_file << "<== HAVE [" << index << "]\n";
m_file.flush();
return false;
}
virtual bool on_bitfield(std::vector<bool> const& bitfield)
{
log_timestamp();
m_file << "<== BITFIELD\n";
m_file.flush();
return false;
}
virtual bool on_request(peer_request const& r)
{
log_timestamp();
m_file << "<== REQUEST [ piece: " << r.piece << " | s: " << r.start
<< " | l: " << r.length << " ]\n";
m_file.flush();
return false;
}
virtual bool on_piece(peer_request const& r, char const*)
{
log_timestamp();
m_file << "<== PIECE [ piece: " << r.piece << " | s: " << r.start
<< " | l: " << r.length << " ]\n";
m_file.flush();
return false;
}
virtual bool on_cancel(peer_request const& r)
{
log_timestamp();
m_file << "<== CANCEL [ piece: " << r.piece << " | s: " << r.start
<< " | l: " << r.length << " ]\n";
m_file.flush();
return false;
}
// called when an extended message is received. If returning true,
// the message is not processed by any other plugin and if false
// is returned the next plugin in the chain will receive it to
// be able to handle it
virtual bool on_extended(int length
, int msg, buffer::const_interval body)
{ return false; }
virtual bool on_unknown_message(int length, int msg
, buffer::const_interval body)
{
if (body.left() < length) return false;
log_timestamp();
m_file << "<== UNKNOWN [ msg: " << msg
<< " | l: " << length << " ]\n";
m_file.flush();
return false;
}
virtual void on_piece_pass(int index)
{
log_timestamp();
m_file << "*** HASH PASSED *** [ piece: " << index << " ]\n";
m_file.flush();
}
virtual void on_piece_failed(int index)
{
log_timestamp();
m_file << "*** HASH FAILED *** [ piece: " << index << " ]\n";
m_file.flush();
}
private:
boost::filesystem::ofstream m_file;
};
struct logger_plugin : torrent_plugin
{
virtual boost::shared_ptr<peer_plugin> new_connection(
peer_connection* pc)
{
return boost::shared_ptr<peer_plugin>(new logger_peer_plugin(
pc->remote().address().to_string() + "_"
+ boost::lexical_cast<std::string>(pc->remote().port()) + ".log"));
}
};
} }
namespace libtorrent
{
boost::shared_ptr<torrent_plugin> create_logger_plugin(torrent*)
{
return boost::shared_ptr<torrent_plugin>(new logger_plugin());
}
}

555
src/metadata_transfer.cpp Normal file
View File

@ -0,0 +1,555 @@
/*
Copyright (c) 2006, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef _MSC_VER
#pragma warning(push, 1)
#endif
#include <boost/shared_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include <vector>
#include <utility>
#include <numeric>
#include "libtorrent/peer_connection.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp"
#include "libtorrent/extensions/metadata_transfer.hpp"
using boost::posix_time::second_clock;
namespace libtorrent { namespace
{
int div_round_up(int numerator, int denominator)
{
return (numerator + denominator - 1) / denominator;
}
std::pair<int, int> req_to_offset(std::pair<int, int> req, int total_size)
{
assert(req.first >= 0);
assert(req.second > 0);
assert(req.second <= 256);
assert(req.first + req.second <= 256);
int start = div_round_up(req.first * total_size, 256);
int size = div_round_up((req.first + req.second) * total_size, 256) - start;
return std::make_pair(start, size);
}
std::pair<int, int> offset_to_req(std::pair<int, int> offset, int total_size)
{
int start = offset.first * 256 / total_size;
int size = (offset.first + offset.second) * 256 / total_size - start;
std::pair<int, int> ret(start, size);
assert(start >= 0);
assert(size > 0);
assert(start <= 256);
assert(start + size <= 256);
// assert the identity of this function
#ifndef NDEBUG
std::pair<int, int> identity = req_to_offset(ret, total_size);
assert(offset == identity);
#endif
return ret;
}
struct metadata_plugin : torrent_plugin
{
metadata_plugin(torrent& t)
: m_torrent(t)
, m_metadata_progress(0)
, m_metadata_size(0)
{
m_requested_metadata.resize(256, 0);
}
virtual boost::shared_ptr<peer_plugin> new_connection(
peer_connection* pc);
std::vector<char> const& metadata() const
{
if (m_metadata.empty())
{
bencode(std::back_inserter(m_metadata)
, m_torrent.torrent_file().create_info_metadata());
assert(hasher(&m_metadata[0], m_metadata.size()).final()
== m_torrent.torrent_file().info_hash());
}
assert(!m_metadata.empty());
return m_metadata;
}
bool received_metadata(char const* buf, int size, int offset, int total_size)
{
if (m_torrent.valid_metadata()) return false;
if ((int)m_metadata.size() < total_size)
m_metadata.resize(total_size);
std::copy(
buf
, buf + size
, &m_metadata[offset]);
if (m_have_metadata.empty())
m_have_metadata.resize(256, false);
std::pair<int, int> req = offset_to_req(std::make_pair(offset, size)
, total_size);
assert(req.first + req.second <= (int)m_have_metadata.size());
std::fill(
m_have_metadata.begin() + req.first
, m_have_metadata.begin() + req.first + req.second
, true);
bool have_all = std::count(
m_have_metadata.begin()
, m_have_metadata.end()
, true) == 256;
if (!have_all) return false;
hasher h;
h.update(&m_metadata[0], (int)m_metadata.size());
sha1_hash info_hash = h.final();
if (info_hash != m_torrent.torrent_file().info_hash())
{
std::fill(
m_have_metadata.begin()
, m_have_metadata.begin() + req.first + req.second
, false);
m_metadata_progress = 0;
m_metadata_size = 0;
// TODO: allow plugins to post alerts
/*
if (m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(metadata_failed_alert(
get_handle(), "invalid metadata received from swarm"));
}
*/
return false;
}
entry metadata = bdecode(m_metadata.begin(), m_metadata.end());
m_torrent.set_metadata(metadata);
// clear the storage for the bitfield
std::vector<bool>().swap(m_have_metadata);
std::vector<int>().swap(m_requested_metadata);
return true;
}
// returns a range of the metadata that
// we should request.
std::pair<int, int> metadata_request();
void cancel_metadata_request(std::pair<int, int> req)
{
for (int i = req.first; i < req.first + req.second; ++i)
{
assert(m_requested_metadata[i] > 0);
if (m_requested_metadata[i] > 0)
--m_requested_metadata[i];
}
}
// this is called from the peer_connection for
// each piece of metadata it receives
void metadata_progress(int total_size, int received)
{
m_metadata_progress += received;
m_metadata_size = total_size;
}
private:
torrent& m_torrent;
// this buffer is filled with the info-section of
// the metadata file while downloading it from
// peers, and while sending it.
// it is mutable because it's generated lazily
mutable std::vector<char> m_metadata;
int m_metadata_progress;
int m_metadata_size;
// this is a bitfield of size 256, each bit represents
// a piece of the metadata. It is set to one if we
// have that piece. This vector may be empty
// (size 0) if we haven't received any metadata
// or if we already have all metadata
std::vector<bool> m_have_metadata;
// this vector keeps track of how many times each meatdata
// block has been requested
std::vector<int> m_requested_metadata;
};
struct metadata_peer_plugin : peer_plugin
{
metadata_peer_plugin(torrent& t, peer_connection& pc
, metadata_plugin& tp)
: m_waiting_metadata_request(false)
, m_message_index(0)
, m_metadata_progress(0)
, m_no_metadata(
boost::gregorian::date(1970, boost::date_time::Jan, 1)
, boost::posix_time::seconds(0))
, m_metadata_request(
boost::gregorian::date(1970, boost::date_time::Jan, 1)
, boost::posix_time::seconds(0))
, m_torrent(t)
, m_pc(pc)
, m_tp(tp)
{}
// can add entries to the extension handshake
virtual void add_handshake(entry& h)
{
entry& messages = h["m"];
messages["LT_metadata"] = 14;
}
// called when the extension handshake from the other end is received
virtual bool on_extension_handshake(entry const& h)
{
entry const& messages = h["m"];
if (entry const* index = messages.find_key("LT_metadata"))
{
m_message_index = index->integer();
return true;
}
else
{
m_message_index = 0;
return false;
}
}
void write_metadata_request(std::pair<int, int> req)
{
assert(req.first >= 0);
assert(req.second > 0);
assert(req.first + req.second <= 256);
assert(!m_pc.associated_torrent().expired());
assert(!m_pc.associated_torrent().lock()->valid_metadata());
int start = req.first;
int size = req.second;
// abort if the peer doesn't support the metadata extension
if (m_message_index == 0) return;
buffer::interval i = m_pc.allocate_send_buffer(9);
detail::write_uint32(1 + 1 + 3, i.begin);
detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
detail::write_uint8(m_message_index, i.begin);
// means 'request data'
detail::write_uint8(0, i.begin);
detail::write_uint8(start, i.begin);
detail::write_uint8(size - 1, i.begin);
assert(i.begin == i.end);
m_pc.setup_send();
}
void write_metadata(std::pair<int, int> req)
{
assert(req.first >= 0);
assert(req.second > 0);
assert(req.second <= 256);
assert(req.first + req.second <= 256);
assert(!m_pc.associated_torrent().expired());
// abort if the peer doesn't support the metadata extension
if (m_message_index == 0) return;
if (m_torrent.valid_metadata())
{
std::pair<int, int> offset
= req_to_offset(req, (int)m_tp.metadata().size());
buffer::interval i = m_pc.allocate_send_buffer(15 + offset.second);
// yes, we have metadata, send it
detail::write_uint32(11 + offset.second, i.begin);
detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
detail::write_uint8(m_message_index, i.begin);
// means 'data packet'
detail::write_uint8(1, i.begin);
detail::write_uint32((int)m_tp.metadata().size(), i.begin);
detail::write_uint32(offset.first, i.begin);
std::vector<char> const& metadata = m_tp.metadata();
std::copy(metadata.begin() + offset.first
, metadata.begin() + offset.first + offset.second, i.begin);
i.begin += offset.second;
assert(i.begin == i.end);
}
else
{
buffer::interval i = m_pc.allocate_send_buffer(4 + 3);
// we don't have the metadata, reply with
// don't have-message
detail::write_uint32(1 + 2, i.begin);
detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
detail::write_uint8(m_message_index, i.begin);
// means 'have no data'
detail::write_uint8(2, i.begin);
assert(i.begin == i.end);
}
m_pc.setup_send();
}
virtual bool on_extended(int length
, int msg, buffer::const_interval body)
{
if (msg != 14) return false;
if (m_message_index == 0) return false;
if (length > 500 * 1024)
throw protocol_error("LT_metadata message larger than 500 kB");
if (body.left() < 1) return true;
int type = detail::read_uint8(body.begin);
switch (type)
{
case 0: // request
{
if (body.left() < 2) return true;
int start = detail::read_uint8(body.begin);
int size = detail::read_uint8(body.begin) + 1;
if (length != 3)
{
// invalid metadata request
throw protocol_error("invalid metadata request");
}
write_metadata(std::make_pair(start, size));
}
break;
case 1: // data
{
if (body.left() < 8) return true;
int total_size = detail::read_int32(body.begin);
int offset = detail::read_int32(body.begin);
int data_size = length - 9;
if (total_size > 500 * 1024)
throw protocol_error("metadata size larger than 500 kB");
if (total_size <= 0)
throw protocol_error("invalid metadata size");
if (offset > total_size || offset < 0)
throw protocol_error("invalid metadata offset");
if (offset + data_size > total_size)
throw protocol_error("invalid metadata message");
m_tp.metadata_progress(total_size
, body.left() - m_metadata_progress);
m_metadata_progress = body.left();
if (body.left() < data_size) return true;
m_waiting_metadata_request = false;
m_tp.received_metadata(body.begin, data_size
, offset, total_size);
m_metadata_progress = 0;
}
break;
case 2: // have no data
m_no_metadata = second_clock::universal_time();
if (m_waiting_metadata_request)
m_tp.cancel_metadata_request(m_last_metadata_request);
m_waiting_metadata_request = false;
break;
default:
throw protocol_error("unknown metadata extension message: "
+ boost::lexical_cast<std::string>(type));
}
return true;
}
virtual void tick()
{
// if we don't have any metadata, and this peer
// supports the request metadata extension
// and we aren't currently waiting for a request
// reply. Then, send a request for some metadata.
if (!m_torrent.valid_metadata()
&& m_message_index != 0
&& !m_waiting_metadata_request
&& has_metadata())
{
m_last_metadata_request = m_tp.metadata_request();
write_metadata_request(m_last_metadata_request);
m_waiting_metadata_request = true;
m_metadata_request = second_clock::universal_time();
}
}
bool has_metadata() const
{
using namespace boost::posix_time;
return second_clock::universal_time() - m_no_metadata > minutes(5);
}
private:
// this is set to true when we send a metadata
// request to this peer, and reset to false when
// we receive a reply to our request.
bool m_waiting_metadata_request;
// this is the message index the remote peer uses
// for metadata extension messages.
int m_message_index;
// the number of bytes of metadata we have received
// so far from this per, only counting the current
// request. Any previously finished requests
// that have been forwarded to the torrent object
// do not count.
int m_metadata_progress;
// this is set to the current time each time we get a
// "I don't have metadata" message.
boost::posix_time::ptime m_no_metadata;
// this is set to the time when we last sent
// a request for metadata to this peer
boost::posix_time::ptime m_metadata_request;
// if we're waiting for a metadata request
// this was the request we sent
std::pair<int, int> m_last_metadata_request;
torrent& m_torrent;
peer_connection& m_pc;
metadata_plugin& m_tp;
};
boost::shared_ptr<peer_plugin> metadata_plugin::new_connection(
peer_connection* pc)
{
return boost::shared_ptr<peer_plugin>(new metadata_peer_plugin(m_torrent, *pc, *this));
}
std::pair<int, int> metadata_plugin::metadata_request()
{
// count the number of peers that supports the
// extension and that has metadata
int peers = 0;
#ifndef TORRENT_DISABLE_EXTENSIONS
typedef std::map<tcp::endpoint, peer_connection*> conn_map;
for (conn_map::iterator i = m_torrent.begin()
, end(m_torrent.end()); i != end; ++i)
{
bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(i->second);
if (c == 0) continue;
metadata_peer_plugin* p
= c->supports_extension<metadata_peer_plugin>();
if (p == 0) continue;
if (!p->has_metadata()) continue;
++peers;
}
#endif
// the number of blocks to request
int num_blocks = 256 / (peers + 1);
if (num_blocks < 1) num_blocks = 1;
assert(num_blocks <= 128);
int min_element = std::numeric_limits<int>::max();
int best_index = 0;
for (int i = 0; i < 256 - num_blocks + 1; ++i)
{
int min = *std::min_element(m_requested_metadata.begin() + i
, m_requested_metadata.begin() + i + num_blocks);
min += std::accumulate(m_requested_metadata.begin() + i
, m_requested_metadata.begin() + i + num_blocks, (int)0);
if (min_element > min)
{
best_index = i;
min_element = min;
}
}
std::pair<int, int> ret(best_index, num_blocks);
for (int i = ret.first; i < ret.first + ret.second; ++i)
m_requested_metadata[i]++;
assert(ret.first >= 0);
assert(ret.second > 0);
assert(ret.second <= 256);
assert(ret.first + ret.second <= 256);
return ret;
}
} }
namespace libtorrent
{
boost::shared_ptr<torrent_plugin> create_metadata_plugin(torrent* t)
{
return boost::shared_ptr<torrent_plugin>(new metadata_plugin(*t));
}
}

View File

@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/io.hpp"
#include "libtorrent/file.hpp"
#include "libtorrent/version.hpp"
#include "libtorrent/extensions.hpp"
#include "libtorrent/aux_/session_impl.hpp"
using namespace boost::posix_time;
@ -115,6 +116,8 @@ namespace libtorrent
, m_last_write_size(0)
, m_reading(false)
, m_last_read_size(0)
, m_prefer_whole_pieces(false)
, m_request_large_blocks(false)
, m_refs(0)
#ifndef NDEBUG
, m_in_constructor(true)
@ -204,6 +207,8 @@ namespace libtorrent
, m_last_write_size(0)
, m_reading(false)
, m_last_read_size(0)
, m_prefer_whole_pieces(false)
, m_request_large_blocks(false)
, m_refs(0)
#ifndef NDEBUG
, m_in_constructor(true)
@ -256,6 +261,14 @@ namespace libtorrent
std::fill(m_peer_id.begin(), m_peer_id.end(), 0);
}
#ifndef TORRENT_DISABLE_EXTENSIONS
void peer_connection::add_extension(boost::shared_ptr<peer_plugin> ext)
{
m_extensions.push_back(ext);
}
#endif
void peer_connection::init()
{
INVARIANT_CHECK;
@ -380,19 +393,35 @@ namespace libtorrent
return m_have_piece;
}
void peer_connection::received_valid_data()
void peer_connection::received_valid_data(int index)
{
INVARIANT_CHECK;
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
try { (*i)->on_piece_pass(index); } catch (std::exception&) {}
}
#endif
m_trust_points++;
// TODO: make this limit user settable
if (m_trust_points > 20) m_trust_points = 20;
}
void peer_connection::received_invalid_data()
void peer_connection::received_invalid_data(int index)
{
INVARIANT_CHECK;
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
try { (*i)->on_piece_failed(index); } catch (std::exception&) {}
}
#endif
// we decrease more than we increase, to keep the
// allowed failed/passed ratio low.
// TODO: make this limit user settable
@ -444,10 +473,12 @@ namespace libtorrent
&& p.start >= 0
&& (p.length == t->block_size()
|| (p.length < t->block_size()
&& p.piece == t->torrent_file().num_pieces()-1
&& p.start + p.length == t->torrent_file().piece_size(p.piece)))
&& p.piece == t->torrent_file().num_pieces()-1
&& p.start + p.length == t->torrent_file().piece_size(p.piece))
|| (m_request_large_blocks
&& p.length <= t->torrent_file().piece_size(p.piece)))
&& p.start + p.length <= t->torrent_file().piece_size(p.piece)
&& p.start % t->block_size() == 0;
&& (p.start % t->block_size() == 0);
}
struct disconnect_torrent
@ -709,7 +740,11 @@ namespace libtorrent
// verify the bitfield size
if (t->valid_metadata()
&& (bitfield.size() / 8) != (m_have_piece.size() / 8))
throw protocol_error("got bitfield with invalid size");
throw protocol_error("got bitfield with invalid size: "
+ boost::lexical_cast<std::string>(bitfield.size() / 8)
+ "bytes. expected: "
+ boost::lexical_cast<std::string>(m_have_piece.size() / 8)
+ "bytes");
// if we don't have metadata yet
// just remember the bitmask
@ -891,7 +926,6 @@ namespace libtorrent
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << to_simple_string(second_clock::universal_time())
<< " <== PIECE [ piece: " << p.piece << " | "
"b: " << p.start / t->block_size() << " | "
"s: " << p.start << " | "
"l: " << p.length << " | "
"ds: " << statistics().download_rate() << " | "
@ -915,91 +949,102 @@ namespace libtorrent
piece_picker& picker = t->picker();
piece_block block_finished(p.piece, p.start / t->block_size());
std::deque<piece_block>::iterator b
= std::find(
m_download_queue.begin()
, m_download_queue.end()
, block_finished);
std::deque<piece_block>::iterator i;
if (b != m_download_queue.end())
bool redundant = true;
for (;block_finished.block_index * t->block_size() < p.start + p.length;
++block_finished.block_index)
{
if (m_assume_fifo)
std::deque<piece_block>::iterator b
= std::find(
m_download_queue.begin()
, m_download_queue.end()
, block_finished);
std::deque<piece_block>::iterator i;
if (b != m_download_queue.end())
{
for (i = m_download_queue.begin();
i != b; ++i)
if (m_assume_fifo)
{
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << to_simple_string(second_clock::universal_time())
<< " *** SKIPPED_PIECE [ piece: " << i->piece_index << " | "
"b: " << i->block_index << " ] ***\n";
#endif
// since this piece was skipped, clear it and allow it to
// be requested from other peers
// TODO: send cancel?
picker.abort_download(*i);
for (i = m_download_queue.begin();
i != b; ++i)
{
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << to_simple_string(second_clock::universal_time())
<< " *** SKIPPED_PIECE [ piece: " << i->piece_index << " | "
"b: " << i->block_index << " ] ***\n";
#endif
// since this piece was skipped, clear it and allow it to
// be requested from other peers
// TODO: send cancel?
picker.abort_download(*i);
}
// remove the request that just finished
// from the download queue plus the
// skipped blocks.
m_download_queue.erase(m_download_queue.begin()
, boost::next(b));
}
// remove the request that just finished
// from the download queue plus the
// skipped blocks.
m_download_queue.erase(m_download_queue.begin()
, boost::next(b));
else
{
m_download_queue.erase(b);
}
send_block_requests();
}
else
{
m_download_queue.erase(b);
}
send_block_requests();
}
else
{
// cancel the block from the
// peer that has taken over it.
boost::optional<tcp::endpoint> peer
= t->picker().get_downloader(block_finished);
if (peer)
{
peer_connection* pc = t->connection_for(*peer);
if (pc && pc != this)
// cancel the block from the
// peer that has taken over it.
boost::optional<tcp::endpoint> peer
= t->picker().get_downloader(block_finished);
if (peer)
{
pc->cancel_request(block_finished);
peer_connection* pc = t->connection_for(*peer);
if (pc && pc != this)
{
pc->cancel_request(block_finished);
}
}
else
{
if (t->alerts().should_post(alert::debug))
{
t->alerts().post_alert(
peer_error_alert(
m_remote
, m_peer_id
, "got a block that was not requested"));
}
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " *** The block we just got was not in the "
"request queue ***\n";
#endif
}
}
// if the block we got is already finished, then ignore it
if (picker.is_finished(block_finished))
{
t->received_redundant_data(t->block_size());
}
else
{
if (t->alerts().should_post(alert::debug))
{
t->alerts().post_alert(
peer_error_alert(
m_remote
, m_peer_id
, "got a block that was not requested"));
}
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " *** The block we just got was not in the "
"request queue ***\n";
#endif
redundant = false;
}
picker.mark_as_finished(block_finished, m_remote);
t->get_policy().block_finished(*this, block_finished);
}
// if the block we got is already finished, then ignore it
if (picker.is_finished(block_finished))
{
t->received_redundant_data(p.length);
return;
}
if (redundant) return;
t->filesystem().write(data, p.piece, p.start, p.length);
bool was_seed = t->is_seed();
bool was_finished = picker.num_filtered() + t->num_pieces()
== t->torrent_file().num_pieces();
picker.mark_as_finished(block_finished, m_remote);
t->get_policy().block_finished(*this, block_finished);
// if the piece failed, this connection may be closed, and
// detached from the torrent. In that case m_torrent will
@ -1256,11 +1301,9 @@ namespace libtorrent
&& (int)m_download_queue.size() < m_desired_queue_size)
{
piece_block block = m_request_queue.front();
m_request_queue.pop_front();
m_download_queue.push_back(block);
int block_offset = block.block_index * t->block_size();
int block_size = std::min((int)t->torrent_file().piece_size(
int block_size = std::min((int)t->torrent_file().piece_size(
block.piece_index) - block_offset, t->block_size());
assert(block_size > 0);
assert(block_size <= t->block_size());
@ -1270,19 +1313,68 @@ namespace libtorrent
r.start = block_offset;
r.length = block_size;
m_request_queue.pop_front();
m_download_queue.push_back(block);
/*
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << to_simple_string(second_clock::universal_time())
<< " *** REQUEST-QUEUE** [ "
"piece: " << block.piece_index << " | "
"block: " << block.block_index << " ]\n";
#endif
*/
// if we are requesting large blocks, merge the smaller
// blocks that are in the same piece into larger requests
if (m_request_large_blocks)
{
while (!m_request_queue.empty()
&& m_request_queue.front().piece_index == r.piece
&& m_request_queue.front().block_index == block.block_index + 1)
{
block = m_request_queue.front();
m_request_queue.pop_front();
m_download_queue.push_back(block);
/*
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << to_simple_string(second_clock::universal_time())
<< " *** REQUEST-QUEUE** [ "
"piece: " << block.piece_index << " | "
"block: " << block.block_index << " ]\n";
#endif
*/
block_offset = block.block_index * t->block_size();
block_size = std::min((int)t->torrent_file().piece_size(
block.piece_index) - block_offset, t->block_size());
assert(block_size > 0);
assert(block_size <= t->block_size());
r.length += block_size;
}
}
assert(verify_piece(r));
write_request(r);
#ifndef TORRENT_DISABLE_EXTENSIONS
bool handled = false;
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if (handled = (*i)->write_request(r)) break;
}
if (!handled) write_request(r);
#else
write_request(r);
#endif
using namespace boost::posix_time;
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << to_simple_string(second_clock::universal_time())
<< " ==> REQUEST [ "
"piece: " << block.piece_index << " | "
"b: " << block.block_index << " | "
"s: " << block_offset << " | "
"l: " << block_size << " | "
"ds: " << statistics().download_rate() << " | "
"piece: " << r.piece << " | "
"s: " << r.start << " | "
"l: " << r.length << " | "
"ds: " << statistics().download_rate() << " B/s | "
"qs: " << m_desired_queue_size << " ]\n";
#endif
}
@ -1292,7 +1384,8 @@ namespace libtorrent
void close_socket_ignore_error(boost::shared_ptr<stream_socket> s)
{
s->close(asio::ignore_error());
asio::error_code e;
s->close(e);
}
void peer_connection::disconnect()
@ -1405,6 +1498,14 @@ namespace libtorrent
on_tick();
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
(*i)->tick();
}
#endif
if (!t->valid_metadata()) return;
// calculate the desired download queue size
@ -1415,7 +1516,8 @@ namespace libtorrent
// the minimum number of requests is 2 and the maximum is 48
// the block size doesn't have to be 16. So we first query the
// torrent for it
const int block_size = t->block_size();
const int block_size = m_request_large_blocks
? t->torrent_file().piece_length() : t->block_size();
assert(block_size > 0);
m_desired_queue_size = static_cast<int>(queue_time
@ -1719,7 +1821,7 @@ namespace libtorrent
// --------------------------
// throws exception when the client should be disconnected
void peer_connection::on_receive_data(const asio::error& error
void peer_connection::on_receive_data(const asio::error_code& error
, std::size_t bytes_transferred) try
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
@ -1737,10 +1839,10 @@ namespace libtorrent
if (error)
{
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << "**ERROR**: " << error.what() << "\n";
(*m_logger) << "**ERROR**: " << error.message() << "\n";
#endif
on_receive(error, bytes_transferred);
throw std::runtime_error(error.what());
throw std::runtime_error(error.message());
}
if (m_disconnecting) return;
@ -1847,7 +1949,7 @@ namespace libtorrent
}
}
void peer_connection::on_connection_complete(asio::error const& e) try
void peer_connection::on_connection_complete(asio::error_code const& e) try
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
@ -1858,7 +1960,7 @@ namespace libtorrent
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_ses.m_logger) << "CONNECTION FAILED: " << m_remote.address().to_string() << "\n";
#endif
m_ses.connection_failed(m_socket, m_remote, e.what());
m_ses.connection_failed(m_socket, m_remote, e.message().c_str());
return;
}
@ -1894,7 +1996,7 @@ namespace libtorrent
// --------------------------
// throws exception when the client should be disconnected
void peer_connection::on_send_data(asio::error const& error
void peer_connection::on_send_data(asio::error_code const& error
, std::size_t bytes_transferred) try
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
@ -1912,9 +2014,9 @@ namespace libtorrent
if (error)
{
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << "**ERROR**: " << error.what() << "\n";
(*m_logger) << "**ERROR**: " << error.message() << "\n";
#endif
throw std::runtime_error(error.what());
throw std::runtime_error(error.message());
}
if (m_disconnecting) return;

View File

@ -86,6 +86,20 @@ namespace
std::vector<piece_block> interesting_pieces;
interesting_pieces.reserve(100);
bool prefer_whole_pieces = c.prefer_whole_pieces();
if (!prefer_whole_pieces)
{
prefer_whole_pieces = c.statistics().download_payload_rate()
* t.settings().whole_pieces_threshold
> t.torrent_file().piece_length();
}
// if we prefer whole pieces, the piece picker will pick at least
// the number of blocks we want, but it will try to make the picked
// blocks be from whole pieces, possibly by returning more blocks
// than we requested.
assert(c.remote() == c.get_socket()->remote_endpoint());
// picks the interesting pieces from this peer
// the integer is the number of pieces that
// should be guaranteed to be available for download
@ -94,17 +108,6 @@ namespace
// the last argument is if we should prefer whole pieces
// for this peer. If we're downloading one piece in 20 seconds
// then use this mode.
bool prefer_whole_pieces = c.statistics().download_payload_rate()
* t.settings().whole_pieces_threshold
> t.torrent_file().piece_length();
// if we prefer whole pieces, the piece picker will pick at least
// the number of blocks we want, but it will try to make the picked
// blocks be from whole pieces, possibly by returning more blocks
// than we requested.
#ifndef NDEBUG
assert(c.remote() == c.get_socket()->remote_endpoint());
#endif
p.pick_pieces(c.get_bitfield(), interesting_pieces
, num_requests, prefer_whole_pieces, c.remote());

View File

@ -123,9 +123,9 @@ namespace libtorrent
m_impl->abort();
}
void session::disable_extensions()
void session::add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*)> ext)
{
m_impl->disable_extensions();
m_impl->add_extension(ext);
}
void session::set_ip_filter(ip_filter const& f)
@ -143,15 +143,16 @@ namespace libtorrent
m_impl->set_key(key);
}
void session::enable_extension(extension_index i)
{
m_impl->enable_extension(i);
}
std::vector<torrent_handle> session::get_torrents() const
{
return m_impl->get_torrents();
}
torrent_handle session::find_torrent(sha1_hash const& info_hash) const
{
return m_impl->find_torrent_handle(info_hash);
}
// if the torrent already exists, this will throw duplicate_torrent
torrent_handle session::add_torrent(
@ -168,12 +169,13 @@ namespace libtorrent
torrent_handle session::add_torrent(
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, boost::filesystem::path const& save_path
, entry const& e
, bool compact_mode
, int block_size)
{
return m_impl->add_torrent(tracker_url, info_hash, save_path, e
return m_impl->add_torrent(tracker_url, info_hash, name, save_path, e
, compact_mode, block_size);
}

View File

@ -486,10 +486,8 @@ namespace libtorrent { namespace detail
using boost::posix_time::to_simple_string;
(*m_logger) << to_simple_string(second_clock::universal_time()) << "\n";
#endif
std::fill(m_extension_enabled, m_extension_enabled
+ num_supported_extensions, true);
// ---- generate a peer id ----
// ---- generate a peer id ----
std::srand((unsigned int)std::time(0));
m_key = rand() + (rand() << 15) + (rand() << 30);
@ -520,6 +518,14 @@ namespace libtorrent { namespace detail
m_checker_thread.reset(new boost::thread(boost::ref(m_checker_impl)));
}
#ifndef TORRENT_DISABLE_EXTENSIONS
void session_impl::add_extension(
boost::function<boost::shared_ptr<torrent_plugin>(torrent*)> ext)
{
m_extensions.push_back(ext);
}
#endif
#ifndef TORRENT_DISABLE_DHT
void session_impl::add_dht_node(udp::endpoint n)
{
@ -565,13 +571,6 @@ namespace libtorrent { namespace detail
}
}
bool session_impl::extensions_enabled() const
{
const int n = num_supported_extensions;
return std::find(m_extension_enabled
, m_extension_enabled + n, true) != m_extension_enabled + n;
}
void session_impl::set_settings(session_settings const& s)
{
mutex_t::scoped_lock l(m_mutex);
@ -599,7 +598,7 @@ namespace libtorrent { namespace detail
m_listen_socket->listen();
break;
}
catch (asio::error& e)
catch (asio::system_error& e)
{
// TODO: make sure this is correct
if (e.code() == asio::error::host_not_found)
@ -637,7 +636,7 @@ namespace libtorrent { namespace detail
}
}
}
catch (asio::error& e)
catch (asio::system_error& e)
{
if (m_alerts.should_post(alert::fatal))
{
@ -693,7 +692,7 @@ namespace libtorrent { namespace detail
}
void session_impl::on_incoming_connection(shared_ptr<stream_socket> const& s
, weak_ptr<socket_acceptor> const& listen_socket, asio::error const& e) try
, weak_ptr<socket_acceptor> const& listen_socket, asio::error_code const& e) try
{
if (listen_socket.expired())
return;
@ -864,14 +863,14 @@ namespace libtorrent { namespace detail
m_key = key;
}
void session_impl::second_tick(asio::error const& e) try
void session_impl::second_tick(asio::error_code const& e) try
{
session_impl::mutex_t::scoped_lock l(m_mutex);
if (e)
{
#if defined(TORRENT_LOGGING)
(*m_logger) << "*** SECOND TIMER FAILED " << e.what() << "\n";
(*m_logger) << "*** SECOND TIMER FAILED " << e.message() << "\n";
#endif
m_abort = true;
m_selector.interrupt();
@ -1138,21 +1137,6 @@ namespace libtorrent { namespace detail
}
#endif
void session_impl::disable_extensions()
{
mutex_t::scoped_lock l(m_mutex);
std::fill(m_extension_enabled, m_extension_enabled
+ num_supported_extensions, false);
}
void session_impl::enable_extension(extension_index i)
{
assert(i >= 0);
assert(i < num_supported_extensions);
mutex_t::scoped_lock l(m_mutex);
m_extension_enabled[i] = true;
}
std::vector<torrent_handle> session_impl::get_torrents()
{
mutex_t::scoped_lock l(m_mutex);
@ -1167,6 +1151,15 @@ namespace libtorrent { namespace detail
, (*i)->info_hash));
}
for (std::deque<boost::shared_ptr<aux::piece_checker_data> >::iterator i
= m_checker_impl.m_processing.begin()
, end(m_checker_impl.m_processing.end()); i != end; ++i)
{
if ((*i)->abort) continue;
ret.push_back(torrent_handle(this, &m_checker_impl
, (*i)->info_hash));
}
for (session_impl::torrent_map::iterator i
= m_torrents.begin(), end(m_torrents.end());
i != end; ++i)
@ -1178,6 +1171,11 @@ namespace libtorrent { namespace detail
return ret;
}
torrent_handle session_impl::find_torrent_handle(sha1_hash const& info_hash)
{
return torrent_handle(this, &m_checker_impl, info_hash);
}
torrent_handle session_impl::add_torrent(
torrent_info const& ti
, boost::filesystem::path const& save_path
@ -1225,6 +1223,14 @@ namespace libtorrent { namespace detail
, m_listen_interface, compact_mode, block_size
, settings()));
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
torrent_ptr->add_extension((*i)(torrent_ptr.get()));
}
#endif
boost::shared_ptr<aux::piece_checker_data> d(
new aux::piece_checker_data);
d->torrent_ptr = torrent_ptr;
@ -1255,6 +1261,7 @@ namespace libtorrent { namespace detail
torrent_handle session_impl::add_torrent(
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, boost::filesystem::path const& save_path
, entry const&
, bool compact_mode
@ -1286,10 +1293,6 @@ namespace libtorrent { namespace detail
// lock the session
session_impl::mutex_t::scoped_lock l(m_mutex);
// the metadata extension has to be enabled for this to work
assert(m_extension_enabled
[extended_metadata_message]);
// is the torrent already active?
if (!find_torrent(info_hash).expired())
throw duplicate_torrent();
@ -1301,10 +1304,18 @@ namespace libtorrent { namespace detail
// the checker thread and store it before starting
// the thread
boost::shared_ptr<torrent> torrent_ptr(
new torrent(*this, m_checker_impl, tracker_url, info_hash, save_path
, m_listen_interface, compact_mode, block_size
new torrent(*this, m_checker_impl, tracker_url, info_hash, name
, save_path, m_listen_interface, compact_mode, block_size
, settings()));
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
torrent_ptr->add_extension((*i)(torrent_ptr.get()));
}
#endif
m_torrents.insert(
std::make_pair(info_hash, torrent_ptr)).first;

View File

@ -66,6 +66,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert.hpp"
#include "libtorrent/identify_client.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/extensions.hpp"
#include "libtorrent/aux_/session_impl.hpp"
using namespace libtorrent;
@ -234,8 +235,6 @@ namespace libtorrent
, m_download_bandwidth_limit(std::numeric_limits<int>::max())
, m_save_path(complete(save_path))
, m_compact_mode(compact_mode)
, m_metadata_progress(0)
, m_metadata_size(0)
, m_default_block_size(block_size)
, m_connections_initialized(true)
, m_settings(s)
@ -294,6 +293,7 @@ namespace libtorrent
, aux::checker_impl& checker
, char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, boost::filesystem::path const& save_path
, tcp::endpoint const& net_interface
, bool compact_mode
@ -333,8 +333,6 @@ namespace libtorrent
, m_download_bandwidth_limit(std::numeric_limits<int>::max())
, m_save_path(complete(save_path))
, m_compact_mode(compact_mode)
, m_metadata_progress(0)
, m_metadata_size(0)
, m_default_block_size(block_size)
, m_connections_initialized(false)
, m_settings(s)
@ -344,6 +342,8 @@ namespace libtorrent
#endif
INVARIANT_CHECK;
if (name) m_name.reset(new std::string(name));
m_uploads_quota.min = 2;
m_connections_quota.min = 2;
// this will be corrected the next time the main session
@ -378,7 +378,6 @@ namespace libtorrent
}
m_trackers.push_back(announce_entry(tracker_url));
m_requested_metadata.resize(256, 0);
m_policy.reset(new policy(this));
m_torrent_file.add_tracker(tracker_url);
@ -409,6 +408,20 @@ namespace libtorrent
disconnect_all();
}
std::string torrent::name() const
{
if (valid_metadata()) return m_torrent_file.name();
if (m_name) return *m_name;
return "";
}
#ifndef TORRENT_DISABLE_EXTENSIONS
void torrent::add_extension(boost::shared_ptr<torrent_plugin> ext)
{
m_extensions.push_back(ext);
}
#endif
void torrent::init()
{
INVARIANT_CHECK;
@ -446,7 +459,7 @@ namespace libtorrent
tor->on_dht_announce_response(peers);
}
void torrent::on_dht_announce(asio::error const& e)
void torrent::on_dht_announce(asio::error_code const& e)
{
if (e) return;
m_dht_announce_timer.expires_from_now(boost::posix_time::minutes(30));
@ -736,12 +749,20 @@ namespace libtorrent
std::set<tcp::endpoint> peers;
std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
try { (*i)->on_piece_failed(index); } catch (std::exception&) {}
}
#endif
for (std::set<tcp::endpoint>::iterator i = peers.begin()
, end(peers.end()); i != end; ++i)
{
peer_iterator p = m_connections.find(*i);
if (p == m_connections.end()) continue;
p->second->received_invalid_data();
p->second->received_invalid_data(index);
// either, we have received too many failed hashes
// or this was the only peer that sent us this piece.
@ -817,12 +838,20 @@ namespace libtorrent
{
peer_iterator p = m_connections.find(*i);
if (p == m_connections.end()) continue;
p->second->received_valid_data();
p->second->received_valid_data(index);
}
m_picker->we_have(index);
for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i)
i->second->announce_piece(index);
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
try { (*i)->on_piece_pass(index); } catch (std::exception&) {}
}
#endif
}
std::string torrent::tracker_login() const
@ -1055,7 +1084,7 @@ namespace libtorrent
}
void torrent::on_name_lookup(asio::error const& e, tcp::resolver::iterator host
void torrent::on_name_lookup(asio::error_code const& e, tcp::resolver::iterator host
, std::string url) try
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
@ -1075,7 +1104,7 @@ namespace libtorrent
if (m_ses.m_alerts.should_post(alert::warning))
{
std::stringstream msg;
msg << "HTTP seed hostname lookup failed: " << e.what();
msg << "HTTP seed hostname lookup failed: " << e.message();
m_ses.m_alerts.post_alert(
url_seed_alert(url, msg.str()));
}
@ -1151,6 +1180,15 @@ namespace libtorrent
c->m_in_constructor = false;
#endif
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
if (pp) c->add_extension(pp);
}
#endif
try
{
m_ses.m_connection_queue.push_back(c);
@ -1183,6 +1221,35 @@ namespace libtorrent
return *c;
}
void torrent::set_metadata(entry const& metadata)
{
m_torrent_file.parse_info_section(metadata);
boost::mutex::scoped_lock(m_checker.m_mutex);
boost::shared_ptr<aux::piece_checker_data> d(
new aux::piece_checker_data);
d->torrent_ptr = shared_from_this();
d->save_path = m_save_path;
d->info_hash = m_torrent_file.info_hash();
// add the torrent to the queue to be checked
m_checker.m_torrents.push_back(d);
typedef session_impl::torrent_map torrent_map;
torrent_map::iterator i = m_ses.m_torrents.find(
m_torrent_file.info_hash());
assert(i != m_ses.m_torrents.end());
m_ses.m_torrents.erase(i);
// and notify the thread that it got another
// job in its queue
m_checker.m_cond.notify_one();
if (m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(metadata_received_alert(
get_handle(), "metadata successfully received from swarm"));
}
}
void torrent::attach_peer(peer_connection* p)
{
INVARIANT_CHECK;
@ -1217,19 +1284,26 @@ namespace libtorrent
throw protocol_error("session is closing");
}
peer_iterator i = m_connections.insert(
peer_iterator ci = m_connections.insert(
std::make_pair(p->remote(), p)).first;
try
{
// if new_connection throws, we have to remove the
// it from the list.
m_policy->new_connection(*i->second);
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
boost::shared_ptr<peer_plugin> pp((*i)->new_connection(p));
if (pp) p->add_extension(pp);
}
#endif
m_policy->new_connection(*ci->second);
}
catch (std::exception& e)
{
m_connections.erase(i);
m_connections.erase(ci);
throw;
}
#ifndef NDEBUG
@ -1412,7 +1486,12 @@ namespace libtorrent
for (conn_map::iterator i = m_connections.begin()
, end(m_connections.end()); i != end;)
{
try { i->second->init(); ++i;}
try
{
i->second->init();
i->second->on_metadata();
++i;
}
catch (std::exception& e)
{
// the connection failed, close it
@ -1469,7 +1548,7 @@ namespace libtorrent
{
INVARIANT_CHECK;
return torrent_handle(&m_ses, 0, m_torrent_file.info_hash());
return torrent_handle(&m_ses, &m_checker, m_torrent_file.info_hash());
}
session_settings const& torrent::settings() const
@ -1560,6 +1639,15 @@ namespace libtorrent
INVARIANT_CHECK;
if (m_paused) return;
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
try { if ((*i)->on_pause()) return; } catch (std::exception&) {}
}
#endif
disconnect_all();
m_paused = true;
// tell the tracker that we stopped
@ -1575,6 +1663,15 @@ namespace libtorrent
INVARIANT_CHECK;
if (!m_paused) return;
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
try { if ((*i)->on_resume()) return; } catch (std::exception&) {}
}
#endif
m_paused = false;
// tell the tracker that we're back
@ -1600,6 +1697,14 @@ namespace libtorrent
m_dl_bandwidth_quota.min = 0;
m_dl_bandwidth_quota.max = 0;
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
try { (*i)->tick(); } catch (std::exception&) {}
}
#endif
if (m_paused)
{
// let the stats fade out to 0
@ -1754,22 +1859,6 @@ namespace libtorrent
bool torrent::is_allocating() const
{ return m_storage.get() && m_storage->is_allocating(); }
std::vector<char> const& torrent::metadata() const
{
INVARIANT_CHECK;
if (m_metadata.empty())
{
bencode(std::back_inserter(m_metadata)
, m_torrent_file.create_info_metadata());
assert(hasher(&m_metadata[0], m_metadata.size()).final()
== m_torrent_file.info_hash());
}
assert(!m_metadata.empty());
return m_metadata;
}
void torrent::file_progress(std::vector<float>& fp) const
{
assert(valid_metadata());
@ -1817,7 +1906,7 @@ namespace libtorrent
torrent_status st;
st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end(),
st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end(),
boost::bind<bool>(std::logical_not<bool>(), boost::bind(&peer_connection::is_connecting,
boost::bind(&std::map<tcp::endpoint,peer_connection*>::value_type::second, _1))));
@ -1867,8 +1956,11 @@ namespace libtorrent
else
st.state = torrent_status::downloading_metadata;
if (m_metadata_size == 0) st.progress = 0.f;
else st.progress = std::min(1.f, m_metadata_progress / (float)m_metadata_size);
// TODO: add e progress member to the torrent that will be used in this case
// and that may be set by a plugin
// if (m_metadata_size == 0) st.progress = 0.f;
// else st.progress = std::min(1.f, m_metadata_progress / (float)m_metadata_size);
st.progress = 0.f;
st.block_size = 0;
@ -1925,200 +2017,8 @@ namespace libtorrent
return (int)std::count_if(m_connections.begin(), m_connections.end(),
boost::bind(&peer_connection::is_seed,
boost::bind(&std::map<tcp::endpoint,peer_connection*>::value_type::second, _1)));
}
int div_round_up(int numerator, int denominator)
{
return (numerator + denominator - 1) / denominator;
}
std::pair<int, int> req_to_offset(std::pair<int, int> req, int total_size)
{
assert(req.first >= 0);
assert(req.second > 0);
assert(req.second <= 256);
assert(req.first + req.second <= 256);
int start = div_round_up(req.first * total_size, 256);
int size = div_round_up((req.first + req.second) * total_size, 256) - start;
return std::make_pair(start, size);
}
std::pair<int, int> offset_to_req(std::pair<int, int> offset, int total_size)
{
int start = offset.first * 256 / total_size;
int size = (offset.first + offset.second) * 256 / total_size - start;
std::pair<int, int> ret(start, size);
assert(start >= 0);
assert(size > 0);
assert(start <= 256);
assert(start + size <= 256);
// assert the identity of this function
#ifndef NDEBUG
std::pair<int, int> identity = req_to_offset(ret, total_size);
assert(offset == identity);
#endif
return ret;
}
bool torrent::received_metadata(char const* buf, int size, int offset, int total_size)
{
INVARIANT_CHECK;
if (valid_metadata()) return false;
if ((int)m_metadata.size() < total_size)
m_metadata.resize(total_size);
std::copy(
buf
, buf + size
, &m_metadata[offset]);
if (m_have_metadata.empty())
m_have_metadata.resize(256, false);
std::pair<int, int> req = offset_to_req(std::make_pair(offset, size)
, total_size);
assert(req.first + req.second <= (int)m_have_metadata.size());
std::fill(
m_have_metadata.begin() + req.first
, m_have_metadata.begin() + req.first + req.second
, true);
bool have_all = std::count(
m_have_metadata.begin()
, m_have_metadata.end()
, true) == 256;
if (!have_all) return false;
hasher h;
h.update(&m_metadata[0], (int)m_metadata.size());
sha1_hash info_hash = h.final();
if (info_hash != m_torrent_file.info_hash())
{
std::fill(
m_have_metadata.begin()
, m_have_metadata.begin() + req.first + req.second
, false);
m_metadata_progress = 0;
m_metadata_size = 0;
if (m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(metadata_failed_alert(
get_handle(), "invalid metadata received from swarm"));
}
return false;
}
entry metadata = bdecode(m_metadata.begin(), m_metadata.end());
m_torrent_file.parse_info_section(metadata);
{
boost::mutex::scoped_lock(m_checker.m_mutex);
boost::shared_ptr<aux::piece_checker_data> d(
new aux::piece_checker_data);
d->torrent_ptr = shared_from_this();
d->save_path = m_save_path;
d->info_hash = m_torrent_file.info_hash();
// add the torrent to the queue to be checked
m_checker.m_torrents.push_back(d);
typedef session_impl::torrent_map torrent_map;
torrent_map::iterator i = m_ses.m_torrents.find(
m_torrent_file.info_hash());
assert(i != m_ses.m_torrents.end());
m_ses.m_torrents.erase(i);
// and notify the thread that it got another
// job in its queue
m_checker.m_cond.notify_one();
}
if (m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(metadata_received_alert(
get_handle(), "metadata successfully received from swarm"));
}
// clear the storage for the bitfield
std::vector<bool>().swap(m_have_metadata);
std::vector<int>().swap(m_requested_metadata);
return true;
}
std::pair<int, int> torrent::metadata_request()
{
INVARIANT_CHECK;
// count the number of peers that supports the
// extension and that has metadata
int peers = 0;
typedef std::map<tcp::endpoint, peer_connection*> conn_map;
for (conn_map::iterator i = m_connections.begin()
, end(m_connections.end()); i != end; ++i)
{
bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(i->second);
if (c == 0) continue;
if (!c->supports_extension(
extended_metadata_message))
continue;
if (!c->has_metadata())
continue;
++peers;
}
// the number of blocks to request
int num_blocks = 256 / (peers + 1);
if (num_blocks < 1) num_blocks = 1;
assert(num_blocks <= 128);
int min_element = std::numeric_limits<int>::max();
int best_index = 0;
for (int i = 0; i < 256 - num_blocks + 1; ++i)
{
int min = *std::min_element(m_requested_metadata.begin() + i
, m_requested_metadata.begin() + i + num_blocks);
min += std::accumulate(m_requested_metadata.begin() + i
, m_requested_metadata.begin() + i + num_blocks, (int)0);
if (min_element > min)
{
best_index = i;
min_element = min;
}
}
std::pair<int, int> ret(best_index, num_blocks);
for (int i = ret.first; i < ret.first + ret.second; ++i)
m_requested_metadata[i]++;
assert(ret.first >= 0);
assert(ret.second > 0);
assert(ret.second <= 256);
assert(ret.first + ret.second <= 256);
return ret;
}
void torrent::cancel_metadata_request(std::pair<int, int> req)
{
INVARIANT_CHECK;
for (int i = req.first; i < req.first + req.second; ++i)
{
assert(m_requested_metadata[i] > 0);
if (m_requested_metadata[i] > 0)
--m_requested_metadata[i];
}
boost::bind(&std::map<tcp::endpoint
,peer_connection*>::value_type::second, _1)));
}
void torrent::tracker_request_timed_out(
@ -2176,11 +2076,5 @@ namespace libtorrent
}
#endif
void torrent::metadata_progress(int total_size, int received)
{
m_metadata_progress += received;
m_metadata_size = total_size;
}
}

View File

@ -82,6 +82,8 @@ namespace libtorrent
{
void throw_invalid_handle()
{
// TODO: TEMP!
assert(false);
throw invalid_handle();
}
@ -107,6 +109,10 @@ namespace libtorrent
if (t) return f(*t);
}
assert(false);
// throwing directly instead of calling
// the throw_invalid_handle() function
// avoids a warning in gcc
throw invalid_handle();
}
}
@ -346,6 +352,13 @@ namespace libtorrent
, bind(&torrent::is_piece_filtered, _1, index));
}
std::string torrent_handle::name() const
{
INVARIANT_CHECK;
return call_member<std::string>(m_ses, m_chk, m_info_hash
, bind(&torrent::name, _1));
}
std::vector<bool> torrent_handle::filtered_pieces() const
{
INVARIANT_CHECK;
@ -387,7 +400,7 @@ namespace libtorrent
, bind(&torrent::replace_trackers, _1, urls));
}
const torrent_info& torrent_handle::get_torrent_info() const
torrent_info const& torrent_handle::get_torrent_info() const
{
INVARIANT_CHECK;
@ -549,14 +562,6 @@ namespace libtorrent
, bind(&torrent::save_path, _1));
}
std::vector<char> const& torrent_handle::metadata() const
{
INVARIANT_CHECK;
return call_member<std::vector<char> const&>(m_ses, m_chk, m_info_hash
, bind(&torrent::metadata, _1));
}
void torrent_handle::connect_peer(tcp::endpoint const& adr) const
{
INVARIANT_CHECK;
@ -653,7 +658,7 @@ namespace libtorrent
peer->get_peer_info(p);
}
}
/*
bool torrent_handle::send_chat_message(tcp::endpoint ip, std::string message) const
{
if (m_ses == 0) throw_invalid_handle();
@ -689,7 +694,7 @@ namespace libtorrent
}
return false;
}
*/
void torrent_handle::get_download_queue(std::vector<partial_piece_info>& queue) const
{
INVARIANT_CHECK;

View File

@ -244,6 +244,7 @@ namespace libtorrent
, m_name()
, m_creation_date(second_clock::universal_time())
, m_multifile(false)
, m_private(false)
, m_extra_info(entry::dictionary_t)
{
}
@ -255,6 +256,7 @@ namespace libtorrent
, m_name()
, m_creation_date(second_clock::universal_time())
, m_multifile(false)
, m_private(false)
, m_extra_info(entry::dictionary_t)
{
}
@ -591,16 +593,14 @@ namespace libtorrent
if (!info.find_key("files"))
{
entry& files = info["files"];
files = entry(entry::list_t);
for (std::vector<file_entry>::const_iterator i = m_files.begin();
i != m_files.end(); ++i)
{
files.list().push_back(entry(entry::dictionary_t));
files.list().push_back(entry());
entry& file_e = files.list().back();
file_e["length"] = i->size;
entry& path_e = file_e["path"];
path_e = entry(entry::list_t);
fs::path const* file_path;
if (i->orig_path) file_path = &(*i->orig_path);
@ -619,7 +619,6 @@ namespace libtorrent
info["piece length"] = piece_length();
entry& pieces = info["pieces"];
pieces = entry(entry::string_t);
std::string& p = pieces.string();
@ -641,8 +640,6 @@ namespace libtorrent
namespace fs = boost::filesystem;
entry dict(entry::dictionary_t);
if ((m_urls.empty() && m_nodes.empty()) || m_files.empty())
{
// TODO: throw something here
@ -650,6 +647,8 @@ namespace libtorrent
return entry();
}
entry dict;
if (m_private) dict["private"] = 1;
if (!m_urls.empty())
@ -658,7 +657,6 @@ namespace libtorrent
if (!m_nodes.empty())
{
entry& nodes = dict["nodes"];
nodes = entry(entry::list_t);
entry::list_type& nodes_list = nodes.list();
for (nodes_t::const_iterator i = m_nodes.begin()
, end(m_nodes.end()); i != end; ++i)
@ -708,7 +706,6 @@ namespace libtorrent
else
{
entry& list = dict["url-list"];
list = entry(entry::list_t);
for (std::vector<std::string>::const_iterator i
= m_url_seeds.begin(); i != m_url_seeds.end(); ++i)
{

View File

@ -347,7 +347,7 @@ namespace libtorrent
m_timeout.cancel();
}
void timeout_handler::timeout_callback(asio::error const& error) try
void timeout_handler::timeout_callback(asio::error_code const& error) try
{
if (error) return;
if (m_completion_timeout == 0) return;

View File

@ -97,14 +97,14 @@ namespace libtorrent
, m_settings.tracker_receive_timeout);
}
void udp_tracker_connection::name_lookup(asio::error const& error
void udp_tracker_connection::name_lookup(asio::error_code const& error
, tcp::resolver::iterator i) try
{
if (error == asio::error::operation_aborted) return;
if (!m_socket) return; // the operation was aborted
if (error || i == tcp::resolver::iterator())
{
fail(-1, error.what());
fail(-1, error.message().c_str());
return;
}
@ -162,14 +162,14 @@ namespace libtorrent
, boost::bind(&udp_tracker_connection::connect_response, self(), _1, _2));
}
void udp_tracker_connection::connect_response(asio::error const& error
void udp_tracker_connection::connect_response(asio::error_code const& error
, std::size_t bytes_transferred) try
{
if (error == asio::error::operation_aborted) return;
if (!m_socket) return; // the operation was aborted
if (error)
{
fail(-1, error.what());
fail(-1, error.message().c_str());
return;
}
@ -328,14 +328,14 @@ namespace libtorrent
, bind(&udp_tracker_connection::scrape_response, self(), _1, _2));
}
void udp_tracker_connection::announce_response(asio::error const& error
void udp_tracker_connection::announce_response(asio::error_code const& error
, std::size_t bytes_transferred) try
{
if (error == asio::error::operation_aborted) return;
if (!m_socket) return; // the operation was aborted
if (error)
{
fail(-1, error.what());
fail(-1, error.message().c_str());
return;
}
@ -437,14 +437,14 @@ namespace libtorrent
fail(-1, e.what());
}; // msvc 7.1 seems to require this
void udp_tracker_connection::scrape_response(asio::error const& error
void udp_tracker_connection::scrape_response(asio::error_code const& error
, std::size_t bytes_transferred) try
{
if (error == asio::error::operation_aborted) return;
if (!m_socket) return; // the operation was aborted
if (error)
{
fail(-1, error.what());
fail(-1, error.message().c_str());
return;
}

View File

@ -67,7 +67,18 @@ namespace libtorrent
{
INVARIANT_CHECK;
m_max_out_request_queue = ses.settings().urlseed_pipeline_size;
// we always prefer downloading entire
// pieces from web seeds
prefer_whole_pieces(true);
request_large_blocks(true);
shared_ptr<torrent> tor = t.lock();
assert(tor);
int blocks_per_piece = tor->torrent_file().piece_length() / tor->block_size();
// multiply with the blocks per piece since that many requests are
// merged into one http request
m_max_out_request_queue = ses.settings().urlseed_pipeline_size
* blocks_per_piece;
// since this is a web seed, change the timeout
// according to the settings.
@ -241,15 +252,12 @@ namespace libtorrent
// --------------------------
// throws exception when the client should be disconnected
void web_peer_connection::on_receive(const asio::error& error
void web_peer_connection::on_receive(asio::error_code const& error
, std::size_t bytes_transferred)
{
INVARIANT_CHECK;
if (error)
{
return;
}
if (error) return;
boost::shared_ptr<torrent> t = associated_torrent().lock();
assert(t);
@ -312,7 +320,7 @@ namespace libtorrent
, range_end - range_start);
buffer::const_interval http_body = m_parser.get_body();
if (r == m_requests.front())
{
m_requests.pop_front();
@ -430,7 +438,7 @@ namespace libtorrent
}
// throws exception when the client should be disconnected
void web_peer_connection::on_sent(asio::error const& error
void web_peer_connection::on_sent(asio::error_code const& error
, std::size_t bytes_transferred)
{
INVARIANT_CHECK;

View File

@ -60,7 +60,9 @@ boost::tuple<torrent_handle, torrent_handle> setup_transfer(
// use the same files
torrent_handle tor1 = ses1.add_torrent(t, "./tmp1");
torrent_handle tor2 = ses2.add_torrent(tracker_url
, t.info_hash(), "./tmp2");
, t.info_hash(), 0, "./tmp2");
sleep(100);
std::cerr << "connecting peer\n";
tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1")

View File

@ -6,6 +6,7 @@
#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/extensions/metadata_transfer.hpp"
using boost::filesystem::remove_all;
@ -15,6 +16,8 @@ void test_transfer(bool clear_files = true, bool disconnect = false)
session ses1;
session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49000, 50000));
ses1.add_extension(&create_metadata_plugin);
ses2.add_extension(&create_metadata_plugin);
torrent_handle tor1;
torrent_handle tor2;
@ -61,13 +64,13 @@ int test_main()
using namespace boost::filesystem;
// test to disconnect one client prematurely
test_transfer(true, true);
// test_transfer(true, true);
// test where one has data and one doesn't
test_transfer(true);
// test where both have data (to trigger the file check)
test_transfer(false);
// test_transfer(false);
remove_all("./tmp1");
remove_all("./tmp2");