landed ssl branch back into trunk

This commit is contained in:
Arvid Norberg 2012-01-14 16:04:25 +00:00
parent cbe02221cd
commit 4a40e68a82
20 changed files with 737 additions and 565 deletions

View File

@ -1,3 +1,4 @@
* improve SSL torrent support by using SNI and a single SSL listen socket
* improved peer exchange performance by sharing incoming connections which advertize listen port * improved peer exchange performance by sharing incoming connections which advertize listen port
* deprecate set_ratio(), and per-peer rate limits * deprecate set_ratio(), and per-peer rate limits
* add web seed support for torrents with pad files * add web seed support for torrents with pad files

View File

@ -65,7 +65,7 @@ rule linking ( properties * )
} }
# gcrypt libraries, if enabled # gcrypt libraries, if enabled
if <encryption>gcrypt in $(properties) if <encryption>gcrypt in $(properties) || <encryption>openssl in $(properties)
{ {
# on mac os x, adding the /opt/local/include path # on mac os x, adding the /opt/local/include path
# would include openssl headers incompatible with # would include openssl headers incompatible with
@ -371,7 +371,7 @@ lib boost_system : : <name>boost_system ;
lib gcrypt : : <name>gcrypt <link>shared <search>/opt/local/lib ; lib gcrypt : : <name>gcrypt <link>shared <search>/opt/local/lib ;
lib z : : <link>shared <name>z <search>/lib ; lib z : : <link>shared <name>z <search>/lib ;
lib crypto : : <name>crypto <search>/lib <use>z ; lib crypto : : <name>crypto <search>/lib <use>z ;
lib ssl : : <name>ssl <link>shared <use>crypto ; lib ssl : : <name>ssl <link>shared <use>crypto <search>/opt/local/lib ;
lib dl : : <link>shared <name>dl ; lib dl : : <link>shared <name>dl ;
# time functions used on linux require librt # time functions used on linux require librt

View File

@ -2,25 +2,23 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<script type="text/javascript">
/* <![CDATA[ */
(function() {
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
s.type = 'text/javascript';
s.async = true;
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
t.parentNode.insertBefore(s, t);
})();
/* ]]> */
</script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" />
<title></title> <title></title>
<meta name="author" content="Arvid Norberg, arvid&#64;rasterbar.com" /> <meta name="author" content="Arvid Norberg, arvid&#64;rasterbar.com" />
<link rel="stylesheet" type="text/css" href="../../css/base.css" /> <link rel="stylesheet" type="text/css" href="../../css/base.css" />
<link rel="stylesheet" type="text/css" href="../../css/rst.css" /> <link rel="stylesheet" type="text/css" href="../../css/rst.css" />
<script type="text/javascript">
/* <![CDATA[ */
(function() {
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
s.type = 'text/javascript';
s.async = true;
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
t.parentNode.insertBefore(s, t);
})();
/* ]]> */
</script>
<link rel="stylesheet" href="style.css" type="text/css" /> <link rel="stylesheet" href="style.css" type="text/css" />
<style type="text/css"> <style type="text/css">
/* Hides from IE-mac \*/ /* Hides from IE-mac \*/

View File

@ -2,25 +2,23 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<script type="text/javascript">
/* <![CDATA[ */
(function() {
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
s.type = 'text/javascript';
s.async = true;
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
t.parentNode.insertBefore(s, t);
})();
/* ]]> */
</script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" />
<title></title> <title></title>
<meta name="author" content="Arvid Norberg, arvid&#64;rasterbar.com Ludvig Strigeus, ludde&#64;utorrent.com" /> <meta name="author" content="Arvid Norberg, arvid&#64;rasterbar.com Ludvig Strigeus, ludde&#64;utorrent.com" />
<link rel="stylesheet" type="text/css" href="../../css/base.css" /> <link rel="stylesheet" type="text/css" href="../../css/base.css" />
<link rel="stylesheet" type="text/css" href="../../css/rst.css" /> <link rel="stylesheet" type="text/css" href="../../css/rst.css" />
<script type="text/javascript">
/* <![CDATA[ */
(function() {
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
s.type = 'text/javascript';
s.async = true;
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
t.parentNode.insertBefore(s, t);
})();
/* ]]> */
</script>
<link rel="stylesheet" href="style.css" type="text/css" /> <link rel="stylesheet" href="style.css" type="text/css" />
<style type="text/css"> <style type="text/css">
/* Hides from IE-mac \*/ /* Hides from IE-mac \*/

View File

@ -2,25 +2,23 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<script type="text/javascript">
/* <![CDATA[ */
(function() {
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
s.type = 'text/javascript';
s.async = true;
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
t.parentNode.insertBefore(s, t);
})();
/* ]]> */
</script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" />
<title></title> <title></title>
<meta name="author" content="Arvid Norberg, arvid&#64;rasterbar.com" /> <meta name="author" content="Arvid Norberg, arvid&#64;rasterbar.com" />
<link rel="stylesheet" type="text/css" href="../../css/base.css" /> <link rel="stylesheet" type="text/css" href="../../css/base.css" />
<link rel="stylesheet" type="text/css" href="../../css/rst.css" /> <link rel="stylesheet" type="text/css" href="../../css/rst.css" />
<script type="text/javascript">
/* <![CDATA[ */
(function() {
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
s.type = 'text/javascript';
s.async = true;
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
t.parentNode.insertBefore(s, t);
})();
/* ]]> */
</script>
<link rel="stylesheet" href="style.css" type="text/css" /> <link rel="stylesheet" href="style.css" type="text/css" />
<style type="text/css"> <style type="text/css">
/* Hides from IE-mac \*/ /* Hides from IE-mac \*/

View File

@ -75,8 +75,9 @@
<li><a class="reference internal" href="#add-url-seed-add-http-seed" id="id17">add_url_seed() add_http_seed()</a></li> <li><a class="reference internal" href="#add-url-seed-add-http-seed" id="id17">add_url_seed() add_http_seed()</a></li>
<li><a class="reference internal" href="#add-node" id="id18">add_node()</a></li> <li><a class="reference internal" href="#add-node" id="id18">add_node()</a></li>
<li><a class="reference internal" href="#add-tracker" id="id19">add_tracker()</a></li> <li><a class="reference internal" href="#add-tracker" id="id19">add_tracker()</a></li>
<li><a class="reference internal" href="#set-priv-priv" id="id20">set_priv() priv()</a></li> <li><a class="reference internal" href="#set-root-cert" id="id20">set_root_cert()</a></li>
<li><a class="reference internal" href="#merkle-tree" id="id21">merkle_tree()</a></li> <li><a class="reference internal" href="#set-priv-priv" id="id21">set_priv() priv()</a></li>
<li><a class="reference internal" href="#merkle-tree" id="id22">merkle_tree()</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -345,6 +346,7 @@ struct create_torrent
void add_http_seed(std::string const&amp; url); void add_http_seed(std::string const&amp; url);
void add_node(std::pair&lt;std::string, int&gt; const&amp; node); void add_node(std::pair&lt;std::string, int&gt; const&amp; node);
void add_tracker(std::string const&amp; url, int tier = 0); void add_tracker(std::string const&amp; url, int tier = 0);
void set_root_cert(std::string const&amp; pem);
void set_priv(bool p); void set_priv(bool p);
int num_pieces() const; int num_pieces() const;
@ -530,6 +532,18 @@ info-hash. The tier is the fallback priority of the tracker. All trackers with t
tried first (in any order). If all fail, trackers with tier 1 are tried. If all of those tried first (in any order). If all fail, trackers with tier 1 are tried. If all of those
fail, trackers with tier 2 are tried, and so on.</p> fail, trackers with tier 2 are tried, and so on.</p>
</div> </div>
<div class="section" id="set-root-cert">
<h2>set_root_cert()</h2>
<blockquote>
<pre class="literal-block">
void set_root_cert(std::string const&amp; pem);
</pre>
</blockquote>
<p>This function sets an X.509 certificate in PEM format to the torrent. This makes the
torrent an <em>SSL torrent</em>. An SSL torrent requires that each peer has a valid certificate
signed by this root certificate. For SSL torrents, all peers are connecting over SSL
connections. For more information on SSL torrents, see the <a class="reference external" href="manual.html#ssl-torrents">manual</a>.</p>
</div>
<div class="section" id="set-priv-priv"> <div class="section" id="set-priv-priv">
<h2>set_priv() priv()</h2> <h2>set_priv() priv()</h2>
<blockquote> <blockquote>

View File

@ -288,6 +288,7 @@ The ``create_torrent`` class has the following synopsis::
void add_http_seed(std::string const& url); void add_http_seed(std::string const& url);
void add_node(std::pair<std::string, int> const& node); void add_node(std::pair<std::string, int> const& node);
void add_tracker(std::string const& url, int tier = 0); void add_tracker(std::string const& url, int tier = 0);
void set_root_cert(std::string const& pem);
void set_priv(bool p); void set_priv(bool p);
int num_pieces() const; int num_pieces() const;
@ -482,6 +483,20 @@ info-hash. The tier is the fallback priority of the tracker. All trackers with t
tried first (in any order). If all fail, trackers with tier 1 are tried. If all of those tried first (in any order). If all fail, trackers with tier 1 are tried. If all of those
fail, trackers with tier 2 are tried, and so on. fail, trackers with tier 2 are tried, and so on.
set_root_cert()
---------------
::
void set_root_cert(std::string const& pem);
This function sets an X.509 certificate in PEM format to the torrent. This makes the
torrent an *SSL torrent*. An SSL torrent requires that each peer has a valid certificate
signed by this root certificate. For SSL torrents, all peers are connecting over SSL
connections. For more information on SSL torrents, see the manual_.
.. _manual: manual.html#ssl-torrents
set_priv() priv() set_priv() priv()
----------------- -----------------

View File

@ -138,210 +138,208 @@
<li><a class="reference internal" href="#scrape-tracker" id="id87">scrape_tracker()</a></li> <li><a class="reference internal" href="#scrape-tracker" id="id87">scrape_tracker()</a></li>
<li><a class="reference internal" href="#connect-peer" id="id88">connect_peer()</a></li> <li><a class="reference internal" href="#connect-peer" id="id88">connect_peer()</a></li>
<li><a class="reference internal" href="#name" id="id89">name()</a></li> <li><a class="reference internal" href="#name" id="id89">name()</a></li>
<li><a class="reference internal" href="#set-ratio" id="id90">set_ratio()</a></li> <li><a class="reference internal" href="#set-upload-limit-set-download-limit-upload-limit-download-limit" id="id90">set_upload_limit() set_download_limit() upload_limit() download_limit()</a></li>
<li><a class="reference internal" href="#set-upload-limit-set-download-limit-upload-limit-download-limit" id="id91">set_upload_limit() set_download_limit() upload_limit() download_limit()</a></li> <li><a class="reference internal" href="#set-sequential-download" id="id91">set_sequential_download()</a></li>
<li><a class="reference internal" href="#set-sequential-download" id="id92">set_sequential_download()</a></li> <li><a class="reference internal" href="#pause-resume" id="id92">pause() resume()</a></li>
<li><a class="reference internal" href="#get-peer-download-limit-get-peer-upload-limit-set-peer-upload-limit-set-peer-download-limit" id="id93">get_peer_download_limit() get_peer_upload_limit() set_peer_upload_limit() set_peer_download_limit()</a></li> <li><a class="reference internal" href="#flush-cache" id="id93">flush_cache()</a></li>
<li><a class="reference internal" href="#pause-resume" id="id94">pause() resume()</a></li> <li><a class="reference internal" href="#force-recheck" id="id94">force_recheck()</a></li>
<li><a class="reference internal" href="#flush-cache" id="id95">flush_cache()</a></li> <li><a class="reference internal" href="#clear-error" id="id95">clear_error()</a></li>
<li><a class="reference internal" href="#force-recheck" id="id96">force_recheck()</a></li> <li><a class="reference internal" href="#set-upload-mode" id="id96">set_upload_mode()</a></li>
<li><a class="reference internal" href="#clear-error" id="id97">clear_error()</a></li> <li><a class="reference internal" href="#set-share-mode" id="id97">set_share_mode()</a></li>
<li><a class="reference internal" href="#set-upload-mode" id="id98">set_upload_mode()</a></li> <li><a class="reference internal" href="#apply-ip-filter" id="id98">apply_ip_filter()</a></li>
<li><a class="reference internal" href="#set-share-mode" id="id99">set_share_mode()</a></li> <li><a class="reference internal" href="#resolve-countries" id="id99">resolve_countries()</a></li>
<li><a class="reference internal" href="#apply-ip-filter" id="id100">apply_ip_filter()</a></li> <li><a class="reference internal" href="#is-seed" id="id100">is_seed()</a></li>
<li><a class="reference internal" href="#resolve-countries" id="id101">resolve_countries()</a></li> <li><a class="reference internal" href="#auto-managed" id="id101">auto_managed()</a></li>
<li><a class="reference internal" href="#is-seed" id="id102">is_seed()</a></li> <li><a class="reference internal" href="#set-metadata" id="id102">set_metadata()</a></li>
<li><a class="reference internal" href="#auto-managed" id="id103">auto_managed()</a></li> <li><a class="reference internal" href="#set-tracker-login" id="id103">set_tracker_login()</a></li>
<li><a class="reference internal" href="#set-metadata" id="id104">set_metadata()</a></li> <li><a class="reference internal" href="#trackers-replace-trackers-add-tracker" id="id104">trackers() replace_trackers() add_tracker()</a></li>
<li><a class="reference internal" href="#set-tracker-login" id="id105">set_tracker_login()</a></li> <li><a class="reference internal" href="#add-url-seed-remove-url-seed-url-seeds" id="id105">add_url_seed() remove_url_seed() url_seeds()</a></li>
<li><a class="reference internal" href="#trackers-replace-trackers-add-tracker" id="id106">trackers() replace_trackers() add_tracker()</a></li> <li><a class="reference internal" href="#add-http-seed-remove-http-seed-http-seeds" id="id106">add_http_seed() remove_http_seed() http_seeds()</a></li>
<li><a class="reference internal" href="#add-url-seed-remove-url-seed-url-seeds" id="id107">add_url_seed() remove_url_seed() url_seeds()</a></li> <li><a class="reference internal" href="#queue-position-queue-position-up-queue-position-down-queue-position-top-queue-position-bottom" id="id107">queue_position() queue_position_up() queue_position_down() queue_position_top() queue_position_bottom()</a></li>
<li><a class="reference internal" href="#add-http-seed-remove-http-seed-http-seeds" id="id108">add_http_seed() remove_http_seed() http_seeds()</a></li> <li><a class="reference internal" href="#set-priority" id="id108">set_priority()</a></li>
<li><a class="reference internal" href="#queue-position-queue-position-up-queue-position-down-queue-position-top-queue-position-bottom" id="id109">queue_position() queue_position_up() queue_position_down() queue_position_top() queue_position_bottom()</a></li> <li><a class="reference internal" href="#use-interface" id="id109">use_interface()</a></li>
<li><a class="reference internal" href="#set-priority" id="id110">set_priority()</a></li> <li><a class="reference internal" href="#info-hash" id="id110">info_hash()</a></li>
<li><a class="reference internal" href="#use-interface" id="id111">use_interface()</a></li> <li><a class="reference internal" href="#set-max-uploads-max-uploads" id="id111">set_max_uploads() max_uploads()</a></li>
<li><a class="reference internal" href="#info-hash" id="id112">info_hash()</a></li> <li><a class="reference internal" href="#set-max-connections-max-connections" id="id112">set_max_connections() max_connections()</a></li>
<li><a class="reference internal" href="#set-max-uploads-max-uploads" id="id113">set_max_uploads() max_uploads()</a></li> <li><a class="reference internal" href="#save-resume-data" id="id113">save_resume_data()</a></li>
<li><a class="reference internal" href="#set-max-connections-max-connections" id="id114">set_max_connections() max_connections()</a></li> <li><a class="reference internal" href="#need-save-resume-data" id="id114">need_save_resume_data()</a></li>
<li><a class="reference internal" href="#save-resume-data" id="id115">save_resume_data()</a></li> <li><a class="reference internal" href="#id5" id="id115">status()</a></li>
<li><a class="reference internal" href="#need-save-resume-data" id="id116">need_save_resume_data()</a></li> <li><a class="reference internal" href="#get-download-queue" id="id116">get_download_queue()</a></li>
<li><a class="reference internal" href="#id5" id="id117">status()</a></li> <li><a class="reference internal" href="#get-peer-info" id="id117">get_peer_info()</a></li>
<li><a class="reference internal" href="#get-download-queue" id="id118">get_download_queue()</a></li> <li><a class="reference internal" href="#get-torrent-info" id="id118">get_torrent_info()</a></li>
<li><a class="reference internal" href="#get-peer-info" id="id119">get_peer_info()</a></li> <li><a class="reference internal" href="#is-valid" id="id119">is_valid()</a></li>
<li><a class="reference internal" href="#get-torrent-info" id="id120">get_torrent_info()</a></li> <li><a class="reference internal" href="#set-ssl-certificate" id="id120">set_ssl_certificate()</a></li>
<li><a class="reference internal" href="#is-valid" id="id121">is_valid()</a></li>
<li><a class="reference internal" href="#set-ssl-certificate" id="id122">set_ssl_certificate()</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#torrent-status" id="id123">torrent_status</a></li> <li><a class="reference internal" href="#torrent-status" id="id121">torrent_status</a></li>
<li><a class="reference internal" href="#peer-info" id="id124">peer_info</a></li> <li><a class="reference internal" href="#peer-info" id="id122">peer_info</a></li>
<li><a class="reference internal" href="#feed-handle" id="id125">feed_handle</a><ul> <li><a class="reference internal" href="#feed-handle" id="id123">feed_handle</a><ul>
<li><a class="reference internal" href="#update-feed" id="id126">update_feed()</a></li> <li><a class="reference internal" href="#update-feed" id="id124">update_feed()</a></li>
<li><a class="reference internal" href="#get-feed-status" id="id127">get_feed_status()</a></li> <li><a class="reference internal" href="#get-feed-status" id="id125">get_feed_status()</a></li>
<li><a class="reference internal" href="#set-settings-settings" id="id128">set_settings() settings()</a></li> <li><a class="reference internal" href="#set-settings-settings" id="id126">set_settings() settings()</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#feed-item" id="id129">feed_item</a></li> <li><a class="reference internal" href="#feed-item" id="id127">feed_item</a></li>
<li><a class="reference internal" href="#session-customization" id="id130">session customization</a><ul> <li><a class="reference internal" href="#session-customization" id="id128">session customization</a><ul>
<li><a class="reference internal" href="#presets" id="id131">presets</a></li> <li><a class="reference internal" href="#presets" id="id129">presets</a></li>
<li><a class="reference internal" href="#session-settings" id="id132">session_settings</a></li> <li><a class="reference internal" href="#session-settings" id="id130">session_settings</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#pe-settings" id="id133">pe_settings</a></li> <li><a class="reference internal" href="#pe-settings" id="id131">pe_settings</a></li>
<li><a class="reference internal" href="#proxy-settings" id="id134">proxy_settings</a></li> <li><a class="reference internal" href="#proxy-settings" id="id132">proxy_settings</a></li>
<li><a class="reference internal" href="#ip-filter" id="id135">ip_filter</a><ul> <li><a class="reference internal" href="#ip-filter" id="id133">ip_filter</a><ul>
<li><a class="reference internal" href="#id8" id="id136">ip_filter()</a></li> <li><a class="reference internal" href="#id8" id="id134">ip_filter()</a></li>
<li><a class="reference internal" href="#add-rule" id="id137">add_rule()</a></li> <li><a class="reference internal" href="#add-rule" id="id135">add_rule()</a></li>
<li><a class="reference internal" href="#access" id="id138">access()</a></li> <li><a class="reference internal" href="#access" id="id136">access()</a></li>
<li><a class="reference internal" href="#export-filter" id="id139">export_filter()</a></li> <li><a class="reference internal" href="#export-filter" id="id137">export_filter()</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#big-number" id="id140">big_number</a></li> <li><a class="reference internal" href="#big-number" id="id138">big_number</a></li>
<li><a class="reference internal" href="#bitfield" id="id141">bitfield</a></li> <li><a class="reference internal" href="#bitfield" id="id139">bitfield</a></li>
<li><a class="reference internal" href="#hasher" id="id142">hasher</a></li> <li><a class="reference internal" href="#hasher" id="id140">hasher</a></li>
<li><a class="reference internal" href="#fingerprint" id="id143">fingerprint</a></li> <li><a class="reference internal" href="#fingerprint" id="id141">fingerprint</a></li>
<li><a class="reference internal" href="#upnp-and-nat-pmp" id="id144">UPnP and NAT-PMP</a><ul> <li><a class="reference internal" href="#upnp-and-nat-pmp" id="id142">UPnP and NAT-PMP</a><ul>
<li><a class="reference internal" href="#add-mapping" id="id145">add_mapping()</a></li> <li><a class="reference internal" href="#add-mapping" id="id143">add_mapping()</a></li>
<li><a class="reference internal" href="#delete-mapping" id="id146">delete_mapping()</a></li> <li><a class="reference internal" href="#delete-mapping" id="id144">delete_mapping()</a></li>
<li><a class="reference internal" href="#router-model" id="id147">router_model()</a></li> <li><a class="reference internal" href="#router-model" id="id145">router_model()</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#free-functions" id="id148">free functions</a><ul> <li><a class="reference internal" href="#free-functions" id="id146">free functions</a><ul>
<li><a class="reference internal" href="#identify-client" id="id149">identify_client()</a></li> <li><a class="reference internal" href="#identify-client" id="id147">identify_client()</a></li>
<li><a class="reference internal" href="#client-fingerprint" id="id150">client_fingerprint()</a></li> <li><a class="reference internal" href="#client-fingerprint" id="id148">client_fingerprint()</a></li>
<li><a class="reference internal" href="#lazy-bdecode" id="id151">lazy_bdecode()</a></li> <li><a class="reference internal" href="#lazy-bdecode" id="id149">lazy_bdecode()</a></li>
<li><a class="reference internal" href="#bdecode-bencode" id="id152">bdecode() bencode()</a></li> <li><a class="reference internal" href="#bdecode-bencode" id="id150">bdecode() bencode()</a></li>
<li><a class="reference internal" href="#add-magnet-uri" id="id153">add_magnet_uri()</a></li> <li><a class="reference internal" href="#add-magnet-uri" id="id151">add_magnet_uri()</a></li>
<li><a class="reference internal" href="#make-magnet-uri" id="id154">make_magnet_uri()</a></li> <li><a class="reference internal" href="#make-magnet-uri" id="id152">make_magnet_uri()</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#alerts" id="id155">alerts</a><ul> <li><a class="reference internal" href="#alerts" id="id153">alerts</a><ul>
<li><a class="reference internal" href="#torrent-added-alert" id="id156">torrent_added_alert</a></li> <li><a class="reference internal" href="#torrent-added-alert" id="id154">torrent_added_alert</a></li>
<li><a class="reference internal" href="#add-torrent-alert" id="id157">add_torrent_alert</a></li> <li><a class="reference internal" href="#add-torrent-alert" id="id155">add_torrent_alert</a></li>
<li><a class="reference internal" href="#torrent-removed-alert" id="id158">torrent_removed_alert</a></li> <li><a class="reference internal" href="#torrent-removed-alert" id="id156">torrent_removed_alert</a></li>
<li><a class="reference internal" href="#read-piece-alert" id="id159">read_piece_alert</a></li> <li><a class="reference internal" href="#read-piece-alert" id="id157">read_piece_alert</a></li>
<li><a class="reference internal" href="#external-ip-alert" id="id160">external_ip_alert</a></li> <li><a class="reference internal" href="#external-ip-alert" id="id158">external_ip_alert</a></li>
<li><a class="reference internal" href="#listen-failed-alert" id="id161">listen_failed_alert</a></li> <li><a class="reference internal" href="#listen-failed-alert" id="id159">listen_failed_alert</a></li>
<li><a class="reference internal" href="#listen-succeeded-alert" id="id162">listen_succeeded_alert</a></li> <li><a class="reference internal" href="#listen-succeeded-alert" id="id160">listen_succeeded_alert</a></li>
<li><a class="reference internal" href="#portmap-error-alert" id="id163">portmap_error_alert</a></li> <li><a class="reference internal" href="#portmap-error-alert" id="id161">portmap_error_alert</a></li>
<li><a class="reference internal" href="#portmap-alert" id="id164">portmap_alert</a></li> <li><a class="reference internal" href="#portmap-alert" id="id162">portmap_alert</a></li>
<li><a class="reference internal" href="#portmap-log-alert" id="id165">portmap_log_alert</a></li> <li><a class="reference internal" href="#portmap-log-alert" id="id163">portmap_log_alert</a></li>
<li><a class="reference internal" href="#file-error-alert" id="id166">file_error_alert</a></li> <li><a class="reference internal" href="#file-error-alert" id="id164">file_error_alert</a></li>
<li><a class="reference internal" href="#torrent-error-alert" id="id167">torrent_error_alert</a></li> <li><a class="reference internal" href="#torrent-error-alert" id="id165">torrent_error_alert</a></li>
<li><a class="reference internal" href="#file-renamed-alert" id="id168">file_renamed_alert</a></li> <li><a class="reference internal" href="#file-renamed-alert" id="id166">file_renamed_alert</a></li>
<li><a class="reference internal" href="#file-rename-failed-alert" id="id169">file_rename_failed_alert</a></li> <li><a class="reference internal" href="#file-rename-failed-alert" id="id167">file_rename_failed_alert</a></li>
<li><a class="reference internal" href="#tracker-announce-alert" id="id170">tracker_announce_alert</a></li> <li><a class="reference internal" href="#tracker-announce-alert" id="id168">tracker_announce_alert</a></li>
<li><a class="reference internal" href="#tracker-error-alert" id="id171">tracker_error_alert</a></li> <li><a class="reference internal" href="#tracker-error-alert" id="id169">tracker_error_alert</a></li>
<li><a class="reference internal" href="#tracker-reply-alert" id="id172">tracker_reply_alert</a></li> <li><a class="reference internal" href="#tracker-reply-alert" id="id170">tracker_reply_alert</a></li>
<li><a class="reference internal" href="#tracker-warning-alert" id="id173">tracker_warning_alert</a></li> <li><a class="reference internal" href="#tracker-warning-alert" id="id171">tracker_warning_alert</a></li>
<li><a class="reference internal" href="#scrape-reply-alert" id="id174">scrape_reply_alert</a></li> <li><a class="reference internal" href="#scrape-reply-alert" id="id172">scrape_reply_alert</a></li>
<li><a class="reference internal" href="#scrape-failed-alert" id="id175">scrape_failed_alert</a></li> <li><a class="reference internal" href="#scrape-failed-alert" id="id173">scrape_failed_alert</a></li>
<li><a class="reference internal" href="#url-seed-alert" id="id176">url_seed_alert</a></li> <li><a class="reference internal" href="#url-seed-alert" id="id174">url_seed_alert</a></li>
<li><a class="reference internal" href="#hash-failed-alert" id="id177">hash_failed_alert</a></li> <li><a class="reference internal" href="#hash-failed-alert" id="id175">hash_failed_alert</a></li>
<li><a class="reference internal" href="#peer-alert" id="id178">peer_alert</a></li> <li><a class="reference internal" href="#peer-alert" id="id176">peer_alert</a></li>
<li><a class="reference internal" href="#peer-connect-alert" id="id179">peer_connect_alert</a></li> <li><a class="reference internal" href="#peer-connect-alert" id="id177">peer_connect_alert</a></li>
<li><a class="reference internal" href="#peer-ban-alert" id="id180">peer_ban_alert</a></li> <li><a class="reference internal" href="#peer-ban-alert" id="id178">peer_ban_alert</a></li>
<li><a class="reference internal" href="#peer-snubbed-alert" id="id181">peer_snubbed_alert</a></li> <li><a class="reference internal" href="#peer-snubbed-alert" id="id179">peer_snubbed_alert</a></li>
<li><a class="reference internal" href="#peer-unsnubbed-alert" id="id182">peer_unsnubbed_alert</a></li> <li><a class="reference internal" href="#peer-unsnubbed-alert" id="id180">peer_unsnubbed_alert</a></li>
<li><a class="reference internal" href="#peer-error-alert" id="id183">peer_error_alert</a></li> <li><a class="reference internal" href="#peer-error-alert" id="id181">peer_error_alert</a></li>
<li><a class="reference internal" href="#peer-connected-alert" id="id184">peer_connected_alert</a></li> <li><a class="reference internal" href="#peer-connected-alert" id="id182">peer_connected_alert</a></li>
<li><a class="reference internal" href="#peer-disconnected-alert" id="id185">peer_disconnected_alert</a></li> <li><a class="reference internal" href="#peer-disconnected-alert" id="id183">peer_disconnected_alert</a></li>
<li><a class="reference internal" href="#invalid-request-alert" id="id186">invalid_request_alert</a></li> <li><a class="reference internal" href="#invalid-request-alert" id="id184">invalid_request_alert</a></li>
<li><a class="reference internal" href="#request-dropped-alert" id="id187">request_dropped_alert</a></li> <li><a class="reference internal" href="#request-dropped-alert" id="id185">request_dropped_alert</a></li>
<li><a class="reference internal" href="#block-timeout-alert" id="id188">block_timeout_alert</a></li> <li><a class="reference internal" href="#block-timeout-alert" id="id186">block_timeout_alert</a></li>
<li><a class="reference internal" href="#block-finished-alert" id="id189">block_finished_alert</a></li> <li><a class="reference internal" href="#block-finished-alert" id="id187">block_finished_alert</a></li>
<li><a class="reference internal" href="#lsd-peer-alert" id="id190">lsd_peer_alert</a></li> <li><a class="reference internal" href="#lsd-peer-alert" id="id188">lsd_peer_alert</a></li>
<li><a class="reference internal" href="#file-completed-alert" id="id191">file_completed_alert</a></li> <li><a class="reference internal" href="#file-completed-alert" id="id189">file_completed_alert</a></li>
<li><a class="reference internal" href="#block-downloading-alert" id="id192">block_downloading_alert</a></li> <li><a class="reference internal" href="#block-downloading-alert" id="id190">block_downloading_alert</a></li>
<li><a class="reference internal" href="#unwanted-block-alert" id="id193">unwanted_block_alert</a></li> <li><a class="reference internal" href="#unwanted-block-alert" id="id191">unwanted_block_alert</a></li>
<li><a class="reference internal" href="#torrent-delete-failed-alert" id="id194">torrent_delete_failed_alert</a></li> <li><a class="reference internal" href="#torrent-delete-failed-alert" id="id192">torrent_delete_failed_alert</a></li>
<li><a class="reference internal" href="#torrent-deleted-alert" id="id195">torrent_deleted_alert</a></li> <li><a class="reference internal" href="#torrent-deleted-alert" id="id193">torrent_deleted_alert</a></li>
<li><a class="reference internal" href="#torrent-finished-alert" id="id196">torrent_finished_alert</a></li> <li><a class="reference internal" href="#torrent-finished-alert" id="id194">torrent_finished_alert</a></li>
<li><a class="reference internal" href="#performance-alert" id="id197">performance_alert</a></li> <li><a class="reference internal" href="#performance-alert" id="id195">performance_alert</a></li>
<li><a class="reference internal" href="#state-changed-alert" id="id198">state_changed_alert</a></li> <li><a class="reference internal" href="#state-changed-alert" id="id196">state_changed_alert</a></li>
<li><a class="reference internal" href="#metadata-failed-alert" id="id199">metadata_failed_alert</a></li> <li><a class="reference internal" href="#metadata-failed-alert" id="id197">metadata_failed_alert</a></li>
<li><a class="reference internal" href="#metadata-received-alert" id="id200">metadata_received_alert</a></li> <li><a class="reference internal" href="#metadata-received-alert" id="id198">metadata_received_alert</a></li>
<li><a class="reference internal" href="#fastresume-rejected-alert" id="id201">fastresume_rejected_alert</a></li> <li><a class="reference internal" href="#fastresume-rejected-alert" id="id199">fastresume_rejected_alert</a></li>
<li><a class="reference internal" href="#peer-blocked-alert" id="id202">peer_blocked_alert</a></li> <li><a class="reference internal" href="#peer-blocked-alert" id="id200">peer_blocked_alert</a></li>
<li><a class="reference internal" href="#storage-moved-alert" id="id203">storage_moved_alert</a></li> <li><a class="reference internal" href="#storage-moved-alert" id="id201">storage_moved_alert</a></li>
<li><a class="reference internal" href="#storage-moved-failed-alert" id="id204">storage_moved_failed_alert</a></li> <li><a class="reference internal" href="#storage-moved-failed-alert" id="id202">storage_moved_failed_alert</a></li>
<li><a class="reference internal" href="#torrent-paused-alert" id="id205">torrent_paused_alert</a></li> <li><a class="reference internal" href="#torrent-paused-alert" id="id203">torrent_paused_alert</a></li>
<li><a class="reference internal" href="#torrent-resumed-alert" id="id206">torrent_resumed_alert</a></li> <li><a class="reference internal" href="#torrent-resumed-alert" id="id204">torrent_resumed_alert</a></li>
<li><a class="reference internal" href="#save-resume-data-alert" id="id207">save_resume_data_alert</a></li> <li><a class="reference internal" href="#save-resume-data-alert" id="id205">save_resume_data_alert</a></li>
<li><a class="reference internal" href="#save-resume-data-failed-alert" id="id208">save_resume_data_failed_alert</a></li> <li><a class="reference internal" href="#save-resume-data-failed-alert" id="id206">save_resume_data_failed_alert</a></li>
<li><a class="reference internal" href="#stats-alert" id="id209">stats_alert</a></li> <li><a class="reference internal" href="#stats-alert" id="id207">stats_alert</a></li>
<li><a class="reference internal" href="#cache-flushed-alert" id="id210">cache_flushed_alert</a></li> <li><a class="reference internal" href="#cache-flushed-alert" id="id208">cache_flushed_alert</a></li>
<li><a class="reference internal" href="#torrent-need-cert-alert" id="id211">torrent_need_cert_alert</a></li> <li><a class="reference internal" href="#torrent-need-cert-alert" id="id209">torrent_need_cert_alert</a></li>
<li><a class="reference internal" href="#dht-announce-alert" id="id212">dht_announce_alert</a></li> <li><a class="reference internal" href="#dht-announce-alert" id="id210">dht_announce_alert</a></li>
<li><a class="reference internal" href="#dht-get-peers-alert" id="id213">dht_get_peers_alert</a></li> <li><a class="reference internal" href="#dht-get-peers-alert" id="id211">dht_get_peers_alert</a></li>
<li><a class="reference internal" href="#dht-reply-alert" id="id214">dht_reply_alert</a></li> <li><a class="reference internal" href="#dht-reply-alert" id="id212">dht_reply_alert</a></li>
<li><a class="reference internal" href="#dht-bootstrap-alert" id="id215">dht_bootstrap_alert</a></li> <li><a class="reference internal" href="#dht-bootstrap-alert" id="id213">dht_bootstrap_alert</a></li>
<li><a class="reference internal" href="#anonymous-mode-alert" id="id216">anonymous_mode_alert</a></li> <li><a class="reference internal" href="#anonymous-mode-alert" id="id214">anonymous_mode_alert</a></li>
<li><a class="reference internal" href="#rss-alert" id="id217">rss_alert</a></li> <li><a class="reference internal" href="#rss-alert" id="id215">rss_alert</a></li>
<li><a class="reference internal" href="#incoming-connection-alert" id="id218">incoming_connection_alert</a></li> <li><a class="reference internal" href="#incoming-connection-alert" id="id216">incoming_connection_alert</a></li>
<li><a class="reference internal" href="#state-update-alert" id="id219">state_update_alert</a></li> <li><a class="reference internal" href="#state-update-alert" id="id217">state_update_alert</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#alert-dispatcher" id="id220">alert dispatcher</a></li> <li><a class="reference internal" href="#alert-dispatcher" id="id218">alert dispatcher</a></li>
<li><a class="reference internal" href="#exceptions" id="id221">exceptions</a><ul> <li><a class="reference internal" href="#exceptions" id="id219">exceptions</a><ul>
<li><a class="reference internal" href="#libtorrent-exception" id="id222">libtorrent_exception</a></li> <li><a class="reference internal" href="#libtorrent-exception" id="id220">libtorrent_exception</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#error-code" id="id223">error_code</a><ul> <li><a class="reference internal" href="#error-code" id="id221">error_code</a><ul>
<li><a class="reference internal" href="#translating-error-codes" id="id224">translating error codes</a></li> <li><a class="reference internal" href="#translating-error-codes" id="id222">translating error codes</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#storage-interface" id="id225">storage_interface</a><ul> <li><a class="reference internal" href="#storage-interface" id="id223">storage_interface</a><ul>
<li><a class="reference internal" href="#initialize" id="id226">initialize()</a></li> <li><a class="reference internal" href="#initialize" id="id224">initialize()</a></li>
<li><a class="reference internal" href="#has-any-file" id="id227">has_any_file()</a></li> <li><a class="reference internal" href="#has-any-file" id="id225">has_any_file()</a></li>
<li><a class="reference internal" href="#hint-read" id="id228">hint_read()</a></li> <li><a class="reference internal" href="#hint-read" id="id226">hint_read()</a></li>
<li><a class="reference internal" href="#readv-writev" id="id229">readv() writev()</a></li> <li><a class="reference internal" href="#readv-writev" id="id227">readv() writev()</a></li>
<li><a class="reference internal" href="#sparse-end" id="id230">sparse_end()</a></li> <li><a class="reference internal" href="#sparse-end" id="id228">sparse_end()</a></li>
<li><a class="reference internal" href="#id10" id="id231">move_storage()</a></li> <li><a class="reference internal" href="#id10" id="id229">move_storage()</a></li>
<li><a class="reference internal" href="#verify-resume-data" id="id232">verify_resume_data()</a></li> <li><a class="reference internal" href="#verify-resume-data" id="id230">verify_resume_data()</a></li>
<li><a class="reference internal" href="#write-resume-data" id="id233">write_resume_data()</a></li> <li><a class="reference internal" href="#write-resume-data" id="id231">write_resume_data()</a></li>
<li><a class="reference internal" href="#move-slot" id="id234">move_slot()</a></li> <li><a class="reference internal" href="#move-slot" id="id232">move_slot()</a></li>
<li><a class="reference internal" href="#swap-slots" id="id235">swap_slots()</a></li> <li><a class="reference internal" href="#swap-slots" id="id233">swap_slots()</a></li>
<li><a class="reference internal" href="#swap-slots3" id="id236">swap_slots3()</a></li> <li><a class="reference internal" href="#swap-slots3" id="id234">swap_slots3()</a></li>
<li><a class="reference internal" href="#id11" id="id237">rename_file()</a></li> <li><a class="reference internal" href="#id11" id="id235">rename_file()</a></li>
<li><a class="reference internal" href="#release-files" id="id238">release_files()</a></li> <li><a class="reference internal" href="#release-files" id="id236">release_files()</a></li>
<li><a class="reference internal" href="#delete-files" id="id239">delete_files()</a></li> <li><a class="reference internal" href="#delete-files" id="id237">delete_files()</a></li>
<li><a class="reference internal" href="#finalize-file" id="id240">finalize_file()</a></li> <li><a class="reference internal" href="#finalize-file" id="id238">finalize_file()</a></li>
<li><a class="reference internal" href="#example" id="id241">example</a></li> <li><a class="reference internal" href="#example" id="id239">example</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#magnet-links" id="id242">magnet links</a></li> <li><a class="reference internal" href="#magnet-links" id="id240">magnet links</a></li>
<li><a class="reference internal" href="#queuing" id="id243">queuing</a><ul> <li><a class="reference internal" href="#queuing" id="id241">queuing</a><ul>
<li><a class="reference internal" href="#downloading" id="id244">downloading</a></li> <li><a class="reference internal" href="#downloading" id="id242">downloading</a></li>
<li><a class="reference internal" href="#seeding" id="id245">seeding</a></li> <li><a class="reference internal" href="#seeding" id="id243">seeding</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#fast-resume" id="id246">fast resume</a><ul> <li><a class="reference internal" href="#fast-resume" id="id244">fast resume</a><ul>
<li><a class="reference internal" href="#file-format" id="id247">file format</a></li> <li><a class="reference internal" href="#file-format" id="id245">file format</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#storage-allocation" id="id248">storage allocation</a><ul> <li><a class="reference internal" href="#storage-allocation" id="id246">storage allocation</a><ul>
<li><a class="reference internal" href="#sparse-allocation" id="id249">sparse allocation</a></li> <li><a class="reference internal" href="#sparse-allocation" id="id247">sparse allocation</a></li>
<li><a class="reference internal" href="#full-allocation" id="id250">full allocation</a></li> <li><a class="reference internal" href="#full-allocation" id="id248">full allocation</a></li>
<li><a class="reference internal" href="#compact-allocation" id="id251">compact allocation</a></li> <li><a class="reference internal" href="#compact-allocation" id="id249">compact allocation</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#extensions" id="id252">extensions</a><ul> <li><a class="reference internal" href="#extensions" id="id250">extensions</a><ul>
<li><a class="reference internal" href="#metadata-from-peers" id="id253">metadata from peers</a></li> <li><a class="reference internal" href="#metadata-from-peers" id="id251">metadata from peers</a></li>
<li><a class="reference internal" href="#dont-have" id="id254">dont_have</a></li> <li><a class="reference internal" href="#dont-have" id="id252">dont_have</a></li>
<li><a class="reference internal" href="#http-seeding" id="id255">HTTP seeding</a></li> <li><a class="reference internal" href="#http-seeding" id="id253">HTTP seeding</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#piece-picker" id="id256">piece picker</a><ul> <li><a class="reference internal" href="#piece-picker" id="id254">piece picker</a><ul>
<li><a class="reference internal" href="#internal-representation" id="id257">internal representation</a></li> <li><a class="reference internal" href="#internal-representation" id="id255">internal representation</a></li>
<li><a class="reference internal" href="#picker-strategy" id="id258">picker strategy</a></li> <li><a class="reference internal" href="#picker-strategy" id="id256">picker strategy</a></li>
<li><a class="reference internal" href="#reverse-order" id="id259">reverse order</a></li> <li><a class="reference internal" href="#reverse-order" id="id257">reverse order</a></li>
<li><a class="reference internal" href="#parole-mode" id="id260">parole mode</a></li> <li><a class="reference internal" href="#parole-mode" id="id258">parole mode</a></li>
<li><a class="reference internal" href="#prioritize-partial-pieces" id="id261">prioritize partial pieces</a></li> <li><a class="reference internal" href="#prioritize-partial-pieces" id="id259">prioritize partial pieces</a></li>
<li><a class="reference internal" href="#prefer-whole-pieces" id="id262">prefer whole pieces</a></li> <li><a class="reference internal" href="#prefer-whole-pieces" id="id260">prefer whole pieces</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#ssl-torrents" id="id263">SSL torrents</a></li> <li><a class="reference internal" href="#ssl-torrents" id="id261">SSL torrents</a></li>
</ul> </ul>
</div> </div>
<div class="section" id="overview"> <div class="section" id="overview">
@ -2402,7 +2400,6 @@ struct torrent_handle
void remove_http_seed(std::string const&amp; url); void remove_http_seed(std::string const&amp; url);
std::set&lt;std::string&gt; http_seeds() const; std::set&lt;std::string&gt; http_seeds() const;
void set_ratio(float ratio) const;
int max_uploads() const; int max_uploads() const;
void set_max_uploads(int max_uploads) const; void set_max_uploads(int max_uploads) const;
void set_max_connections(int max_connections) const; void set_max_connections(int max_connections) const;
@ -2414,11 +2411,6 @@ struct torrent_handle
void set_sequential_download(bool sd) const; void set_sequential_download(bool sd) const;
bool is_sequential_download() const; bool is_sequential_download() const;
int get_peer_upload_limit(tcp::endpoint ip);
int get_peer_download_limit(tcp::endpoint ip);
void set_peer_upload_limit(asio::ip::tcp::endpoint ip, int limit) const;
void set_peer_download_limit(asio::ip::tcp::endpoint ip, int limit) const;
int queue_position() const; int queue_position() const;
void queue_position_up() const; void queue_position_up() const;
void queue_position_down() const; void queue_position_down() const;
@ -2790,21 +2782,6 @@ std::string name() const;
case the torrent was started without metadata, and hasn't completely received it yet, 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> 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>
<div class="section" id="set-ratio">
<h2>set_ratio()</h2>
<blockquote>
<pre class="literal-block">
void set_ratio(float ratio) const;
</pre>
</blockquote>
<p><tt class="docutils literal"><span class="pre">set_ratio()</span></tt> sets the desired download / upload ratio. If set to 0, it is considered being
infinite. i.e. the client will always upload as much as it can, no matter how much it gets back
in return. With this setting it will work much like the standard clients.</p>
<p>Besides 0, the ratio can be set to any number greater than or equal to 1. It means how much to
attempt to upload in return for each download. e.g. if set to 2, the client will try to upload
2 bytes for every byte received. The default setting for this is 0, which will make it work
as a standard client.</p>
</div>
<div class="section" id="set-upload-limit-set-download-limit-upload-limit-download-limit"> <div class="section" id="set-upload-limit-set-download-limit-upload-limit-download-limit">
<h2>set_upload_limit() set_download_limit() upload_limit() download_limit()</h2> <h2>set_upload_limit() set_download_limit() upload_limit() download_limit()</h2>
<blockquote> <blockquote>
@ -2836,20 +2813,6 @@ picker will pick pieces in sequence instead of rarest first.</p>
<p>Enabling sequential download will affect the piece distribution negatively in the swarm. It should be <p>Enabling sequential download will affect the piece distribution negatively in the swarm. It should be
used sparingly.</p> used sparingly.</p>
</div> </div>
<div class="section" id="get-peer-download-limit-get-peer-upload-limit-set-peer-upload-limit-set-peer-download-limit">
<h2>get_peer_download_limit() get_peer_upload_limit() set_peer_upload_limit() set_peer_download_limit()</h2>
<blockquote>
<pre class="literal-block">
int get_peer_upload_limit(tcp::endpoint ip);
int get_peer_download_limit(tcp::endpoint ip);
void set_peer_upload_limit(asio::ip::tcp::endpoint ip, int limit) const;
void set_peer_download_limit(asio::ip::tcp::endpoint ip, int limit) const;
</pre>
</blockquote>
<p>Works like <tt class="docutils literal"><span class="pre">get_upload_limit</span></tt>, <tt class="docutils literal"><span class="pre">get_download_limit</span></tt>, <tt class="docutils literal"><span class="pre">set_upload_limit</span></tt> and
<tt class="docutils literal"><span class="pre">set_download_limit</span></tt> respectively, but controls individual peer instead of the
whole torrent.</p>
</div>
<div class="section" id="pause-resume"> <div class="section" id="pause-resume">
<h2>pause() resume()</h2> <h2>pause() resume()</h2>
<blockquote> <blockquote>
@ -4516,8 +4479,6 @@ struct session_settings
bool report_true_downloaded; bool report_true_downloaded;
bool strict_end_game_mode; bool strict_end_game_mode;
int default_peer_upload_rate;
int default_peer_download_rate;
bool broadcast_lsd; bool broadcast_lsd;
bool enable_outgoing_utp; bool enable_outgoing_utp;
@ -4574,6 +4535,8 @@ struct session_settings
int read_job_every; int read_job_every;
bool use_disk_read_ahead; bool use_disk_read_ahead;
bool lock_files; bool lock_files;
int ssl_listen;
}; };
</pre> </pre>
<p><tt class="docutils literal"><span class="pre">version</span></tt> is automatically set to the libtorrent version you're using <p><tt class="docutils literal"><span class="pre">version</span></tt> is automatically set to the libtorrent version you're using
@ -5124,12 +5087,6 @@ sometimes, but it may also avoid downloading a lot of redundant bytes.
If this is <tt class="docutils literal"><span class="pre">false</span></tt>, libtorrent attempts to use each peer connection If this is <tt class="docutils literal"><span class="pre">false</span></tt>, libtorrent attempts to use each peer connection
to its max, by always requesting something, even if it means requesting to its max, by always requesting something, even if it means requesting
something that has been requested from another peer already.</p> something that has been requested from another peer already.</p>
<p><tt class="docutils literal"><span class="pre">default_peer_upload_rate</span></tt> and <tt class="docutils literal"><span class="pre">default_peer_download_rate</span></tt> specifies
the default upload and download rate limits for peers, respectively. These
default to 0, which means unlimited. These settings affect the rate limits
set on new peer connections (not existing ones). The peer rate limits can
be changed individually later using
<a class="reference internal" href="#get-peer-download-limit-get-peer-upload-limit-set-peer-upload-limit-set-peer-download-limit">get_peer_download_limit() get_peer_upload_limit() set_peer_upload_limit() set_peer_download_limit()</a>.</p>
<p>if <tt class="docutils literal"><span class="pre">broadcast_lsd</span></tt> is set to true, the local peer discovery <p>if <tt class="docutils literal"><span class="pre">broadcast_lsd</span></tt> is set to true, the local peer discovery
(or Local Service Discovery) will not only use IP multicast, but also (or Local Service Discovery) will not only use IP multicast, but also
broadcast its messages. This can be useful when running on networks broadcast its messages. This can be useful when running on networks
@ -5301,6 +5258,11 @@ in the disk job queue. This gives a significant performance boost for seeding.</
to or seeding from. This is implemented using <tt class="docutils literal"><span class="pre">fcntl(F_SETLK)</span></tt> on unix systems and to or seeding from. This is implemented using <tt class="docutils literal"><span class="pre">fcntl(F_SETLK)</span></tt> on unix systems and
by not passing in <tt class="docutils literal"><span class="pre">SHARE_READ</span></tt> and <tt class="docutils literal"><span class="pre">SHARE_WRITE</span></tt> on windows. This might prevent by not passing in <tt class="docutils literal"><span class="pre">SHARE_READ</span></tt> and <tt class="docutils literal"><span class="pre">SHARE_WRITE</span></tt> on windows. This might prevent
3rd party processes from corrupting the files under libtorrent's feet.</p> 3rd party processes from corrupting the files under libtorrent's feet.</p>
<p><tt class="docutils literal"><span class="pre">ssl_listen</span></tt> sets the listen port for SSL connections. If this is set to 0,
no SSL listen port is opened. Otherwise a socket is opened on this port. This
setting is only taken into account when opening the regular listen port, and
won't re-open the listen socket simply by changing this setting.</p>
<p>It defaults to port 4433.</p>
</div> </div>
</div> </div>
<div class="section" id="pe-settings"> <div class="section" id="pe-settings">
@ -6501,7 +6463,7 @@ struct peer_disconnected_alert: peer_alert
<div class="section" id="invalid-request-alert"> <div class="section" id="invalid-request-alert">
<h2>invalid_request_alert</h2> <h2>invalid_request_alert</h2>
<p>This is a debug alert that is generated by an incoming invalid piece request. <p>This is a debug alert that is generated by an incoming invalid piece request.
<tt class="docutils literal"><span class="pre">Ïp</span></tt> is the address of the peer and the <tt class="docutils literal"><span class="pre">request</span></tt> is the actual incoming <tt class="docutils literal"><span class="pre">ìp</span></tt> is the address of the peer and the <tt class="docutils literal"><span class="pre">request</span></tt> is the actual incoming
request from the peer.</p> request from the peer.</p>
<pre class="literal-block"> <pre class="literal-block">
struct invalid_request_alert: peer_alert struct invalid_request_alert: peer_alert
@ -7667,6 +7629,16 @@ metadata, and also torrents added by URL.</td>
message is an extension to allow peers to advertise that the message is an extension to allow peers to advertise that the
no longer has a piece they previously had.</td> no longer has a piece they previously had.</td>
</tr> </tr>
<tr><td>111</td>
<td>requires_ssl_connection</td>
<td>The peer tried to connect to an SSL torrent without connecting
over SSL.</td>
</tr>
<tr><td>112</td>
<td>invalid_ssl_cert</td>
<td>The peer tried to connect to a torrent with a certificate
for a different torrent.</td>
</tr>
</tbody> </tbody>
</table> </table>
<p>NAT-PMP errors:</p> <p>NAT-PMP errors:</p>
@ -8054,13 +8026,13 @@ std::string error_code_to_string(boost::system::error_code const&amp; ec)
static const char const* swedish[] = static const char const* swedish[] =
{ {
&quot;inget fel&quot;, &quot;inget fel&quot;,
&quot;en fil i torrenten kolliderar med en fil frÂn en annan torrent&quot;, &quot;en fil i torrenten kolliderar med en fil från en annan torrent&quot;,
&quot;hash check misslyckades&quot;, &quot;hash check misslyckades&quot;,
&quot;torrent filen r inte en dictionary&quot;, &quot;torrent filen är inte en dictionary&quot;,
&quot;'info'-nyckeln saknas eller r korrupt i torrentfilen&quot;, &quot;'info'-nyckeln saknas eller är korrupt i torrentfilen&quot;,
&quot;'info'-f‰ltet ‰r inte en dictionary&quot;, &quot;'info'-fältet är inte en dictionary&quot;,
&quot;'piece length' f‰ltet saknas eller ‰r korrupt i torrentfilen&quot;, &quot;'piece length' fältet saknas eller är korrupt i torrentfilen&quot;,
&quot;torrentfilen saknar namnfltet&quot;, &quot;torrentfilen saknar namnfältet&quot;,
&quot;ogiltigt namn i torrentfilen (kan vara en attack)&quot;, &quot;ogiltigt namn i torrentfilen (kan vara en attack)&quot;,
// ... more strings here // ... more strings here
}; };
@ -8712,7 +8684,7 @@ as much space as has been downloaded.</p>
</div> </div>
<div class="section" id="full-allocation"> <div class="section" id="full-allocation">
<h2>full allocation</h2> <h2>full allocation</h2>
<p>When a torrent is started in full allocation mode, the disk-io thread (see <a href="#id264"><span class="problematic" id="id265">threads_</span></a>) <p>When a torrent is started in full allocation mode, the disk-io thread (see <a href="#id262"><span class="problematic" id="id263">threads_</span></a>)
will make sure that the entire storage is allocated, and fill any gaps with zeros. will make sure that the entire storage is allocated, and fill any gaps with zeros.
This will be skipped if the filesystem supports sparse files or automatic zero filling. This will be skipped if the filesystem supports sparse files or automatic zero filling.
It will of course still check for existing pieces and fast resume data. The main It will of course still check for existing pieces and fast resume data. The main
@ -9089,22 +9061,46 @@ The protocols are layered like this:</p>
+-----------+-----------+ +-----------+-----------+
</pre> </pre>
<p>During the SSL handshake, both peers need to authenticate by providing a certificate <p>During the SSL handshake, both peers need to authenticate by providing a certificate
that is signed by the private counterpart of the CA certificate found in the that is signed by the CA certificate found in the .torrent file. These peer
.torrent file. These peer certificates are expected to be privided to peers through certificates are expected to be privided to peers through some other means than
some other means than bittorrent. Typically by a peer generating a certificate request bittorrent. Typically by a peer generating a certificate request which is sent to
which is sent to the publisher of the torrent, and the publisher returning a signed the publisher of the torrent, and the publisher returning a signed certificate.</p>
certificate.</p>
<p>In libtorrent, <a class="reference internal" href="#set-ssl-certificate">set_ssl_certificate()</a> in <a class="reference internal" href="#torrent-handle">torrent_handle</a> is used to tell libtorrent where <p>In libtorrent, <a class="reference internal" href="#set-ssl-certificate">set_ssl_certificate()</a> in <a class="reference internal" href="#torrent-handle">torrent_handle</a> is used to tell libtorrent where
to find the peer certificate and the private key for it. When an SSL torrent is loaded, to find the peer certificate and the private key for it. When an SSL torrent is loaded,
the <a class="reference internal" href="#torrent-need-cert-alert">torrent_need_cert_alert</a> is posted to remind the user to provide a certificate.</p> the <a class="reference internal" href="#torrent-need-cert-alert">torrent_need_cert_alert</a> is posted to remind the user to provide a certificate.</p>
<p>In order for the client to know which torrent an incoming connection belongs to, in order <p>A peer connecting to an SSL torrent MUST provide the <em>SNI</em> TLS extension (server name
to provide the correct certificate, each SSL torrent opens their own dedicated listen socket.</p> indication). The server name is the hex encoded info-hash of the torrent to connect to.
This is required for the client accepting the connection to know which certificate to
present.</p>
<p>SSL connections are accepted on a separate socket from normal bittorrent connections. To
pick which port the SSL socket should bind to, set <tt class="docutils literal"><span class="pre">session_settings::ssl_listen</span></tt> to a
different port. It defaults to port 4433. This setting is only taken into account when the
normal listen socket is opened (i.e. just changing this setting won't necessarily close
and re-open the SSL socket). To not listen on an SSL socket at all, set <tt class="docutils literal"><span class="pre">ssl_listen</span></tt> to 0.</p>
<p>This feature is only available if libtorrent is build with openssl support (<tt class="docutils literal"><span class="pre">TORRENT_USE_OPENSSL</span></tt>).</p> <p>This feature is only available if libtorrent is build with openssl support (<tt class="docutils literal"><span class="pre">TORRENT_USE_OPENSSL</span></tt>).</p>
<p>To test incoming SSL connections to an SSL torrent, one can use the following <em>openssl</em> command:</p>
<pre class="literal-block">
openssl s_client -cert &lt;peer-certificate&gt;.pem -key &lt;peer-private-key&gt;.pem -CAfile &lt;torrent-cert&gt;.pem -debug -connect 127.0.0.1:4433 -tls1 -servername &lt;info-hash&gt;
</pre>
<p>To create a root certificate, the Distinguished Name (<em>DN</em>) is not taken into account
by bittorrent peers. You still need to specify something, but from libtorrent's point of
view, it doesn't matter what it is. libtorrent only makes sure the peer certificates are
signed by the correct root certificate.</p>
<p>One way to create the certificates is to use the <tt class="docutils literal"><span class="pre">CA.sh</span></tt> script that comes with openssl, like thisi (don't forget to enter a common Name for the certificate):</p>
<pre class="literal-block">
CA.sh -newca
CA.sh -newreq
CA.sh -sign
</pre>
<p>The torrent certificate is located in <tt class="docutils literal"><span class="pre">./demoCA/private/demoCA/cacert.pem</span></tt>, this is
the pem file to include in the .torrent file.</p>
<p>The peer's certificate is located in <tt class="docutils literal"><span class="pre">./newcert.pem</span></tt> and the certificate's
private key in <tt class="docutils literal"><span class="pre">./newkey.pem</span></tt>.</p>
</div> </div>
<div class="system-messages section"> <div class="system-messages section">
<h1>Docutils System Messages</h1> <h1>Docutils System Messages</h1>
<div class="system-message" id="id264"> <div class="system-message" id="id262">
<p class="system-message-title">System Message: ERROR/3 (<tt class="docutils">manual.rst</tt>, line 8717); <em><a href="#id265">backlink</a></em></p> <p class="system-message-title">System Message: ERROR/3 (<tt class="docutils">manual.rst</tt>, line 8686); <em><a href="#id263">backlink</a></em></p>
Unknown target name: &quot;threads&quot;.</div> Unknown target name: &quot;threads&quot;.</div>
</div> </div>
</div> </div>

View File

@ -4535,6 +4535,8 @@ session_settings
int read_job_every; int read_job_every;
bool use_disk_read_ahead; bool use_disk_read_ahead;
bool lock_files; bool lock_files;
int ssl_listen;
}; };
``version`` is automatically set to the libtorrent version you're using ``version`` is automatically set to the libtorrent version you're using
@ -5403,6 +5405,13 @@ to or seeding from. This is implemented using ``fcntl(F_SETLK)`` on unix systems
by not passing in ``SHARE_READ`` and ``SHARE_WRITE`` on windows. This might prevent by not passing in ``SHARE_READ`` and ``SHARE_WRITE`` on windows. This might prevent
3rd party processes from corrupting the files under libtorrent's feet. 3rd party processes from corrupting the files under libtorrent's feet.
``ssl_listen`` sets the listen port for SSL connections. If this is set to 0,
no SSL listen port is opened. Otherwise a socket is opened on this port. This
setting is only taken into account when opening the regular listen port, and
won't re-open the listen socket simply by changing this setting.
It defaults to port 4433.
pe_settings pe_settings
=========== ===========
@ -7779,6 +7788,12 @@ code symbol description
110 invalid_dont_have The peer sent an invalid ``dont_have`` message. The dont have 110 invalid_dont_have The peer sent an invalid ``dont_have`` message. The dont have
message is an extension to allow peers to advertise that the message is an extension to allow peers to advertise that the
no longer has a piece they previously had. no longer has a piece they previously had.
------ ----------------------------------------- -----------------------------------------------------------------
111 requires_ssl_connection The peer tried to connect to an SSL torrent without connecting
over SSL.
------ ----------------------------------------- -----------------------------------------------------------------
112 invalid_ssl_cert The peer tried to connect to a torrent with a certificate
for a different torrent.
====== ========================================= ================================================================= ====== ========================================= =================================================================
NAT-PMP errors: NAT-PMP errors:
@ -9022,18 +9037,46 @@ The protocols are layered like this::
+-----------+-----------+ +-----------+-----------+
During the SSL handshake, both peers need to authenticate by providing a certificate During the SSL handshake, both peers need to authenticate by providing a certificate
that is signed by the private counterpart of the CA certificate found in the that is signed by the CA certificate found in the .torrent file. These peer
.torrent file. These peer certificates are expected to be privided to peers through certificates are expected to be privided to peers through some other means than
some other means than bittorrent. Typically by a peer generating a certificate request bittorrent. Typically by a peer generating a certificate request which is sent to
which is sent to the publisher of the torrent, and the publisher returning a signed the publisher of the torrent, and the publisher returning a signed certificate.
certificate.
In libtorrent, `set_ssl_certificate()`_ in torrent_handle_ is used to tell libtorrent where In libtorrent, `set_ssl_certificate()`_ in torrent_handle_ is used to tell libtorrent where
to find the peer certificate and the private key for it. When an SSL torrent is loaded, to find the peer certificate and the private key for it. When an SSL torrent is loaded,
the torrent_need_cert_alert_ is posted to remind the user to provide a certificate. the torrent_need_cert_alert_ is posted to remind the user to provide a certificate.
In order for the client to know which torrent an incoming connection belongs to, in order A peer connecting to an SSL torrent MUST provide the *SNI* TLS extension (server name
to provide the correct certificate, each SSL torrent opens their own dedicated listen socket. indication). The server name is the hex encoded info-hash of the torrent to connect to.
This is required for the client accepting the connection to know which certificate to
present.
SSL connections are accepted on a separate socket from normal bittorrent connections. To
pick which port the SSL socket should bind to, set ``session_settings::ssl_listen`` to a
different port. It defaults to port 4433. This setting is only taken into account when the
normal listen socket is opened (i.e. just changing this setting won't necessarily close
and re-open the SSL socket). To not listen on an SSL socket at all, set ``ssl_listen`` to 0.
This feature is only available if libtorrent is build with openssl support (``TORRENT_USE_OPENSSL``). This feature is only available if libtorrent is build with openssl support (``TORRENT_USE_OPENSSL``).
To test incoming SSL connections to an SSL torrent, one can use the following *openssl* command::
openssl s_client -cert <peer-certificate>.pem -key <peer-private-key>.pem -CAfile <torrent-cert>.pem -debug -connect 127.0.0.1:4433 -tls1 -servername <info-hash>
To create a root certificate, the Distinguished Name (*DN*) is not taken into account
by bittorrent peers. You still need to specify something, but from libtorrent's point of
view, it doesn't matter what it is. libtorrent only makes sure the peer certificates are
signed by the correct root certificate.
One way to create the certificates is to use the ``CA.sh`` script that comes with openssl, like thisi (don't forget to enter a common Name for the certificate)::
CA.sh -newca
CA.sh -newreq
CA.sh -sign
The torrent certificate is located in ``./demoCA/private/demoCA/cacert.pem``, this is
the pem file to include in the .torrent file.
The peer's certificate is located in ``./newcert.pem`` and the certificate's
private key in ``./newkey.pem``.

View File

@ -2,25 +2,23 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<script type="text/javascript">
/* <![CDATA[ */
(function() {
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
s.type = 'text/javascript';
s.async = true;
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
t.parentNode.insertBefore(s, t);
})();
/* ]]> */
</script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" />
<title>libtorrent manual</title> <title>libtorrent manual</title>
<meta name="author" content="Arvid Norberg, arvid&#64;rasterbar.com" /> <meta name="author" content="Arvid Norberg, arvid&#64;rasterbar.com" />
<link rel="stylesheet" type="text/css" href="../../css/base.css" /> <link rel="stylesheet" type="text/css" href="../../css/base.css" />
<link rel="stylesheet" type="text/css" href="../../css/rst.css" /> <link rel="stylesheet" type="text/css" href="../../css/rst.css" />
<script type="text/javascript">
/* <![CDATA[ */
(function() {
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
s.type = 'text/javascript';
s.async = true;
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
t.parentNode.insertBefore(s, t);
})();
/* ]]> */
</script>
<link rel="stylesheet" href="style.css" type="text/css" /> <link rel="stylesheet" href="style.css" type="text/css" />
<style type="text/css"> <style type="text/css">
/* Hides from IE-mac \*/ /* Hides from IE-mac \*/

View File

@ -669,6 +669,9 @@ bool seed_mode = false;
bool share_mode = false; bool share_mode = false;
bool disable_storage = false; bool disable_storage = false;
// if non-empty, a peer that will be added to all torrents
std::string peer;
using boost::bind; using boost::bind;
// monitored_dir is true if this torrent is added because // monitored_dir is true if this torrent is added because
@ -871,7 +874,7 @@ bool handle_alert(libtorrent::session& ses, libtorrent::alert* a
snprintf(msg, sizeof(msg), "loaded certificate %s and key %s\n", cert.c_str(), priv.c_str()); snprintf(msg, sizeof(msg), "loaded certificate %s and key %s\n", cert.c_str(), priv.c_str());
if (g_log_file) fprintf(g_log_file, "[%s] %s\n", time_now_string(), msg); if (g_log_file) fprintf(g_log_file, "[%s] %s\n", time_now_string(), msg);
h.set_ssl_certificate(cert, priv, "certificates/dhparams.pem", "test"); h.set_ssl_certificate(cert, priv, "certificates/dhparams.pem", "1234");
h.resume(); h.resume();
} }
#endif #endif
@ -905,6 +908,20 @@ bool handle_alert(libtorrent::session& ses, libtorrent::alert* a
h.resolve_countries(true); h.resolve_countries(true);
#endif #endif
// if we have a peer specified, connect to it
if (!peer.empty())
{
char* port = (char*) strrchr((char*)peer.c_str(), ':');
if (port > 0)
{
*port++ = 0;
char const* ip = peer.c_str();
int peer_port = atoi(port);
if (peer_port > 0)
h.connect_peer(tcp::endpoint(address::from_string(ip), peer_port));
}
}
boost::unordered_set<torrent_status>::iterator j boost::unordered_set<torrent_status>::iterator j
= all_handles.insert(h.status()).first; = all_handles.insert(h.status()).first;
if (show_torrent(*j, torrent_filter, counters)) if (show_torrent(*j, torrent_filter, counters))
@ -1086,6 +1103,7 @@ int main(int argc, char* argv[])
" -B <seconds> sets the peer timeout\n" " -B <seconds> sets the peer timeout\n"
" -Q enables share mode. Share mode attempts to maximize\n" " -Q enables share mode. Share mode attempts to maximize\n"
" share ratio rather than downloading\n" " share ratio rather than downloading\n"
" -r <IP:port> connect to specified peer\n"
" -e force encrypted bittorrent connections\n" " -e force encrypted bittorrent connections\n"
"\n QUEING OPTIONS\n" "\n QUEING OPTIONS\n"
" -v <limit> Set the max number of active downloads\n" " -v <limit> Set the max number of active downloads\n"
@ -1310,6 +1328,7 @@ int main(int argc, char* argv[])
case 'O': settings.allow_reordered_disk_operations = false; --i; break; case 'O': settings.allow_reordered_disk_operations = false; --i; break;
case 'M': settings.mixed_mode_algorithm = session_settings::prefer_tcp; --i; break; case 'M': settings.mixed_mode_algorithm = session_settings::prefer_tcp; --i; break;
case 'y': settings.enable_outgoing_tcp = false; settings.enable_incoming_tcp = false; --i; break; case 'y': settings.enable_outgoing_tcp = false; settings.enable_incoming_tcp = false; --i; break;
case 'r': peer = arg; break;
case 'P': case 'P':
{ {
char* port = (char*) strrchr(arg, ':'); char* port = (char*) strrchr(arg, ':');

View File

@ -121,7 +121,7 @@ namespace libtorrent
struct listen_socket_t struct listen_socket_t
{ {
listen_socket_t(): external_port(0) {} listen_socket_t(): external_port(0), ssl(false) {}
// this is typically empty but can be set // this is typically empty but can be set
// to the WAN IP address of NAT-PMP or UPnP router // to the WAN IP address of NAT-PMP or UPnP router
@ -136,6 +136,9 @@ namespace libtorrent
// the client is reachable through. // the client is reachable through.
int external_port; int external_port;
// set to true if this is an SSL listen socket
bool ssl;
// the actual socket // the actual socket
boost::shared_ptr<socket_acceptor> sock; boost::shared_ptr<socket_acceptor> sock;
}; };
@ -230,9 +233,9 @@ namespace libtorrent
tcp::endpoint get_ipv6_interface() const; tcp::endpoint get_ipv6_interface() const;
tcp::endpoint get_ipv4_interface() const; tcp::endpoint get_ipv4_interface() const;
void async_accept(boost::shared_ptr<socket_acceptor> const& listener); void async_accept(boost::shared_ptr<socket_acceptor> const& listener, bool ssl);
void on_accept_connection(boost::shared_ptr<socket_type> const& s void on_accept_connection(boost::shared_ptr<socket_type> const& s
, boost::weak_ptr<socket_acceptor> listener, error_code const& e); , boost::weak_ptr<socket_acceptor> listener, error_code const& e, bool ssl);
void on_socks_accept(boost::shared_ptr<socket_type> const& s void on_socks_accept(boost::shared_ptr<socket_type> const& s
, error_code const& e); , error_code const& e);
@ -373,7 +376,8 @@ namespace libtorrent
void set_peer_id(peer_id const& id); void set_peer_id(peer_id const& id);
void set_key(int key); void set_key(int key);
address listen_address() const; address listen_address() const;
unsigned short listen_port() const; boost::uint16_t listen_port() const;
boost::uint16_t ssl_listen_port() const;
void abort(); void abort();
@ -585,6 +589,8 @@ namespace libtorrent
mutable io_service m_io_service; mutable io_service m_io_service;
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
// this is a generic SSL context used when talking to
// unauthenticated HTTPS servers
asio::ssl::context m_ssl_ctx; asio::ssl::context m_ssl_ctx;
#endif #endif
@ -699,6 +705,10 @@ namespace libtorrent
// we might need more than one listen socket // we might need more than one listen socket
std::list<listen_socket_t> m_listen_sockets; std::list<listen_socket_t> m_listen_sockets;
#ifdef TORRENT_USE_OPENSSL
void ssl_handshake(error_code const& ec, boost::shared_ptr<socket_type> s);
#endif
// when as a socks proxy is used for peers, also // when as a socks proxy is used for peers, also
// listen for incoming connections on a socks connection // listen for incoming connections on a socks connection
boost::shared_ptr<socket_type> m_socks_listen_socket; boost::shared_ptr<socket_type> m_socks_listen_socket;
@ -859,9 +869,17 @@ namespace libtorrent
boost::intrusive_ptr<upnp> m_upnp; boost::intrusive_ptr<upnp> m_upnp;
boost::intrusive_ptr<lsd> m_lsd; boost::intrusive_ptr<lsd> m_lsd;
// mask is a bitmask of which protocols to remap on:
// 1: NAT-PMP
// 2: UPnP
void remap_tcp_ports(boost::uint32_t mask, int tcp_port, int ssl_port);
// 0 is natpmp 1 is upnp // 0 is natpmp 1 is upnp
int m_tcp_mapping[2]; int m_tcp_mapping[2];
int m_udp_mapping[2]; int m_udp_mapping[2];
#ifdef TORRENT_USE_OPENSSL
int m_ssl_mapping[2];
#endif
// the timer used to fire the tick // the timer used to fire the tick
deadline_timer m_timer; deadline_timer m_timer;

View File

@ -168,8 +168,8 @@ namespace libtorrent
too_frequent_pex, too_frequent_pex,
no_metadata, no_metadata,
invalid_dont_have, invalid_dont_have,
reserved111, requires_ssl_connection,
reserved112, invalid_ssl_cert,
reserved113, reserved113,
reserved114, reserved114,
reserved115, reserved115,

View File

@ -268,6 +268,7 @@ namespace libtorrent
, read_job_every(10) , read_job_every(10)
, use_disk_read_ahead(true) , use_disk_read_ahead(true)
, lock_files(false) , lock_files(false)
, ssl_listen(4433)
{} {}
// libtorrent version. Used for forward binary compatibility // libtorrent version. Used for forward binary compatibility
@ -1075,6 +1076,9 @@ namespace libtorrent
// if set to true, files will be locked when opened. // if set to true, files will be locked when opened.
// preventing any other process from modifying them // preventing any other process from modifying them
bool lock_files; bool lock_files;
// open an ssl listen socket for ssl torrents on this port
int ssl_listen;
}; };
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT

View File

@ -62,6 +62,11 @@ public:
typedef typename Stream::endpoint_type endpoint_type; typedef typename Stream::endpoint_type endpoint_type;
typedef typename Stream::protocol_type protocol_type; typedef typename Stream::protocol_type protocol_type;
void set_host_name(std::string name)
{ SSL_set_tlsext_host_name(m_sock.native_handle(), name.c_str()); }
SSL* native_handle() { return m_sock.native_handle(); }
typedef boost::function<void(error_code const&)> handler_type; typedef boost::function<void(error_code const&)> handler_type;
template <class Handler> template <class Handler>
@ -97,8 +102,7 @@ public:
template <class Handler> template <class Handler>
void async_shutdown(Handler const& handler) void async_shutdown(Handler const& handler)
{ {
boost::shared_ptr<handler_type> h(new handler_type(handler)); m_sock.async_shutdown(handler);
m_sock.async_shutdown( boost::bind(&ssl_stream::on_shutdown, this, _1, h));
} }
void shutdown(error_code& ec) void shutdown(error_code& ec)

View File

@ -945,26 +945,8 @@ namespace libtorrent
piece_manager* m_storage; piece_manager* m_storage;
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
// TODO: in order to save space, stick the ssl context
// and the listen_socket_t in a single struct and have
// a shared_pointer to that (or intrusive_ptr even)
boost::shared_ptr<asio::ssl::context> m_ssl_ctx; boost::shared_ptr<asio::ssl::context> m_ssl_ctx;
// listen socket used to accept incoming ssl connections
boost::shared_ptr<listen_socket_t> m_ssl_acceptor;
// SSL torrents have their own listen socket, so that
// we know which certificate to use for incoming connections
// these function are used for handling the torrent specific
// listen socket
void async_accept(boost::shared_ptr<socket_acceptor> const& listener);
void on_accept_ssl_connection(boost::shared_ptr<socket_type> const& s
, boost::weak_ptr<socket_acceptor> listen_socket, error_code const& e);
void ssl_handshake(error_code const& ec, boost::shared_ptr<socket_type> s);
void init_ssl(std::string const& cert); void init_ssl(std::string const& cert);
#endif #endif

View File

@ -160,8 +160,8 @@ namespace libtorrent
"pex messages sent too frequent (possible attack)", "pex messages sent too frequent (possible attack)",
"torrent has no metadata", "torrent has no metadata",
"invalid dont-have message", "invalid dont-have message",
"", "SSL connection required",
"", "invalid SSL certificate",
"", "",
"", "",
"", "",

View File

@ -1179,16 +1179,6 @@ namespace libtorrent
t.reset(); t.reset();
} }
#ifdef TORRENT_USE_OPENSSL
if (t && t->is_ssl_torrent())
{
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
peer_log("*** can't attach to an ssl torrent");
#endif
t.reset();
}
#endif
if (!t) if (!t)
{ {
// we couldn't find the torrent! // we couldn't find the torrent!
@ -2021,7 +2011,7 @@ namespace libtorrent
TORRENT_ASSERT(t); TORRENT_ASSERT(t);
#if defined TORRENT_VERBOSE_LOGGING #if defined TORRENT_VERBOSE_LOGGING
peer_log("<== REQUEST [ piece: %d s: %d l: ]" peer_log("<== REQUEST [ piece: %d s: %d l: %d ]"
, r.piece, r.start, r.length); , r.piece, r.start, r.length);
#endif #endif
@ -3454,6 +3444,12 @@ namespace libtorrent
return; return;
} }
void close_socket(boost::shared_ptr<socket_type> const& s)
{
error_code ec;
s->close(ec);
}
// the error argument defaults to 0, which means deliberate disconnect // the error argument defaults to 0, which means deliberate disconnect
// 1 means unexpected disconnect/error // 1 means unexpected disconnect/error
// 2 protocol error (client sent something invalid) // 2 protocol error (client sent something invalid)
@ -3618,7 +3614,23 @@ namespace libtorrent
m_disconnecting = true; m_disconnecting = true;
error_code e; error_code e;
m_socket->close(e);
#ifdef TORRENT_USE_OPENSSL
// for SSL connections, first do an async_shutdown, before closing the socket
#define CASE(t) case socket_type_int_impl<ssl_stream<t> >::value: \
m_socket->get<ssl_stream<t> >()->async_shutdown(boost::bind(&close_socket, m_socket)); \
break;
switch(m_socket->type())
{
CASE(stream_socket)
CASE(socks5_stream)
CASE(http_stream)
CASE(utp_stream)
default: m_socket->close(e); break;
}
#undef CASE
#endif // TORRENT_USE_OPENSSL
m_ses.close_connection(this, ec); m_ses.close_connection(this, ec);
// we should only disconnect while we still have // we should only disconnect while we still have
@ -4529,7 +4541,7 @@ namespace libtorrent
} }
#if defined TORRENT_VERBOSE_LOGGING #if defined TORRENT_VERBOSE_LOGGING
peer_log("==> PIECE [ piece: %d s: %d l: ]" peer_log("==> PIECE [ piece: %d s: %d l: %d ]"
, r.piece, r.start, r.length); , r.piece, r.start, r.length);
#endif #endif

View File

@ -537,6 +537,44 @@ namespace aux {
int session_impl::logging_allocator::allocated_bytes = 0; int session_impl::logging_allocator::allocated_bytes = 0;
#endif #endif
#ifdef TORRENT_USE_OPENSSL
// when running bittorrent over SSL, the SNI (server name indication)
// extension is used to know which torrent the incoming connection is
// trying to connect to. The 40 first bytes in the name is expected to
// be the hex encoded info-hash
int servername_callback(SSL *s, int *ad, void *arg)
{
session_impl* ses = (session_impl*)arg;
const char* servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
if (!servername || strlen(servername) < 40)
return SSL_TLSEXT_ERR_ALERT_FATAL;
sha1_hash info_hash;
bool valid = from_hex(servername, 40, (char*)&info_hash[0]);
// the server name is not a valid hex-encoded info-hash
if (!valid)
return SSL_TLSEXT_ERR_ALERT_FATAL;
// see if there is a torrent with this info-hash
boost::shared_ptr<torrent> t = ses->find_torrent(info_hash).lock();
// if there isn't, fail
if (!t) return SSL_TLSEXT_ERR_ALERT_FATAL;
// if the torrent we found isn't an SSL torrent, also fail.
// the torrent doesn't have an SSL context and should not allow
// incoming SSL connections
if (!t->is_ssl_torrent()) return SSL_TLSEXT_ERR_ALERT_FATAL;
// use this torrent's certificate
SSL_set_SSL_CTX(s, t->ssl_ctx()->native_handle());
return SSL_TLSEXT_ERR_OK;
}
#endif
session_impl::session_impl( session_impl::session_impl(
std::pair<int, int> listen_port_range std::pair<int, int> listen_port_range
, fingerprint const& cl_fprint , fingerprint const& cl_fprint
@ -556,7 +594,7 @@ namespace aux {
, m_files(40) , m_files(40)
, m_io_service() , m_io_service()
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
, m_ssl_ctx(m_io_service, asio::ssl::context::sslv23_client) , m_ssl_ctx(m_io_service, asio::ssl::context::sslv23)
#endif #endif
, m_alerts(m_io_service, m_settings.alert_queue_size, alert_mask) , m_alerts(m_io_service, m_settings.alert_queue_size, alert_mask)
, m_disk_thread(m_io_service, boost::bind(&session_impl::on_disk_queue, this), m_files) , m_disk_thread(m_io_service, boost::bind(&session_impl::on_disk_queue, this), m_files)
@ -646,6 +684,8 @@ namespace aux {
error_code ec; error_code ec;
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
m_ssl_ctx.set_verify_mode(asio::ssl::context::verify_none, ec); m_ssl_ctx.set_verify_mode(asio::ssl::context::verify_none, ec);
SSL_CTX_set_tlsext_servername_callback(m_ssl_ctx.native_handle(), servername_callback);
SSL_CTX_set_tlsext_servername_arg(m_ssl_ctx.native_handle(), this);
#endif #endif
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
@ -663,6 +703,10 @@ namespace aux {
m_tcp_mapping[1] = -1; m_tcp_mapping[1] = -1;
m_udp_mapping[0] = -1; m_udp_mapping[0] = -1;
m_udp_mapping[1] = -1; m_udp_mapping[1] = -1;
#ifdef TORRENT_USE_OPENSSL
m_ssl_mapping[0] = -1;
m_ssl_mapping[1] = -1;
#endif
#ifdef WIN32 #ifdef WIN32
// windows XP has a limit on the number of // windows XP has a limit on the number of
// simultaneous half-open TCP connections // simultaneous half-open TCP connections
@ -2050,6 +2094,11 @@ namespace aux {
m_ipv6_interface = tcp::endpoint(); m_ipv6_interface = tcp::endpoint();
m_ipv4_interface = tcp::endpoint(); m_ipv4_interface = tcp::endpoint();
#ifdef TORRENT_USE_OPENSSL
tcp::endpoint ssl_interface = m_listen_interface;
ssl_interface.port(m_settings.ssl_listen);
#endif
if (is_any(m_listen_interface.address())) if (is_any(m_listen_interface.address()))
{ {
// this means we should open two listen sockets // this means we should open two listen sockets
@ -2064,12 +2113,27 @@ namespace aux {
// update the listen_interface member with the // update the listen_interface member with the
// actual port we ended up listening on, so that the other // actual port we ended up listening on, so that the other
// sockets can be bound to the same one // sockets can be bound to the same one
m_listen_interface.port(s.sock->local_endpoint(ec).port()); m_listen_interface.port(s.external_port);
m_listen_sockets.push_back(s); m_listen_sockets.push_back(s);
async_accept(s.sock); async_accept(s.sock, s.ssl);
} }
#ifdef TORRENT_USE_OPENSSL
if (m_settings.ssl_listen)
{
listen_socket_t s;
s.ssl = true;
setup_listener(&s, ssl_interface, 10, false, flags, ec);
if (s.sock)
{
m_listen_sockets.push_back(s);
async_accept(s.sock, s.ssl);
}
}
#endif
#if TORRENT_USE_IPV6 #if TORRENT_USE_IPV6
// only try to open the IPv6 port if IPv6 is installed // only try to open the IPv6 port if IPv6 is installed
if (supports_ipv6()) if (supports_ipv6())
@ -2080,8 +2144,24 @@ namespace aux {
if (s.sock) if (s.sock)
{ {
m_listen_sockets.push_back(s); m_listen_sockets.push_back(s);
async_accept(s.sock); async_accept(s.sock, s.ssl);
} }
#ifdef TORRENT_USE_OPENSSL
if (m_settings.ssl_listen)
{
listen_socket_t s;
s.ssl = true;
setup_listener(&s, tcp::endpoint(address_v6::any(), ssl_interface.port())
, 10, false, flags, ec);
if (s.sock)
{
m_listen_sockets.push_back(s);
async_accept(s.sock, s.ssl);
}
}
#endif // TORRENT_USE_OPENSSL
} }
#endif // TORRENT_USE_IPV6 #endif // TORRENT_USE_IPV6
@ -2109,13 +2189,28 @@ namespace aux {
if (s.sock) if (s.sock)
{ {
m_listen_sockets.push_back(s); m_listen_sockets.push_back(s);
async_accept(s.sock); async_accept(s.sock, s.ssl);
if (m_listen_interface.address().is_v6()) if (m_listen_interface.address().is_v6())
m_ipv6_interface = m_listen_interface; m_ipv6_interface = m_listen_interface;
else else
m_ipv4_interface = m_listen_interface; m_ipv4_interface = m_listen_interface;
} }
#ifdef TORRENT_USE_OPENSSL
if (m_settings.ssl_listen)
{
listen_socket_t s;
s.ssl = true;
setup_listener(&s, ssl_interface, 10, false, flags, ec);
if (s.sock)
{
m_listen_sockets.push_back(s);
async_accept(s.sock, s.ssl);
}
}
#endif
} }
m_udp_socket.bind(udp::endpoint(m_listen_interface.address(), m_listen_interface.port()), ec); m_udp_socket.bind(udp::endpoint(m_listen_interface.address(), m_listen_interface.port()), ec);
@ -2145,21 +2240,7 @@ namespace aux {
if (!m_listen_sockets.empty()) if (!m_listen_sockets.empty())
{ {
tcp::endpoint local = m_listen_sockets.front().sock->local_endpoint(ec); tcp::endpoint local = m_listen_sockets.front().sock->local_endpoint(ec);
if (!ec) if (!ec) remap_tcp_ports(3, local.port(), ssl_listen_port());
{
if (m_natpmp.get())
{
if (m_tcp_mapping[0] != -1) m_natpmp->delete_mapping(m_tcp_mapping[0]);
m_tcp_mapping[0] = m_natpmp->add_mapping(natpmp::tcp
, local.port(), local.port());
}
if (m_upnp.get())
{
if (m_tcp_mapping[1] != -1) m_upnp->delete_mapping(m_tcp_mapping[1]);
m_tcp_mapping[1] = m_upnp->add_mapping(upnp::tcp
, local.port(), local.port());
}
}
} }
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
@ -2167,6 +2248,28 @@ namespace aux {
#endif #endif
} }
void session_impl::remap_tcp_ports(boost::uint32_t mask, int tcp_port, int ssl_port)
{
if ((mask & 1) && m_natpmp.get())
{
if (m_tcp_mapping[0] != -1) m_natpmp->delete_mapping(m_tcp_mapping[0]);
m_tcp_mapping[0] = m_natpmp->add_mapping(natpmp::tcp, tcp_port, tcp_port);
#ifdef TORRENT_USE_OPENSSL
if (m_ssl_mapping[0] != -1) m_natpmp->delete_mapping(m_ssl_mapping[0]);
m_ssl_mapping[0] = m_natpmp->add_mapping(natpmp::tcp, ssl_port, ssl_port);
#endif
}
if ((mask & 2) && m_upnp.get())
{
if (m_tcp_mapping[1] != -1) m_upnp->delete_mapping(m_tcp_mapping[1]);
m_tcp_mapping[1] = m_upnp->add_mapping(upnp::tcp, tcp_port, tcp_port);
#ifdef TORRENT_USE_OPENSSL
if (m_ssl_mapping[1] != -1) m_upnp->delete_mapping(m_ssl_mapping[1]);
m_ssl_mapping[1] = m_upnp->add_mapping(upnp::tcp, ssl_port, ssl_port);
#endif
}
}
void session_impl::open_new_incoming_socks_connection() void session_impl::open_new_incoming_socks_connection()
{ {
if (m_proxy.type != proxy_settings::socks5 if (m_proxy.type != proxy_settings::socks5
@ -2298,21 +2401,40 @@ namespace aux {
} }
} }
void session_impl::async_accept(boost::shared_ptr<socket_acceptor> const& listener) void session_impl::async_accept(boost::shared_ptr<socket_acceptor> const& listener, bool ssl)
{ {
TORRENT_ASSERT(!m_abort); TORRENT_ASSERT(!m_abort);
shared_ptr<socket_type> c(new socket_type(m_io_service)); shared_ptr<socket_type> c(new socket_type(m_io_service));
stream_socket* str = 0;
#ifdef TORRENT_USE_OPENSSL
if (ssl)
{
// accept connections initializing the SSL connection to
// use the generic m_ssl_ctx context. However, since it has
// the servername callback set on it, we will switch away from
// this context into a specific torrent once we start handshaking
c->instantiate<ssl_stream<stream_socket> >(m_io_service, &m_ssl_ctx);
str = &c->get<ssl_stream<stream_socket> >()->next_layer();
}
else
#endif
{
c->instantiate<stream_socket>(m_io_service); c->instantiate<stream_socket>(m_io_service);
str = c->get<stream_socket>();
}
#if defined TORRENT_ASIO_DEBUGGING #if defined TORRENT_ASIO_DEBUGGING
add_outstanding_async("session_impl::on_accept_connection"); add_outstanding_async("session_impl::on_accept_connection");
#endif #endif
listener->async_accept(*c->get<stream_socket>() listener->async_accept(*str
, boost::bind(&session_impl::on_accept_connection, this, c , boost::bind(&session_impl::on_accept_connection, this, c
, boost::weak_ptr<socket_acceptor>(listener), _1)); , boost::weak_ptr<socket_acceptor>(listener), _1, ssl));
} }
void session_impl::on_accept_connection(shared_ptr<socket_type> const& s void session_impl::on_accept_connection(shared_ptr<socket_type> const& s
, weak_ptr<socket_acceptor> listen_socket, error_code const& e) , weak_ptr<socket_acceptor> listen_socket, error_code const& e, bool ssl)
{ {
#if defined TORRENT_ASIO_DEBUGGING #if defined TORRENT_ASIO_DEBUGGING
complete_async("session_impl::on_accept_connection"); complete_async("session_impl::on_accept_connection");
@ -2342,7 +2464,7 @@ namespace aux {
// non-fatal and we have to do another async_accept. // non-fatal and we have to do another async_accept.
if (e.value() == ERROR_SEM_TIMEOUT) if (e.value() == ERROR_SEM_TIMEOUT)
{ {
async_accept(listener); async_accept(listener, ssl);
return; return;
} }
#endif #endif
@ -2351,7 +2473,7 @@ namespace aux {
// non-fatal and we have to do another async_accept. // non-fatal and we have to do another async_accept.
if (e.value() == EINVAL) if (e.value() == EINVAL)
{ {
async_accept(listener); async_accept(listener, ssl);
return; return;
} }
#endif #endif
@ -2377,17 +2499,63 @@ namespace aux {
m_settings.connections_limit = m_connections.size(); m_settings.connections_limit = m_connections.size();
} }
// try again, but still alert the user of the problem // try again, but still alert the user of the problem
async_accept(listener); async_accept(listener, ssl);
} }
if (m_alerts.should_post<listen_failed_alert>()) if (m_alerts.should_post<listen_failed_alert>())
m_alerts.post_alert(listen_failed_alert(ep, e)); m_alerts.post_alert(listen_failed_alert(ep, e));
return; return;
} }
async_accept(listener); async_accept(listener, ssl);
#ifdef TORRENT_USE_OPENSSL
if (ssl)
{
// for SSL connections, incoming_connection() is called
// after the handshake is done
s->get<ssl_stream<stream_socket> >()->async_accept_handshake(
boost::bind(&session_impl::ssl_handshake, this, _1, s));
}
else
#endif
{
incoming_connection(s);
}
}
#ifdef TORRENT_USE_OPENSSL
// to test SSL connections, one can use this openssl command template:
//
// openssl s_client -cert <client-cert>.pem -key <client-private-key>.pem \
// -CAfile <torrent-cert>.pem -debug -connect 127.0.0.1:4433 -tls1 \
// -servername <hex-encoded-info-hash>
void session_impl::ssl_handshake(error_code const& ec, boost::shared_ptr<socket_type> s)
{
error_code e;
tcp::endpoint endp = s->remote_endpoint(e);
if (e) return;
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_logger) << time_now_string() << " *** peer SSL handshake done [ ip: "
<< endp << " ec: " << ec.message() << "]\n";
#endif
if (ec)
{
if (m_alerts.should_post<peer_error_alert>())
{
m_alerts.post_alert(peer_error_alert(torrent_handle(), endp
, peer_id(), ec));
}
return;
}
incoming_connection(s); incoming_connection(s);
} }
#endif // TORRENT_USE_OPENSSL
void session_impl::incoming_connection(boost::shared_ptr<socket_type> const& s) void session_impl::incoming_connection(boost::shared_ptr<socket_type> const& s)
{ {
TORRENT_ASSERT(is_network_thread()); TORRENT_ASSERT(is_network_thread());
@ -4701,7 +4869,7 @@ namespace aux {
return address(); return address();
} }
unsigned short session_impl::listen_port() const boost::uint16_t session_impl::listen_port() const
{ {
// if peer connections are set up to be received over a socks // if peer connections are set up to be received over a socks
// proxy, and it's the same one as we're using for the tracker // proxy, and it's the same one as we're using for the tracker
@ -4718,6 +4886,30 @@ namespace aux {
return m_listen_sockets.front().external_port; return m_listen_sockets.front().external_port;
} }
boost::uint16_t session_impl::ssl_listen_port() const
{
#ifdef TORRENT_USE_OPENSSL
// if peer connections are set up to be received over a socks
// proxy, and it's the same one as we're using for the tracker
// just tell the tracker the socks5 port we're listening on
if (m_socks_listen_socket && m_socks_listen_socket->is_open()
&& m_proxy.hostname == m_proxy.hostname)
return m_socks_listen_port;
// if not, don't tell the tracker anything if we're in anonymous
// mode. We don't want to leak our listen port since it can
// potentially identify us if it is leaked elsewere
if (m_settings.anonymous_mode) return 0;
if (m_listen_sockets.empty()) return 0;
for (std::list<listen_socket_t>::const_iterator i = m_listen_sockets.begin()
, end(m_listen_sockets.end()); i != end; ++i)
{
if (i->ssl) return i->external_port;
}
#endif
return 0;
}
void session_impl::announce_lsd(sha1_hash const& ih, int port, bool broadcast) void session_impl::announce_lsd(sha1_hash const& ih, int port, bool broadcast)
{ {
// use internal listen port for local peers // use internal listen port for local peers
@ -5354,8 +5546,7 @@ namespace aux {
if (m_listen_interface.port() > 0) if (m_listen_interface.port() > 0)
{ {
m_tcp_mapping[0] = m_natpmp->add_mapping(natpmp::tcp remap_tcp_ports(1, m_listen_interface.port(), ssl_listen_port());
, m_listen_interface.port(), m_listen_interface.port());
} }
if (m_udp_socket.is_open()) if (m_udp_socket.is_open())
{ {
@ -5387,10 +5578,9 @@ namespace aux {
m_upnp = u; m_upnp = u;
m_upnp->discover_device(); m_upnp->discover_device();
if (m_listen_interface.port() > 0) if (m_listen_interface.port() > 0 || ssl_listen_port() > 0)
{ {
m_tcp_mapping[1] = m_upnp->add_mapping(upnp::tcp remap_tcp_ports(2, m_listen_interface.port(), ssl_listen_port());
, m_listen_interface.port(), m_listen_interface.port());
} }
if (m_udp_socket.is_open()) if (m_udp_socket.is_open())
{ {
@ -5421,6 +5611,9 @@ namespace aux {
m_upnp->close(); m_upnp->close();
m_udp_mapping[1] = -1; m_udp_mapping[1] = -1;
m_tcp_mapping[1] = -1; m_tcp_mapping[1] = -1;
#ifdef TORRENT_USE_OPENSSL
m_ssl_mapping[1] = -1;
#endif
} }
m_upnp = 0; m_upnp = 0;
} }

View File

@ -1288,7 +1288,7 @@ namespace libtorrent
/* /*
bool verify_function(bool preverified, boost::asio::ssl::verify_context& ctx) bool verify_function(bool preverified, boost::asio::ssl::verify_context& ctx)
{ {
return false; return true;
} }
*/ */
@ -1334,7 +1334,7 @@ namespace libtorrent
// this is used for debugging // this is used for debugging
/* /*
#error there's a bug where the async_handshake on the ssl_stream always succeeds, regardless of the certificate failing. It's not a trivial bug in asio, that's been tested with a small repro program. #error there's a bug where the async_handshake on the ssl_stream always succeeds, regardless of the certificate failing. It's not a trivial bug in asio, that's been tested with a small repro program.
ctx->set_verify_callback(verify_function, ec); ctx->set_verify_callback(verify_function, ec);
if (ec) if (ec)
{ {
set_error(ec, "SSL verify callback"); set_error(ec, "SSL verify callback");
@ -1343,7 +1343,6 @@ ctx->set_verify_callback(verify_function, ec);
} }
*/ */
SSL_CTX* ssl_ctx = ctx->impl(); SSL_CTX* ssl_ctx = ctx->impl();
// create a new x.509 certificate store // create a new x.509 certificate store
X509_STORE* cert_store = X509_STORE_new(); X509_STORE* cert_store = X509_STORE_new();
if (!cert_store) if (!cert_store)
@ -1388,186 +1387,9 @@ ctx->set_verify_callback(verify_function, ec);
// tell the client we need a cert for this torrent // tell the client we need a cert for this torrent
alerts().post_alert(torrent_need_cert_alert(get_handle())); alerts().post_alert(torrent_need_cert_alert(get_handle()));
m_ssl_acceptor.reset(new listen_socket_t);
m_ses.setup_listener(m_ssl_acceptor.get()
, tcp::endpoint(address_v4::any(), m_ses.m_listen_interface.port())
, m_ses.m_listen_port_retries + 10, false, 0, ec);
if (!m_ssl_acceptor->sock)
{
set_error(ec, "ssl listen port");
pause();
return;
} }
// TODO: issue UPnP and NAT-PMP for this socket #endif // TORRENT_OPENSSL
async_accept(m_ssl_acceptor->sock);
set_allow_peers(false);
}
void torrent::async_accept(boost::shared_ptr<socket_acceptor> const& listener)
{
boost::shared_ptr<socket_type> c(new socket_type(m_ses.m_io_service));
c->instantiate<ssl_stream<stream_socket> >(m_ses.m_io_service, m_ssl_ctx.get());
#if defined TORRENT_ASIO_DEBUGGING
add_outstanding_async("torrent::on_accept_ssl_connection");
#endif
listener->async_accept(c->get<ssl_stream<stream_socket> >()->next_layer()
, boost::bind(&torrent::on_accept_ssl_connection, shared_from_this(), c
, boost::weak_ptr<socket_acceptor>(listener), _1));
}
void torrent::on_accept_ssl_connection(boost::shared_ptr<socket_type> const& s
, boost::weak_ptr<socket_acceptor> listen_socket, error_code const& e)
{
#if defined TORRENT_ASIO_DEBUGGING
complete_async("torrent::on_accept_ssl_connection");
#endif
// TODO: there's some code duplication with session_impl::on_accept_connection
boost::shared_ptr<socket_acceptor> listener = listen_socket.lock();
if (!listener) return;
if (e == asio::error::operation_aborted) return;
if (m_abort) return;
error_code ec;
if (e)
{
tcp::endpoint ep = listener->local_endpoint(ec);
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
std::string msg = "error accepting connection on '"
+ print_endpoint(ep) + "' " + e.message();
(*m_ses.m_logger) << msg << "\n";
#endif
#ifdef TORRENT_WINDOWS
// Windows sometimes generates this error. It seems to be
// non-fatal and we have to do another async_accept.
if (e.value() == ERROR_SEM_TIMEOUT)
{
async_accept(listener);
return;
}
#endif
#ifdef TORRENT_BSD
// Leopard sometimes generates an "invalid argument" error. It seems to be
// non-fatal and we have to do another async_accept.
if (e.value() == EINVAL)
{
async_accept(listener);
return;
}
#endif
if (alerts().should_post<listen_failed_alert>())
alerts().post_alert(listen_failed_alert(ep, e));
return;
}
async_accept(listener);
if (is_paused()) return;
// we got a connection request!
tcp::endpoint endp = s->remote_endpoint(ec);
if (ec)
{
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_ses.m_logger) << endp << " <== INCOMING CONNECTION FAILED, could "
"not retrieve remote endpoint " << ec.message() << "\n";
#endif
return;
}
if (alerts().should_post<incoming_connection_alert>())
{
alerts().post_alert(incoming_connection_alert(s->type(), endp));
}
if (!settings().enable_incoming_tcp)
{
if (alerts().should_post<peer_blocked_alert>())
alerts().post_alert(peer_blocked_alert(torrent_handle(), endp.address()));
return;
}
if (m_apply_ip_filter
&& m_ses.m_ip_filter.access(endp.address()) & ip_filter::blocked)
{
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_ses.m_logger) << "filtered blocked ip\n";
#endif
if (alerts().should_post<peer_blocked_alert>())
alerts().post_alert(peer_blocked_alert(get_handle(), endp.address()));
return;
}
if (m_connections.size() >= m_max_connections)
{
if (alerts().should_post<peer_disconnected_alert>())
{
alerts().post_alert(
peer_disconnected_alert(get_handle(), endp, peer_id()
, error_code(errors::too_many_connections, get_libtorrent_category())));
}
return;
}
m_ses.setup_socket_buffers(*s);
s->get<ssl_stream<stream_socket> >()->async_accept_handshake(boost::bind(&torrent::ssl_handshake
, shared_from_this(), _1, s));
}
void torrent::ssl_handshake(error_code const& ec, boost::shared_ptr<socket_type> s)
{
error_code e;
tcp::endpoint endp = s->remote_endpoint(e);
if (e) return;
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_ses.m_logger) << time_now_string() << " *** peer SSL handshake done [ ip: "
<< endp << " ec: " << ec.message() << "]\n";
#endif
if (ec)
{
if (alerts().should_post<peer_error_alert>())
{
alerts().post_alert(peer_error_alert(get_handle(), endp
, peer_id(), ec));
}
return;
}
boost::intrusive_ptr<peer_connection> c(
new bt_peer_connection(m_ses, shared_from_this(), s, endp, 0, false));
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
c->m_in_constructor = false;
#endif
if (c->is_disconnecting()) return;
if (!m_policy.new_connection(*c, m_ses.session_time()))
{
#if defined TORRENT_LOGGING
(*m_ses.m_logger) << time_now_string() << " CLOSING CONNECTION "
<< c->remote() << " policy::new_connection returned false (i.e. peer list full)\n";
#endif
c->disconnect(errors::too_many_connections);
return;
}
// add the newly connected peer to this torrent's peer list
m_connections.insert(boost::get_pointer(c));
m_ses.m_connections.insert(c);
c->start();
}
#endif
// this may not be called from a constructor because of the call to // this may not be called from a constructor because of the call to
// shared_from_this() // shared_from_this()
@ -2190,7 +2012,7 @@ ctx->set_verify_callback(verify_function, ec);
if (is_paused()) return; if (is_paused()) return;
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
int port = is_ssl_torrent() ? m_ssl_acceptor->external_port : m_ses.listen_port(); int port = is_ssl_torrent() ? m_ses.ssl_listen_port() : m_ses.listen_port();
#else #else
int port = m_ses.listen_port(); int port = m_ses.listen_port();
#endif #endif
@ -2212,7 +2034,7 @@ ctx->set_verify_callback(verify_function, ec);
TORRENT_ASSERT(m_allow_peers); TORRENT_ASSERT(m_allow_peers);
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
int port = is_ssl_torrent() ? m_ssl_acceptor->external_port : m_ses.listen_port(); int port = is_ssl_torrent() ? m_ses.ssl_listen_port() : m_ses.listen_port();
#else #else
int port = m_ses.listen_port(); int port = m_ses.listen_port();
#endif #endif
@ -2311,7 +2133,7 @@ ctx->set_verify_callback(verify_function, ec);
// TODO: this pattern is repeated in a few places. Factor this into // TODO: this pattern is repeated in a few places. Factor this into
// a function and generalize the concept of a torrent having a // a function and generalize the concept of a torrent having a
// dedicated listen port // dedicated listen port
if (is_ssl_torrent()) req.listen_port = m_ssl_acceptor->external_port; if (is_ssl_torrent()) req.listen_port = m_ses.ssl_listen_port();
else else
#endif #endif
req.listen_port = m_ses.listen_port(); req.listen_port = m_ses.listen_port();
@ -3461,12 +3283,6 @@ ctx->set_verify_callback(verify_function, ec);
m_ses.m_encrypted_torrents.erase(shared_from_this()); m_ses.m_encrypted_torrents.erase(shared_from_this());
m_in_encrypted_list = false; m_in_encrypted_list = false;
} }
if (m_ssl_acceptor && m_ssl_acceptor->sock)
{
error_code ec;
m_ssl_acceptor->sock->close(ec);
}
#endif #endif
m_abort = true; m_abort = true;
@ -5530,6 +5346,26 @@ ctx->set_verify_callback(verify_function, ec);
bool ret = instantiate_connection(m_ses.m_io_service, m_ses.proxy(), *s, userdata, sm, true); bool ret = instantiate_connection(m_ses.m_io_service, m_ses.proxy(), *s, userdata, sm, true);
(void)ret; (void)ret;
TORRENT_ASSERT(ret); TORRENT_ASSERT(ret);
#ifdef TORRENT_USE_OPENSSL
if (is_ssl_torrent())
{
// for ssl sockets, set the hostname
std::string host_name = to_hex(m_torrent_file->info_hash().to_string());
#define CASE(t) case socket_type_int_impl<ssl_stream<t> >::value: \
s->get<ssl_stream<t> >()->set_host_name(host_name); break;
switch (s->type())
{
CASE(stream_socket)
CASE(socks5_stream)
CASE(http_stream)
CASE(utp_stream)
default: break;
};
}
#endif
} }
m_ses.setup_socket_buffers(*s); m_ses.setup_socket_buffers(*s);
@ -5649,6 +5485,49 @@ ctx->set_verify_callback(verify_function, ec);
{ {
// INVARIANT_CHECK; // INVARIANT_CHECK;
#ifdef TORRENT_USE_OPENSSL
if (is_ssl_torrent())
{
// if this is an SSL torrent, don't allow non SSL peers on it
boost::shared_ptr<socket_type> s = p->get_socket();
//
#define SSL(t) socket_type_int_impl<ssl_stream<t> >::value: \
ssl_conn = s->get<ssl_stream<t> >()->native_handle(); \
break;
SSL* ssl_conn = 0;
switch (s->type())
{
case SSL(stream_socket)
case SSL(socks5_stream)
case SSL(http_stream)
case SSL(utp_stream)
};
#undef SSL
if (ssl_conn == 0)
{
// don't allow non SSL peers on SSL torrents
p->disconnect(errors::requires_ssl_connection);
return false;
}
if (SSL_get_SSL_CTX(ssl_conn) != m_ssl_ctx->native_handle())
{
// if the SSL_CTX associated with this connection is
// not the one belonging to this torrent, the SSL handshake
// connected to one torrent, and the BitTorrent protocol
// to a different one. This is probably an attempt to circumvent
// access control. Don't allow it.
p->disconnect(errors::invalid_ssl_cert);
return false;
}
}
#endif // TORRENT_USE_OPENSSL
TORRENT_ASSERT(p != 0); TORRENT_ASSERT(p != 0);
TORRENT_ASSERT(!p->is_local()); TORRENT_ASSERT(!p->is_local());
@ -8053,7 +7932,7 @@ ctx->set_verify_callback(verify_function, ec);
st->listen_port = 0; st->listen_port = 0;
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
if (is_ssl_torrent() && m_ssl_acceptor) st->listen_port = m_ssl_acceptor->external_port; if (is_ssl_torrent()) st->listen_port = m_ses.ssl_listen_port();
#endif #endif
st->has_incoming = m_has_incoming; st->has_incoming = m_has_incoming;