merged uTP branch into trunk (yay)
This commit is contained in:
parent
5a1669cf03
commit
e5f980d80d
@ -31,6 +31,7 @@ set(sources
|
|||||||
http_seed_connection
|
http_seed_connection
|
||||||
instantiate_connection
|
instantiate_connection
|
||||||
natpmp
|
natpmp
|
||||||
|
packet_buffer
|
||||||
piece_picker
|
piece_picker
|
||||||
policy
|
policy
|
||||||
puff
|
puff
|
||||||
@ -206,6 +207,7 @@ endif(MSVC)
|
|||||||
|
|
||||||
add_definitions(-D_FILE_OFFSET_BITS=64)
|
add_definitions(-D_FILE_OFFSET_BITS=64)
|
||||||
add_definitions(-DBOOST_DISABLE_EXCEPTION)
|
add_definitions(-DBOOST_DISABLE_EXCEPTION)
|
||||||
|
add_definitions(-DBOOST_ASIO_ENABLE_CANCELIO)
|
||||||
|
|
||||||
if (tcmalloc)
|
if (tcmalloc)
|
||||||
target_link_libraries(torrent-rasterbar tcmalloc)
|
target_link_libraries(torrent-rasterbar tcmalloc)
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
* support trackerid tracker extension
|
* support trackerid tracker extension
|
||||||
* graceful peer disconnect mode which finishes transactions before disconnecting peers
|
* graceful peer disconnect mode which finishes transactions before disconnecting peers
|
||||||
* support chunked encoding for web seeds
|
* support chunked encoding for web seeds
|
||||||
|
* uTP protocol support
|
||||||
|
* resistance towards certain flood attacks
|
||||||
|
* support chunked encoding for web seeds (only for BEP 19, web seeds)
|
||||||
* optimized session startup time
|
* optimized session startup time
|
||||||
* support SSL for web seeds, through all proxies
|
* support SSL for web seeds, through all proxies
|
||||||
* support extending web seeds with custom authorization and extra headers
|
* support extending web seeds with custom authorization and extra headers
|
||||||
|
10
Jamfile
10
Jamfile
@ -81,8 +81,9 @@ rule linking ( properties * )
|
|||||||
{
|
{
|
||||||
result += <library>ws2_32
|
result += <library>ws2_32
|
||||||
<library>wsock32
|
<library>wsock32
|
||||||
|
<library>iphlpapi
|
||||||
<define>WIN32_LEAN_AND_MEAN
|
<define>WIN32_LEAN_AND_MEAN
|
||||||
<define>_WIN32_WINNT=0x0500
|
<define>_WIN32_WINNT=0x0600
|
||||||
<define>__USE_W32_SOCKETS
|
<define>__USE_W32_SOCKETS
|
||||||
<define>WIN32
|
<define>WIN32
|
||||||
<define>_WIN32
|
<define>_WIN32
|
||||||
@ -353,6 +354,7 @@ lib GeoIP : : <name>GeoIP <link>shared ;
|
|||||||
# socket libraries on windows
|
# socket libraries on windows
|
||||||
lib wsock32 : : <name>wsock32 <link>shared ;
|
lib wsock32 : : <name>wsock32 <link>shared ;
|
||||||
lib ws2_32 : : <name>ws2_32 <link>shared ;
|
lib ws2_32 : : <name>ws2_32 <link>shared ;
|
||||||
|
lib iphlpapi : : <name>iphlpapi <link>shared ;
|
||||||
|
|
||||||
SOURCES =
|
SOURCES =
|
||||||
alert
|
alert
|
||||||
@ -384,6 +386,7 @@ SOURCES =
|
|||||||
i2p_stream
|
i2p_stream
|
||||||
instantiate_connection
|
instantiate_connection
|
||||||
natpmp
|
natpmp
|
||||||
|
packet_buffer
|
||||||
piece_picker
|
piece_picker
|
||||||
policy
|
policy
|
||||||
puff
|
puff
|
||||||
@ -403,8 +406,11 @@ SOURCES =
|
|||||||
http_tracker_connection
|
http_tracker_connection
|
||||||
udp_tracker_connection
|
udp_tracker_connection
|
||||||
sha1
|
sha1
|
||||||
|
timestamp_history
|
||||||
udp_socket
|
udp_socket
|
||||||
upnp
|
upnp
|
||||||
|
utp_socket_manager
|
||||||
|
utp_stream
|
||||||
logger
|
logger
|
||||||
file_pool
|
file_pool
|
||||||
lsd
|
lsd
|
||||||
@ -443,6 +449,8 @@ local usage-requirements =
|
|||||||
<variant>debug:<define>TORRENT_DEBUG
|
<variant>debug:<define>TORRENT_DEBUG
|
||||||
<define>_FILE_OFFSET_BITS=64
|
<define>_FILE_OFFSET_BITS=64
|
||||||
<define>BOOST_EXCEPTION_DISABLE
|
<define>BOOST_EXCEPTION_DISABLE
|
||||||
|
# enable cancel support in asio
|
||||||
|
<define>BOOST_ASIO_ENABLE_CANCELIO
|
||||||
<conditional>@linking
|
<conditional>@linking
|
||||||
# these compiler settings just makes the compiler standard conforming
|
# these compiler settings just makes the compiler standard conforming
|
||||||
<toolset>msvc:<cflags>/Zc:wchar_t
|
<toolset>msvc:<cflags>/Zc:wchar_t
|
||||||
|
@ -593,6 +593,9 @@ COMPILETIME_OPTIONS+="-DBOOST_ASIO_HASH_MAP_BUCKETS=1021 "
|
|||||||
AC_DEFINE([BOOST_EXCEPTION_DISABLE],[1],[Define to disable the boost.exception features.])
|
AC_DEFINE([BOOST_EXCEPTION_DISABLE],[1],[Define to disable the boost.exception features.])
|
||||||
COMPILETIME_OPTIONS+="-DBOOST_EXCEPTION_DISABLE "
|
COMPILETIME_OPTIONS+="-DBOOST_EXCEPTION_DISABLE "
|
||||||
|
|
||||||
|
AC_DEFINE([BOOST_ASIO_ENABLE_CANCELIO],[1],[Define to enable cancel support in asio on windows XP and older.])
|
||||||
|
COMPILETIME_OPTIONS+="-DBOOST_ASIO_ENABLE_CANCELIO "
|
||||||
|
|
||||||
dnl Use possibly specific python install params
|
dnl Use possibly specific python install params
|
||||||
AC_ARG_VAR([PYTHON_INSTALL_PARAMS], [Set specific install parameters for python bindings.])
|
AC_ARG_VAR([PYTHON_INSTALL_PARAMS], [Set specific install parameters for python bindings.])
|
||||||
AS_IF([test "x$PYTHON_INSTALL_PARAMS" = "x"],
|
AS_IF([test "x$PYTHON_INSTALL_PARAMS" = "x"],
|
||||||
|
BIN
docs/cwnd.png
Normal file
BIN
docs/cwnd.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
BIN
docs/cwnd_thumb.png
Normal file
BIN
docs/cwnd_thumb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
docs/delays.png
Normal file
BIN
docs/delays.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
docs/delays_thumb.png
Normal file
BIN
docs/delays_thumb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
@ -56,12 +56,13 @@
|
|||||||
<li><a class="reference internal" href="#high-performance-disk-subsystem" id="id9">high performance disk subsystem</a></li>
|
<li><a class="reference internal" href="#high-performance-disk-subsystem" id="id9">high performance disk subsystem</a></li>
|
||||||
<li><a class="reference internal" href="#network-buffers" id="id10">network buffers</a></li>
|
<li><a class="reference internal" href="#network-buffers" id="id10">network buffers</a></li>
|
||||||
<li><a class="reference internal" href="#piece-picker" id="id11">piece picker</a></li>
|
<li><a class="reference internal" href="#piece-picker" id="id11">piece picker</a></li>
|
||||||
<li><a class="reference internal" href="#merkle-hash-tree-torrents" id="id12">merkle hash tree torrents</a></li>
|
<li><a class="reference internal" href="#share-mode" id="id12">share mode</a></li>
|
||||||
<li><a class="reference internal" href="#customizable-file-storage" id="id13">customizable file storage</a></li>
|
<li><a class="reference internal" href="#merkle-hash-tree-torrents" id="id13">merkle hash tree torrents</a></li>
|
||||||
<li><a class="reference internal" href="#easy-to-use-api" id="id14">easy to use API</a></li>
|
<li><a class="reference internal" href="#customizable-file-storage" id="id14">customizable file storage</a></li>
|
||||||
|
<li><a class="reference internal" href="#easy-to-use-api" id="id15">easy to use API</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a class="reference internal" href="#portability" id="id15">portability</a></li>
|
<li><a class="reference internal" href="#portability" id="id16">portability</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="introduction">
|
<div class="section" id="introduction">
|
||||||
@ -97,9 +98,12 @@ uTorrent interpretation).</li>
|
|||||||
<li>supports the <tt class="docutils literal"><span class="pre">compact=1</span></tt> tracker parameter.</li>
|
<li>supports the <tt class="docutils literal"><span class="pre">compact=1</span></tt> tracker parameter.</li>
|
||||||
<li>super seeding/initial seeding (<a class="reference external" href="http://bittorrent.org/beps/bep_0016.html">BEP 16</a>).</li>
|
<li>super seeding/initial seeding (<a class="reference external" href="http://bittorrent.org/beps/bep_0016.html">BEP 16</a>).</li>
|
||||||
<li>private torrents (<a class="reference external" href="http://bittorrent.org/beps/bep_0027.html">BEP 27</a>).</li>
|
<li>private torrents (<a class="reference external" href="http://bittorrent.org/beps/bep_0027.html">BEP 27</a>).</li>
|
||||||
|
<li>upload-only extension (<a class="reference external" href="http://bittorrent.org/beps/bep_0021.html">BEP 21</a>).</li>
|
||||||
<li>support for IPv6, including <a class="reference external" href="http://bittorrent.org/beps/bep_0007.html">BEP 7</a> and <a class="reference external" href="http://bittorrent.org/beps/bep_0024.html">BEP 24</a>.</li>
|
<li>support for IPv6, including <a class="reference external" href="http://bittorrent.org/beps/bep_0007.html">BEP 7</a> and <a class="reference external" href="http://bittorrent.org/beps/bep_0024.html">BEP 24</a>.</li>
|
||||||
<li>support for merkle hash tree torrents. This makes the size of torrent files
|
<li>support for merkle hash tree torrents. This makes the size of torrent files
|
||||||
scale well with the size of the content.</li>
|
scale well with the size of the content.</li>
|
||||||
|
<li>share-mode. This is a special mode torrents can be put in to optimize share
|
||||||
|
ratio rather than downloading the torrent.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="disk-management">
|
<div class="section" id="disk-management">
|
||||||
@ -124,6 +128,8 @@ piece's hash is verified the first time it is requested.</li>
|
|||||||
<div class="section" id="network">
|
<div class="section" id="network">
|
||||||
<h2>network</h2>
|
<h2>network</h2>
|
||||||
<ul class="simple">
|
<ul class="simple">
|
||||||
|
<li>a high quality uTP implementation (<a href="#id17"><span class="problematic" id="id18">BEP29_</span></a>). A transport protocol with
|
||||||
|
delay based congestion control. See separate <a class="reference external" href="utp.html">article</a>.</li>
|
||||||
<li>adjusts the length of the request queue depending on download rate.</li>
|
<li>adjusts the length of the request queue depending on download rate.</li>
|
||||||
<li>serves multiple torrents on a single port and in a single thread</li>
|
<li>serves multiple torrents on a single port and in a single thread</li>
|
||||||
<li>piece picking on block-level (as opposed to piece-level).
|
<li>piece picking on block-level (as opposed to piece-level).
|
||||||
@ -253,6 +259,15 @@ makes slow peers pick blocks from the same piece, and fast peers pick from the s
|
|||||||
and hence decreasing the likelihood of slow peers blocking the completion of pieces.</p>
|
and hence decreasing the likelihood of slow peers blocking the completion of pieces.</p>
|
||||||
<p>The piece picker can also be set to download pieces in sequential order.</p>
|
<p>The piece picker can also be set to download pieces in sequential order.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="section" id="share-mode">
|
||||||
|
<h2>share mode</h2>
|
||||||
|
<p>The share mode feature in libtorrent is intended for users who are only interested in
|
||||||
|
helping out swarms, not downloading the torrents.</p>
|
||||||
|
<p>It works by predicting the demand for pieces, and only download pieces if there is enough
|
||||||
|
demand. New pieces will only be downloaded once the share ratio has hit a certain target.</p>
|
||||||
|
<p>This feature is especially useful when combined with RSS, so that a client can be set up
|
||||||
|
to provide additional bandwidth to an entire feed.</p>
|
||||||
|
</div>
|
||||||
<div class="section" id="merkle-hash-tree-torrents">
|
<div class="section" id="merkle-hash-tree-torrents">
|
||||||
<h2>merkle hash tree torrents</h2>
|
<h2>merkle hash tree torrents</h2>
|
||||||
<p>Merkle hash tree torrents is an extension that lets a torrent file only contain the
|
<p>Merkle hash tree torrents is an extension that lets a torrent file only contain the
|
||||||
@ -363,6 +378,12 @@ epoll on linux and kqueue on MacOS X and BSD.</p>
|
|||||||
<li>GCC 2.95.4</li>
|
<li>GCC 2.95.4</li>
|
||||||
<li>msvc6</li>
|
<li>msvc6</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="system-messages section">
|
||||||
|
<h1>Docutils System Messages</h1>
|
||||||
|
<div class="system-message" id="id17">
|
||||||
|
<p class="system-message-title">System Message: ERROR/3 (<tt class="docutils">features.rst</tt>, line 82); <em><a href="#id18">backlink</a></em></p>
|
||||||
|
Unknown target name: "bep29".</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
|
@ -52,6 +52,7 @@ extensions
|
|||||||
* share-mode. This is a special mode torrents can be put in to optimize share
|
* share-mode. This is a special mode torrents can be put in to optimize share
|
||||||
ratio rather than downloading the torrent.
|
ratio rather than downloading the torrent.
|
||||||
|
|
||||||
|
.. _article: utp.html
|
||||||
.. _extensions: manual.html#extensions
|
.. _extensions: manual.html#extensions
|
||||||
.. _`http seeding`: manual.html#http-seeding
|
.. _`http seeding`: manual.html#http-seeding
|
||||||
|
|
||||||
@ -78,6 +79,8 @@ disk management
|
|||||||
network
|
network
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
* a high quality uTP implementation (BEP29_). A transport protocol with
|
||||||
|
delay based congestion control. See separate article_.
|
||||||
* adjusts the length of the request queue depending on download rate.
|
* adjusts the length of the request queue depending on download rate.
|
||||||
* serves multiple torrents on a single port and in a single thread
|
* serves multiple torrents on a single port and in a single thread
|
||||||
* piece picking on block-level (as opposed to piece-level).
|
* piece picking on block-level (as opposed to piece-level).
|
||||||
@ -116,6 +119,7 @@ network
|
|||||||
.. _`BEP 21`: http://bittorrent.org/beps/bep_0021.html
|
.. _`BEP 21`: http://bittorrent.org/beps/bep_0021.html
|
||||||
.. _`BEP 24`: http://bittorrent.org/beps/bep_0024.html
|
.. _`BEP 24`: http://bittorrent.org/beps/bep_0024.html
|
||||||
.. _`BEP 27`: http://bittorrent.org/beps/bep_0027.html
|
.. _`BEP 27`: http://bittorrent.org/beps/bep_0027.html
|
||||||
|
.. _`BEP 29`: http://bittorrent.org/beps/bep_0029.html
|
||||||
.. _`extension protocol`: extension_protocol.html
|
.. _`extension protocol`: extension_protocol.html
|
||||||
|
|
||||||
highlighted features
|
highlighted features
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
<hr class="docutils" />
|
<hr class="docutils" />
|
||||||
<p>Extensions</p>
|
<p>Extensions</p>
|
||||||
<ul class="simple">
|
<ul class="simple">
|
||||||
|
<li><a class="reference external" href="utp.html">uTP</a></li>
|
||||||
<li><a class="reference external" href="extension_protocol.html">extensions protocol</a></li>
|
<li><a class="reference external" href="extension_protocol.html">extensions protocol</a></li>
|
||||||
<li><a class="reference external" href="libtorrent_plugins.html">plugin interface</a></li>
|
<li><a class="reference external" href="libtorrent_plugins.html">plugin interface</a></li>
|
||||||
<li><a class="reference external" href="dht_extensions.html">DHT extensions</a></li>
|
<li><a class="reference external" href="dht_extensions.html">DHT extensions</a></li>
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
Extensions
|
Extensions
|
||||||
|
|
||||||
|
* `uTP`_
|
||||||
* `extensions protocol`_
|
* `extensions protocol`_
|
||||||
* `plugin interface`_
|
* `plugin interface`_
|
||||||
* `DHT extensions`_
|
* `DHT extensions`_
|
||||||
@ -59,6 +60,7 @@ libtorrent
|
|||||||
.. _`running tests`: running_tests.html
|
.. _`running tests`: running_tests.html
|
||||||
.. _`tuning`: tuning.html
|
.. _`tuning`: tuning.html
|
||||||
.. _screenshot: client_test.png
|
.. _screenshot: client_test.png
|
||||||
|
.. _`uTP`: utp.html
|
||||||
.. _`extensions protocol`: extension_protocol.html
|
.. _`extensions protocol`: extension_protocol.html
|
||||||
.. _`plugin interface`: libtorrent_plugins.html
|
.. _`plugin interface`: libtorrent_plugins.html
|
||||||
.. _`DHT extensions`: dht_extensions.html
|
.. _`DHT extensions`: dht_extensions.html
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
<tbody valign="top">
|
<tbody valign="top">
|
||||||
<tr><th class="docinfo-name">Author:</th>
|
<tr><th class="docinfo-name">Author:</th>
|
||||||
<td>Arvid Norberg, <a class="last reference external" href="mailto:arvid@rasterbar.com">arvid@rasterbar.com</a></td></tr>
|
<td>Arvid Norberg, <a class="last reference external" href="mailto:arvid@rasterbar.com">arvid@rasterbar.com</a></td></tr>
|
||||||
|
<tr><th class="docinfo-name">Version:</th>
|
||||||
|
<td>0.16.0</td></tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div class="contents topic" id="table-of-contents">
|
<div class="contents topic" id="table-of-contents">
|
||||||
@ -58,7 +60,7 @@
|
|||||||
<li><a class="reference internal" href="#set-creator" id="id14">set_creator()</a></li>
|
<li><a class="reference internal" href="#set-creator" id="id14">set_creator()</a></li>
|
||||||
<li><a class="reference internal" href="#set-hash" id="id15">set_hash()</a></li>
|
<li><a class="reference internal" href="#set-hash" id="id15">set_hash()</a></li>
|
||||||
<li><a class="reference internal" href="#set-file-hash" id="id16">set_file_hash()</a></li>
|
<li><a class="reference internal" href="#set-file-hash" id="id16">set_file_hash()</a></li>
|
||||||
<li><a class="reference internal" href="#add-url-seed" id="id17">add_url_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-priv-priv" id="id20">set_priv() priv()</a></li>
|
||||||
@ -291,6 +293,7 @@ struct create_torrent
|
|||||||
void set_hash(int index, sha1_hash const& h);
|
void set_hash(int index, sha1_hash const& h);
|
||||||
void set_file_hash(int index, sha1_hash const& h);
|
void set_file_hash(int index, sha1_hash const& h);
|
||||||
void add_url_seed(std::string const& url);
|
void add_url_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_priv(bool p);
|
void set_priv(bool p);
|
||||||
@ -433,11 +436,12 @@ void set_file_hash(int index, sha1_hash const& h);
|
|||||||
associated with this file (for multi-file torrents) or in the root info dictionary
|
associated with this file (for multi-file torrents) or in the root info dictionary
|
||||||
for single-file torrents.</p>
|
for single-file torrents.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="add-url-seed">
|
<div class="section" id="add-url-seed-add-http-seed">
|
||||||
<h2>add_url_seed()</h2>
|
<h2>add_url_seed() add_http_seed()</h2>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<pre class="literal-block">
|
<pre class="literal-block">
|
||||||
void add_url_seed(std::string const& url);
|
void add_url_seed(std::string const& url);
|
||||||
|
void add_http_seed(std::string const& url);
|
||||||
</pre>
|
</pre>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
<p>This adds a url seed to the torrent. You can have any number of url seeds. For a
|
<p>This adds a url seed to the torrent. You can have any number of url seeds. For a
|
||||||
@ -445,6 +449,7 @@ single file torrent, this should be an HTTP url, pointing to a file with identic
|
|||||||
content as the file of the torrent. For a multi-file torrent, it should point to
|
content as the file of the torrent. For a multi-file torrent, it should point to
|
||||||
a directory containing a directory with the same name as this torrent, and all the
|
a directory containing a directory with the same name as this torrent, and all the
|
||||||
files of the torrent in it.</p>
|
files of the torrent in it.</p>
|
||||||
|
<p>The second function, <tt class="docutils literal"><span class="pre">add_http_seed()</span></tt> adds an HTTP seed instead.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="add-node">
|
<div class="section" id="add-node">
|
||||||
<h2>add_node()</h2>
|
<h2>add_node()</h2>
|
||||||
|
@ -3,6 +3,7 @@ creating torrents
|
|||||||
=================
|
=================
|
||||||
|
|
||||||
:Author: Arvid Norberg, arvid@rasterbar.com
|
:Author: Arvid Norberg, arvid@rasterbar.com
|
||||||
|
:Version: 0.16.0
|
||||||
|
|
||||||
.. contents:: Table of contents
|
.. contents:: Table of contents
|
||||||
:depth: 2
|
:depth: 2
|
||||||
|
@ -17,6 +17,7 @@ TARGETS = index \
|
|||||||
python_binding \
|
python_binding \
|
||||||
projects \
|
projects \
|
||||||
running_tests \
|
running_tests \
|
||||||
|
utp \
|
||||||
tuning
|
tuning
|
||||||
|
|
||||||
FIGURES = read_disk_buffers write_disk_buffers
|
FIGURES = read_disk_buffers write_disk_buffers
|
||||||
|
1063
docs/manual.html
1063
docs/manual.html
File diff suppressed because it is too large
Load Diff
133
docs/manual.rst
133
docs/manual.rst
@ -618,6 +618,15 @@ struct has the following members::
|
|||||||
int branch_factor;
|
int branch_factor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct utp_status
|
||||||
|
{
|
||||||
|
int num_idle;
|
||||||
|
int num_syn_sent;
|
||||||
|
int num_connected;
|
||||||
|
int num_fin_sent;
|
||||||
|
int num_close_wait;
|
||||||
|
};
|
||||||
|
|
||||||
struct session_status
|
struct session_status
|
||||||
{
|
{
|
||||||
bool has_incoming_connections;
|
bool has_incoming_connections;
|
||||||
@ -663,6 +672,8 @@ struct has the following members::
|
|||||||
size_type dht_global_nodes;
|
size_type dht_global_nodes;
|
||||||
std::vector<dht_lookup> active_requests;
|
std::vector<dht_lookup> active_requests;
|
||||||
int dht_total_allocations;
|
int dht_total_allocations;
|
||||||
|
|
||||||
|
utp_status utp_stats;
|
||||||
};
|
};
|
||||||
|
|
||||||
``has_incoming_connections`` is false as long as no incoming connections have been
|
``has_incoming_connections`` is false as long as no incoming connections have been
|
||||||
@ -730,6 +741,8 @@ network.
|
|||||||
particular DHT lookup. This represents roughly the amount of memory used
|
particular DHT lookup. This represents roughly the amount of memory used
|
||||||
by the DHT.
|
by the DHT.
|
||||||
|
|
||||||
|
``utp_stats`` contains statistics on the uTP sockets.
|
||||||
|
|
||||||
get_cache_status()
|
get_cache_status()
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
@ -1074,7 +1087,6 @@ struct has the following members::
|
|||||||
{
|
{
|
||||||
int max_peers_reply;
|
int max_peers_reply;
|
||||||
int search_branching;
|
int search_branching;
|
||||||
int service_port;
|
|
||||||
int max_fail_count;
|
int max_fail_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1085,19 +1097,18 @@ response to a ``get_peers`` message from another node.
|
|||||||
send when announcing and refreshing the routing table. This parameter is
|
send when announcing and refreshing the routing table. This parameter is
|
||||||
called alpha in the kademlia paper.
|
called alpha in the kademlia paper.
|
||||||
|
|
||||||
``service_port`` is the udp port the node will listen to. This will default
|
|
||||||
to 0, which means the udp listen port will be the same as the tcp listen
|
|
||||||
port. This is in general a good idea, since some NAT implementations
|
|
||||||
reserves the udp port for any mapped tcp port, and vice versa. NAT-PMP
|
|
||||||
guarantees this for example.
|
|
||||||
|
|
||||||
``max_fail_count`` is the maximum number of failed tries to contact a node
|
``max_fail_count`` is the maximum number of failed tries to contact a node
|
||||||
before it is removed from the routing table. If there are known working nodes
|
before it is removed from the routing table. If there are known working nodes
|
||||||
that are ready to replace a failing node, it will be replaced immediately,
|
that are ready to replace a failing node, it will be replaced immediately,
|
||||||
this limit is only used to clear out nodes that don't have any node that can
|
this limit is only used to clear out nodes that don't have any node that can
|
||||||
replace them.
|
replace them.
|
||||||
|
|
||||||
``is_dht_running`` returns true if the DHT support has been started and false
|
The ``dht_settings`` struct used to contain a ``service_port`` member to control
|
||||||
|
which port the DHT would listen on and send messages from. This field is deprecated
|
||||||
|
and ignored. libtorrent always tries to open the UDP socket on the same port
|
||||||
|
as the TCP socket.
|
||||||
|
|
||||||
|
``is_dht_running()`` returns true if the DHT support has been started and false
|
||||||
otherwise.
|
otherwise.
|
||||||
|
|
||||||
|
|
||||||
@ -3387,6 +3398,7 @@ It contains the following fields::
|
|||||||
optimistic_unchoke = 0x800,
|
optimistic_unchoke = 0x800,
|
||||||
snubbed = 0x1000,
|
snubbed = 0x1000,
|
||||||
upload_only = 0x2000,
|
upload_only = 0x2000,
|
||||||
|
holepunched = 0x4000,
|
||||||
rc4_encrypted = 0x100000,
|
rc4_encrypted = 0x100000,
|
||||||
plaintext_encrypted = 0x200000
|
plaintext_encrypted = 0x200000
|
||||||
};
|
};
|
||||||
@ -3535,6 +3547,11 @@ any combination of the enums above. The following table describes each flag:
|
|||||||
| | will not downloading anything more, regardless of |
|
| | will not downloading anything more, regardless of |
|
||||||
| | which pieces we have. |
|
| | which pieces we have. |
|
||||||
+-------------------------+-------------------------------------------------------+
|
+-------------------------+-------------------------------------------------------+
|
||||||
|
| ``holepunched`` | This flag is set if the peer was in holepunch mode |
|
||||||
|
| | when the connection succeeded. This typically only |
|
||||||
|
| | happens if both peers are behind a NAT and the peers |
|
||||||
|
| | connect via the NAT holepunch mechanism. |
|
||||||
|
+-------------------------+-------------------------------------------------------+
|
||||||
|
|
||||||
__ extension_protocol.html
|
__ extension_protocol.html
|
||||||
|
|
||||||
@ -3673,8 +3690,19 @@ that may give away something about which software is running in the other end.
|
|||||||
In the case of a web seed, the server type and version will be a part of this
|
In the case of a web seed, the server type and version will be a part of this
|
||||||
string.
|
string.
|
||||||
|
|
||||||
``connection_type`` can currently be one of ``standard_bittorrent`` or
|
``connection_type`` can currently be one of:
|
||||||
``web_seed``. These are currently the only implemented protocols.
|
|
||||||
|
+---------------------------------------+-------------------------------------------------------+
|
||||||
|
| type | meaning |
|
||||||
|
+=======================================+=======================================================+
|
||||||
|
| ``peer_info::standard_bittorrent`` | Regular bittorrent connection over TCP |
|
||||||
|
+---------------------------------------+-------------------------------------------------------+
|
||||||
|
| ``peer_info::bittorrent_utp`` | Bittorrent connection over uTP |
|
||||||
|
+---------------------------------------+-------------------------------------------------------+
|
||||||
|
| ``peer_info::web_sesed`` | HTTP connection using the `BEP 19`_ protocol |
|
||||||
|
+---------------------------------------+-------------------------------------------------------+
|
||||||
|
| ``peer_info::http_seed`` | HTTP connection using the `BEP 17`_ protocol |
|
||||||
|
+---------------------------------------+-------------------------------------------------------+
|
||||||
|
|
||||||
``remote_dl_rate`` is an estimate of the rate this peer is downloading at, in
|
``remote_dl_rate`` is an estimate of the rate this peer is downloading at, in
|
||||||
bytes per second.
|
bytes per second.
|
||||||
@ -3927,10 +3955,17 @@ session_settings
|
|||||||
int default_peer_upload_rate;
|
int default_peer_upload_rate;
|
||||||
int default_peer_download_rate;
|
int default_peer_download_rate;
|
||||||
bool broadcast_lsd;
|
bool broadcast_lsd;
|
||||||
|
|
||||||
|
bool enable_outgoing_utp;
|
||||||
|
bool enable_incoming_utp;
|
||||||
|
bool enable_outgoing_tcp;
|
||||||
|
bool enable_incoming_tcp;
|
||||||
|
int max_pex_peers;
|
||||||
bool ignore_resume_timestamps;
|
bool ignore_resume_timestamps;
|
||||||
bool anonymous_mode;
|
bool anonymous_mode;
|
||||||
int tick_interval;
|
int tick_interval;
|
||||||
int share_mode_target;
|
int share_mode_target;
|
||||||
|
|
||||||
int upload_rate_limit;
|
int upload_rate_limit;
|
||||||
int download_rate_limit;
|
int download_rate_limit;
|
||||||
int local_upload_rate_limit;
|
int local_upload_rate_limit;
|
||||||
@ -3939,6 +3974,24 @@ session_settings
|
|||||||
int half_open_limit;
|
int half_open_limit;
|
||||||
int connections_limit;
|
int connections_limit;
|
||||||
|
|
||||||
|
int utp_target_delay;
|
||||||
|
int utp_gain_factor;
|
||||||
|
int utp_min_timeout;
|
||||||
|
int utp_syn_resends;
|
||||||
|
int utp_num_resends;
|
||||||
|
int utp_connect_timeout;
|
||||||
|
int utp_delayed_ack;
|
||||||
|
bool utp_dynamic_sock_buf;
|
||||||
|
|
||||||
|
enum bandwidth_mixed_algo_t
|
||||||
|
{
|
||||||
|
prefer_tcp = 0,
|
||||||
|
peer_proportional = 1
|
||||||
|
|
||||||
|
};
|
||||||
|
int mixed_mode_algorithm;
|
||||||
|
bool rate_limit_utp;
|
||||||
|
|
||||||
int listen_queue_size;
|
int listen_queue_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -4604,6 +4657,11 @@ if ``broadcast_lsd`` is set to true, the local peer discovery
|
|||||||
broadcast its messages. This can be useful when running on networks
|
broadcast its messages. This can be useful when running on networks
|
||||||
that don't support multicast. It's off by default since it's inefficient.
|
that don't support multicast. It's off by default since it's inefficient.
|
||||||
|
|
||||||
|
``enable_outgoing_utp``, ``enable_incoming_utp``, ``enable_outgoing_tcp``,
|
||||||
|
``enable_incoming_tcp`` all determines if libtorrent should attempt to make
|
||||||
|
outgoing connections of the specific type, or allow incoming connection. By
|
||||||
|
default all of them are enabled.
|
||||||
|
|
||||||
``ignore_resume_timestamps`` determines if the storage, when loading
|
``ignore_resume_timestamps`` determines if the storage, when loading
|
||||||
resume data files, should verify that the file modification time
|
resume data files, should verify that the file modification time
|
||||||
with the timestamps in the resume data. This defaults to false, which
|
with the timestamps in the resume data. This defaults to false, which
|
||||||
@ -4673,6 +4731,58 @@ opened. The number of connections is set to a hard minimum of at least two per
|
|||||||
torrent, so if you set a too low connections limit, and open too many torrents,
|
torrent, so if you set a too low connections limit, and open too many torrents,
|
||||||
the limit will not be met.
|
the limit will not be met.
|
||||||
|
|
||||||
|
``utp_target_delay`` is the target delay for uTP sockets in milliseconds. A high
|
||||||
|
value will make uTP connections more aggressive and cause longer queues in the upload
|
||||||
|
bottleneck. It cannot be too low, since the noise in the measurements would cause
|
||||||
|
it to send too slow. The default is 50 milliseconds.
|
||||||
|
|
||||||
|
``utp_gain_factor`` is the number of bytes the uTP congestion window can increase
|
||||||
|
at the most in one RTT. This defaults to 300 bytes. If this is set too high,
|
||||||
|
the congestion controller reacts too hard to noise and will not be stable, if it's
|
||||||
|
set too low, it will react slow to congestion and not back off as fast.
|
||||||
|
|
||||||
|
``utp_min_timeout`` is the shortest allowed uTP socket timeout, specified in milliseconds.
|
||||||
|
This defaults to 500 milliseconds. The timeout depends on the RTT of the connection, but
|
||||||
|
is never smaller than this value. A connection times out when every packet in a window
|
||||||
|
is lost, or when a packet is lost twice in a row (i.e. the resent packet is lost as well).
|
||||||
|
|
||||||
|
The shorter the timeout is, the faster the connection will recover from this situation,
|
||||||
|
assuming the RTT is low enough.
|
||||||
|
|
||||||
|
``utp_syn_resends`` is the number of SYN packets that are sent (and timed out) before
|
||||||
|
giving up and closing the socket.
|
||||||
|
|
||||||
|
``utp_num_resends`` is the number of times a packet is sent (and lossed or timed out)
|
||||||
|
before giving up and closing the connection.
|
||||||
|
|
||||||
|
``utp_connect_timeout`` is the number of milliseconds of timeout for the initial SYN
|
||||||
|
packet for uTP connections. For each timed out packet (in a row), the timeout is doubled.
|
||||||
|
|
||||||
|
``utp_delayed_ack`` is the number of milliseconds to delay ACKs the most. Delaying ACKs
|
||||||
|
significantly helps reducing the amount of protocol overhead in the reverse direction
|
||||||
|
from downloads. It defaults to 100 milliseconds. If set to 0, delayed ACKs are disabled
|
||||||
|
and every incoming payload packet is ACKed. The granularity of this timer is capped by
|
||||||
|
the tick interval (as specified by ``tick_interval``).
|
||||||
|
|
||||||
|
``utp_dynamic_sock_buf`` controls if the uTP socket manager is allowed to increase
|
||||||
|
the socket buffer if a network interface with a large MTU is used (such as loopback
|
||||||
|
or ethernet jumbo frames). This defaults to true and might improve uTP throughput.
|
||||||
|
For RAM constrained systems, disabling this typically saves around 30kB in user space
|
||||||
|
and probably around 400kB in kernel socket buffers (it adjusts the send and receive
|
||||||
|
buffer size on the kernel socket, both for IPv4 and IPv6).
|
||||||
|
|
||||||
|
The ``mixed_mode_algorithm`` determines how to treat TCP connections when there are
|
||||||
|
uTP connections. Since uTP is designed to yield to TCP, there's an inherent problem
|
||||||
|
when using swarms that have both TCP and uTP connections. If nothing is done, uTP
|
||||||
|
connections would often be starved out for bandwidth by the TCP connections. This mode
|
||||||
|
is ``prefer_tcp``. The ``peer_proportional`` mode simply looks at the current throughput
|
||||||
|
and rate limits all TCP connections to their proportional share based on how many of
|
||||||
|
the connections are TCP. This works best if uTP connections are not rate limited by
|
||||||
|
the global rate limiter (which they aren't by default).
|
||||||
|
|
||||||
|
``rate_limit_utp`` determines if uTP connections should be throttled by the global rate
|
||||||
|
limiter or not. By default they are not, since uTP manages its own rate.
|
||||||
|
|
||||||
``listen_queue_size`` is the value passed in to listen() for the listen socket.
|
``listen_queue_size`` is the value passed in to listen() for the listen socket.
|
||||||
It is the number of outstanding incoming connections to queue up while we're not
|
It is the number of outstanding incoming connections to queue up while we're not
|
||||||
actively waiting for a connection to be accepted. The default is 5 which should
|
actively waiting for a connection to be accepted. The default is 5 which should
|
||||||
@ -6797,6 +6907,9 @@ code symbol description
|
|||||||
106 invalid_pex_message The peer sent an invalid peer exchange message
|
106 invalid_pex_message The peer sent an invalid peer exchange message
|
||||||
------ ----------------------------------------- -----------------------------------------------------------------
|
------ ----------------------------------------- -----------------------------------------------------------------
|
||||||
107 invalid_lt_tracker_message The peer sent an invalid tracker exchange message
|
107 invalid_lt_tracker_message The peer sent an invalid tracker exchange message
|
||||||
|
------ ----------------------------------------- -----------------------------------------------------------------
|
||||||
|
108 too_frequent_pex The peer sent an pex messages too often. This is a possible
|
||||||
|
attempt of and attack
|
||||||
====== ========================================= =================================================================
|
====== ========================================= =================================================================
|
||||||
|
|
||||||
NAT-PMP errors:
|
NAT-PMP errors:
|
||||||
|
BIN
docs/our_delay_base.png
Normal file
BIN
docs/our_delay_base.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
docs/our_delay_base_thumb.png
Normal file
BIN
docs/our_delay_base_thumb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
@ -203,6 +203,16 @@ of C++ exceptions. By disabling exceptions (-fno-exceptions on GCC), you can
|
|||||||
reduce the executable size with up to 45%. In order to build without exception
|
reduce the executable size with up to 45%. In order to build without exception
|
||||||
support, you need to patch parts of boost.</p>
|
support, you need to patch parts of boost.</p>
|
||||||
<p>Also make sure to optimize for size when compiling.</p>
|
<p>Also make sure to optimize for size when compiling.</p>
|
||||||
|
<p>Another way of reducing the executable size is to disable code that isn't used.
|
||||||
|
There are a number of <tt class="docutils literal"><span class="pre">TORRENT_*</span></tt> macros that control which features are included
|
||||||
|
in libtorrent. If these macros are used to strip down libtorrent, make sure the same
|
||||||
|
macros are defined when building libtorrent as when linking against it. If these
|
||||||
|
are different the structures will look different from the libtorrent side and from
|
||||||
|
the client side and memory corruption will follow.</p>
|
||||||
|
<p>One, probably, safe macro to define is <tt class="docutils literal"><span class="pre">TORRENT_NO_DEPRECATE</span></tt> which removes all
|
||||||
|
deprecated functions and struct members. As long as no deprecated functions are
|
||||||
|
relied upon, this should be a simple way to eliminate a little bit of code.</p>
|
||||||
|
<p>For all available options, see the <a class="reference external" href="building.html">building libtorrent</a> secion.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="reduce-statistics">
|
<div class="section" id="reduce-statistics">
|
||||||
<h2>reduce statistics</h2>
|
<h2>reduce statistics</h2>
|
||||||
|
342
docs/utp.html
Normal file
342
docs/utp.html
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!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">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" />
|
||||||
|
<title>libtorrent manual</title>
|
||||||
|
<meta name="author" content="Arvid Norberg, arvid@rasterbar.com" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../css/base.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../css/rst.css" />
|
||||||
|
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||||
|
<style type="text/css">
|
||||||
|
/* Hides from IE-mac \*/
|
||||||
|
* html pre { height: 1%; }
|
||||||
|
/* End hide from IE-mac */
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="document" id="libtorrent-manual">
|
||||||
|
<div id="container">
|
||||||
|
<div id="headerNav">
|
||||||
|
<ul>
|
||||||
|
<li class="first"><a href="/">Home</a></li>
|
||||||
|
<li><a href="../../products.html">Products</a></li>
|
||||||
|
<li><a href="../../contact.html">Contact</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div id="header">
|
||||||
|
<h1><span>Rasterbar Software</span></h1>
|
||||||
|
<h2><span>Software developement and consulting</span></h2>
|
||||||
|
</div>
|
||||||
|
<div id="main">
|
||||||
|
<h1 class="title">libtorrent manual</h1>
|
||||||
|
<table class="docinfo" frame="void" rules="none">
|
||||||
|
<col class="docinfo-name" />
|
||||||
|
<col class="docinfo-content" />
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr><th class="docinfo-name">Author:</th>
|
||||||
|
<td>Arvid Norberg, <a class="last reference external" href="mailto:arvid@rasterbar.com">arvid@rasterbar.com</a></td></tr>
|
||||||
|
<tr><th class="docinfo-name">Version:</th>
|
||||||
|
<td>0.16.0</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="contents topic" id="table-of-contents">
|
||||||
|
<p class="topic-title first">Table of contents</p>
|
||||||
|
<ul class="simple">
|
||||||
|
<li><a class="reference internal" href="#utp" id="id1">uTP</a><ul>
|
||||||
|
<li><a class="reference internal" href="#rationale" id="id2">rationale</a></li>
|
||||||
|
<li><a class="reference internal" href="#tcp" id="id3">TCP</a></li>
|
||||||
|
<li><a class="reference internal" href="#ledbat-congestion-controller" id="id4">LEDBAT congestion controller</a></li>
|
||||||
|
<li><a class="reference internal" href="#one-way-delays" id="id5">one way delays</a></li>
|
||||||
|
<li><a class="reference internal" href="#path-mtu-discovery" id="id6">Path MTU discovery</a></li>
|
||||||
|
<li><a class="reference internal" href="#clock-drift" id="id7">clock drift</a></li>
|
||||||
|
<li><a class="reference internal" href="#features" id="id8">features</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="utp">
|
||||||
|
<h1>uTP</h1>
|
||||||
|
<p>uTP (uTorrent transport protocol) is a transport protocol which uses one-way
|
||||||
|
delay measurements for its congestion controller. This article is about uTP
|
||||||
|
in general and specifically about libtorrent's implementation of it.</p>
|
||||||
|
<div class="section" id="rationale">
|
||||||
|
<h2>rationale</h2>
|
||||||
|
<p>One of the most common problems users are experiencing using bittorrent is
|
||||||
|
that their internet "stops working". This can be caused by a number of things,
|
||||||
|
for example:</p>
|
||||||
|
<ol class="arabic simple">
|
||||||
|
<li>a home router that crashes or slows down when its NAT pin-hole
|
||||||
|
table overflows, triggered by DHT or simply many TCP connections.</li>
|
||||||
|
<li>a home router that crashes or slows down by UDP traffic (caused by
|
||||||
|
the DHT)</li>
|
||||||
|
<li>a home DSL or cable modem having its send buffer filled up by outgoing
|
||||||
|
data, and the buffer fits seconds worth of bytes. This adds seconds
|
||||||
|
of delay on interactive traffic. For a web site that needs 10 round
|
||||||
|
trips to load this may mean 10s of seconds of delay to load compared
|
||||||
|
to without bittorrent. Skype or other delay sensitive applications
|
||||||
|
would be affected even more.</li>
|
||||||
|
</ol>
|
||||||
|
<p>This document will cover (3).</p>
|
||||||
|
<p>Typically this is solved by asking the user to enter a number of bytes
|
||||||
|
that the client is allowed to send per second (i.e. setting an upload
|
||||||
|
rate limit). The common recommendation is to set this limit to 80% of the
|
||||||
|
uplink's capacity. This is to leave some headroom for things like TCP
|
||||||
|
ACKs as well as the user's interactive use of the connection such as
|
||||||
|
browsing the web or checking email.</p>
|
||||||
|
<p>There are two major drawbacks with this technique:</p>
|
||||||
|
<ol class="arabic simple">
|
||||||
|
<li>The user needs to actively make this setting (very few protocols
|
||||||
|
require the user to provide this sort of information). This also
|
||||||
|
means the user needs to figure out what its up-link capacity is.
|
||||||
|
This is unfortunately a number that many ISPs are not advertizing
|
||||||
|
(because it's often much lower than the download capacity) which
|
||||||
|
might make it hard to find.</li>
|
||||||
|
<li>The 20% headroom is wasted most of the time. Whenever the user
|
||||||
|
is not using the internet connection for anything, those extra 20%
|
||||||
|
could have been used by bittorrent to upload, but they're already
|
||||||
|
allocated for interactive traffic. On top of that, 20% of the up-link
|
||||||
|
is often not enough to give a good and responsive browsing experience.</li>
|
||||||
|
</ol>
|
||||||
|
<p>The ideal bandwidth allocation would be to use 100% for bittorrent when
|
||||||
|
there is no interactive cross traffic, and 100% for interactive traffic
|
||||||
|
whenever there is any. This would not waste any bandwidth while the user
|
||||||
|
is idling, and it would make for a much better experience when the user
|
||||||
|
is using the internet connection for other things.</p>
|
||||||
|
<p>This is what uTP does.</p>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="tcp">
|
||||||
|
<h2>TCP</h2>
|
||||||
|
<p>The reason TCP will fill the send buffer, and cause the delay on all traffic,
|
||||||
|
is because its congestion control is <em>only</em> based on packet loss (and timeout).</p>
|
||||||
|
<p>Since the modem is buffering, packets won't get dropped until the entire queue
|
||||||
|
is full, and no more packets will fit. The packets will be dropped, TCP will
|
||||||
|
detect this within an RTT or so. When TCP notices a packet loss, it will slow
|
||||||
|
down its send rate and the queue will start to drain again. However, TCP will
|
||||||
|
immediately start to ramp up its send rate again until the buffer is full and
|
||||||
|
it detects packet loss again.</p>
|
||||||
|
<p>TCP is designed to fully utilize the link capacity, without causing congestion.
|
||||||
|
Whenever it sense congestion (through packet loss) it backs off. TCP is not
|
||||||
|
designed to keep delays low. When you get the first packet loss (assuming the
|
||||||
|
kind of queue described above, tail-queue) it is already too late. Your queue
|
||||||
|
is full and you have the maximum amount of delay your modem can provide.</p>
|
||||||
|
<p>TCP controls its send rate by limiting the number of bytes in-flight at any
|
||||||
|
given time. This limit is called congestion window (<em>cwnd</em> for short). During
|
||||||
|
steady state, the congestion window is constantly increasing linearly. Each
|
||||||
|
packet that is successfully transferred will increase cwnd.</p>
|
||||||
|
<pre class="literal-block">
|
||||||
|
cwnd
|
||||||
|
send_rate = ----
|
||||||
|
RTT
|
||||||
|
</pre>
|
||||||
|
<p>Send rate is proportional to cwnd divided by RTT. A smaller cwnd will cause
|
||||||
|
the send rate to be lower and a larger cwnd will cause the send rate to be
|
||||||
|
higher.</p>
|
||||||
|
<p>Using a congestion window instead of controlling the rate directly is simple
|
||||||
|
because it also introduces an upper bound for memory usage for packets that
|
||||||
|
haven't been ACKed yet and needs to be kept around.</p>
|
||||||
|
<p>The behavior of TCP, where it bumps up against the ceiling, backs off and then
|
||||||
|
starts increasing again until it hits the ceiling again, forms a saw tooth shape.
|
||||||
|
If the modem wouldn't have any send buffer at all, a single TCP stream would
|
||||||
|
not be able to fully utilize the link because of this behavior, since it would
|
||||||
|
only fully utilize the link right before the packet loss and the back-off.</p>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="ledbat-congestion-controller">
|
||||||
|
<h2>LEDBAT congestion controller</h2>
|
||||||
|
<p>The congestion controller in uTP is called <a class="reference external" href="https://datatracker.ietf.org/doc/draft-ietf-ledbat-congestion/">LEDBAT</a>, which also is an IETF working
|
||||||
|
group attempting to standardize it. The congestion controller, on top of reacting
|
||||||
|
to packet loss the same way TCP does, also reacts to changes in delays.</p>
|
||||||
|
<p>For any uTP (or <a class="reference external" href="https://datatracker.ietf.org/doc/draft-ietf-ledbat-congestion/">LEDBAT</a>) implementation, there is a target delay. This is the
|
||||||
|
amount of delay that is acceptable, and is in fact targeted for the connection.
|
||||||
|
The target delay is defined to 25 ms in <a class="reference external" href="https://datatracker.ietf.org/doc/draft-ietf-ledbat-congestion/">LEDBAT</a>, uTorrent uses 100 ms and
|
||||||
|
libtorrent uses 75 ms. Whenever a delay measurement is lower than the target,
|
||||||
|
cwnd is increased proportional to (target_delay - delay). Whenever the measurement
|
||||||
|
is higher than the target, cwnd is decreased proportional to (delay - target_delay).</p>
|
||||||
|
<p>It can simply be expressed as:</p>
|
||||||
|
<pre class="literal-block">
|
||||||
|
cwnd += gain * (target_delay - delay)
|
||||||
|
</pre>
|
||||||
|
<a class="reference external image-reference" href="cwnd.png"><img align="right" alt="cwnd_thumb.png" class="align-right" src="cwnd_thumb.png" /></a>
|
||||||
|
<p>Similarly to TCP, this is scaled so that the increase is evened out over one RTT.</p>
|
||||||
|
<p>The linear controller will adjust the cwnd more for delays that are far off the
|
||||||
|
target, and less for delays that are close to the target. This makes it converge
|
||||||
|
at the target delay. Although, due to noise there is almost always some amount of
|
||||||
|
oscillation. This oscillation is typically smaller than the saw tooth TCP forms.</p>
|
||||||
|
<p>The figure to the right shows how (TCP) cross traffic causese uTP to essentially
|
||||||
|
entirely stop sending anything. Its delay measurements are mostly well above the target
|
||||||
|
during this time. The cross traffic is only a single TCP stream in this test.</p>
|
||||||
|
<p>As soon as the cross traffic ceases, uTP will pick up its original send rate within
|
||||||
|
a second.</p>
|
||||||
|
<p>Since uTP constantly measures the delay, with every single packet, the reaction time
|
||||||
|
to cross traffic causing delays is a single RTT (typically a fraction of a second).</p>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="one-way-delays">
|
||||||
|
<h2>one way delays</h2>
|
||||||
|
<p>uTP measures the delay imposed on packets being sent to the other end
|
||||||
|
of the connection. This measurement only includes buffering delay along
|
||||||
|
the link, not propagation delay (the speed of light times distance) nor
|
||||||
|
the routing delay (the time routers spend figuring out where to forward
|
||||||
|
the packet). It does this by always comparing all measurements to a
|
||||||
|
baseline measurement, to cancel out any fixed delay. By focusing on the
|
||||||
|
variable delay along a link, it will specifically detect points where
|
||||||
|
there might be congestion, since those points will have buffers.</p>
|
||||||
|
<a class="reference external image-reference" href="delays.png"><img align="right" alt="delays_thumb.png" class="align-right" src="delays_thumb.png" /></a>
|
||||||
|
<p>Delay on the return link is explicitly not included in the delay measurement.
|
||||||
|
This is because in a peer-to-peer application, the other end is likely to also
|
||||||
|
be connected via a modem, with the same send buffer restrictions as we assume
|
||||||
|
for the sending side. The other end having its send queue full is not an indication
|
||||||
|
of congestion on the path going the other way.</p>
|
||||||
|
<p>In order to measure one way delays for packets, we cannot rely on clocks being
|
||||||
|
synchronized, especially not at the microsecond level. Instead, the actual time
|
||||||
|
it takes for a packet to arrive at the destination is not measured, only the changes
|
||||||
|
in the transit time is measured.</p>
|
||||||
|
<p>Each packet that is sent includes a time stamp of the current time, in microseconds,
|
||||||
|
of the sending machine. The receiving machine calculates the difference between its
|
||||||
|
own timestamp and the one in the packet and sends this back in the ACK. This difference,
|
||||||
|
since it is in microseconds, will essentially be a random 32 bit number. However,
|
||||||
|
the difference will stay somewhat similar over time. Any changes in this difference
|
||||||
|
indicates that packets are either going through faster or slower.</p>
|
||||||
|
<p>In order to measure the one-way buffering delay, a base delay is established. The
|
||||||
|
base delay is the lowest ever seen value of the time stamp difference. Each delay
|
||||||
|
sample we receive back, is compared against the base delay and the delay is the
|
||||||
|
difference.</p>
|
||||||
|
<p>This is the delay that's fed into the congestion controller.</p>
|
||||||
|
<p>A histogram of typical delay measurements is shown to the right. This is from
|
||||||
|
a transfer between a cable modem connection and a DSL connection.</p>
|
||||||
|
<p>The details of the delay measurements are slightly more complicated since the
|
||||||
|
values needs to be able to wrap (cross the 2^32 boundry and start over at 0).</p>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="path-mtu-discovery">
|
||||||
|
<h2>Path MTU discovery</h2>
|
||||||
|
<p>MTU is short for <em>Maximum Transfer Unit</em> and describes the largest packet size that
|
||||||
|
can be sent over a link. Any datagrams which size exceeds this limit will either
|
||||||
|
be <em>fragmented</em> or dropped. A fragmented datagram means that the payload is split up
|
||||||
|
in multiple packets, each with its own individual packet header.</p>
|
||||||
|
<p>There are several reasons to avoid sending datagrams that get fragmented:</p>
|
||||||
|
<ol class="arabic simple">
|
||||||
|
<li>A fragmented datagram is more likely to be lost. If any fragment is lost,
|
||||||
|
the whole datagram is dropped.</li>
|
||||||
|
<li>Bandwidth is likely to be wasted. If the datagram size is not divisible
|
||||||
|
by the MTU the last packet will not contain as much payload as it could, and the
|
||||||
|
payload over protocol header ratio decreases.</li>
|
||||||
|
<li>It's expensive to fragment datagrams. Few routers are optimized to handle large
|
||||||
|
numbers of fragmented packets. Datagrams that have to fragment are likely to
|
||||||
|
be delayed significantly, and contribute to more CPU being used on routers.
|
||||||
|
Typically fragmentation (and other advanced IP features) are implemented in
|
||||||
|
software (slow) and not hardware (fast).</li>
|
||||||
|
</ol>
|
||||||
|
<p>The path MTU is the lowest MTU of any link along a path from two endpoints on the
|
||||||
|
internet. The MTU bottleneck isn't necessarily at one of the endpoints, but can
|
||||||
|
be anywhere in between.</p>
|
||||||
|
<p>The most common MTU is 1500 bytes, which is the largest packet size for ethernet
|
||||||
|
networks. Many home DSL connections, however, tunnel IP through PPPoE (Point to
|
||||||
|
Point Protocol over Ethernet. Yes, that is the old dial-up modem protocol). This
|
||||||
|
protocol uses up 8 bytes per packet for its own header.</p>
|
||||||
|
<p>If the user happens to be on an internet connection over a VPN, it will add another
|
||||||
|
layer, with its own packet headers.</p>
|
||||||
|
<p>In short; if you would pick the largest possible packet size on an ethernet network,
|
||||||
|
1472, and stick with it, you would be quite likely to generate fragments for a lot
|
||||||
|
of connections. The fragments that will be created will be very small and especially
|
||||||
|
inflate the overhead waste.</p>
|
||||||
|
<p>The other approach of picking a very conservative packet size, that would be very
|
||||||
|
unlikely to get fragmented has the following drawbacks:</p>
|
||||||
|
<ol class="arabic simple">
|
||||||
|
<li>People on good, normal, networks will be penalized with a small packet size.
|
||||||
|
Both in terms of router load but also bandwidth waste.</li>
|
||||||
|
<li>Software routers are typically not limited by the number of bytes they can route,
|
||||||
|
but the number of packets. Small packets means more of them, and more load on
|
||||||
|
software routers.</li>
|
||||||
|
</ol>
|
||||||
|
<p>The solution to the problem of finding the optimal packet size, is to dynamically
|
||||||
|
adjust the packet size and search for the largest size that can make it through
|
||||||
|
without being fragmented along the path.</p>
|
||||||
|
<p>To help do this, you can set the DF bit (Don't Fragment) in your Datagrams. This
|
||||||
|
asks routers that otherwise would fragment packets to instead drop them, and send
|
||||||
|
back an ICMP message reporting the MTU of the link the packet couldn't fit. With
|
||||||
|
this message, it's very simple to discover the path MTU. You simply mark your packets
|
||||||
|
not to be fragmented, and change your packet size whenever you receive the ICMP
|
||||||
|
packet-too-big message.</p>
|
||||||
|
<p>Unfortunately it's not quite that simple. There are a significant number of firewalls
|
||||||
|
in the wild blocking all ICMP messages. This means we can't rely on them, we also have
|
||||||
|
to guess that a packet was dropped because of its size. This is done by only marking
|
||||||
|
certain packets with DF, and if all other packets go through, except for the MTU probes,
|
||||||
|
we know that we need to lower our packet sizes.</p>
|
||||||
|
<p>If we set up bounds for the path MTU (say the minimum internet MTU, 576 and ethernet's 1500),
|
||||||
|
we can do a binary search for the MTU. This would let us find it in just a few round-trips.</p>
|
||||||
|
<p>On top of this, libtorrent has an optimization where it figures out which interface a
|
||||||
|
uTP connection will be sent over, and initialize the MTU ceiling to that interface's MTU.
|
||||||
|
This means that a VPN tunnel would advertize its MTU as lower, and the uTP connection would
|
||||||
|
immediately know to send smaller packets, no search required. It also has the side-effect
|
||||||
|
of being able to use much larger packet sizes for non-ethernet interfaces or ethernet links
|
||||||
|
with jumbo frames.</p>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="clock-drift">
|
||||||
|
<h2>clock drift</h2>
|
||||||
|
<a class="reference external image-reference" href="our_delay_base.png"><img align="right" alt="our_delay_base_thumb.png" class="align-right" src="our_delay_base_thumb.png" /></a>
|
||||||
|
<p>Clock drift is clocks progressing at different rates. It's different from clock
|
||||||
|
skew which means clocks set to different values (but which may progress at the same
|
||||||
|
rate).</p>
|
||||||
|
<p>Any clock drift between the two machines involved in a uTP transfer will result
|
||||||
|
in systematically inflated or deflated delay measurements.</p>
|
||||||
|
<p>This can be solved by letting the base delay be the lowest seen sample in the last
|
||||||
|
<em>n</em> minutes. This is a trade-off between seeing a single packet go straight through
|
||||||
|
the queue, with no delay, and the amount of clock drift one can assume on normal computers.</p>
|
||||||
|
<p>It turns out that it's fairly safe to assume that one of your packets will in fact go
|
||||||
|
straight through without any significant delay, once every 20 minutes or so. However,
|
||||||
|
the clock drift between normal computers can be as much as 17 ms in 10 minutes. 17 ms
|
||||||
|
is quite significant, especially if your target delay is 25 ms (as in the <a class="reference external" href="https://datatracker.ietf.org/doc/draft-ietf-ledbat-congestion/">LEDBAT</a> spec).</p>
|
||||||
|
<p>Clocks progresses at different rates depending on temperature. This means computers
|
||||||
|
running hot are likely to have a clock drift compared to computers running cool.</p>
|
||||||
|
<p>So, by updating the delay base periodically based on the lowest seen sample, you'll either
|
||||||
|
end up changing it upwards (artificaially making the delay samples appear small) without
|
||||||
|
the congestion or delay actually having changed, or you'll end up with a significant clock
|
||||||
|
drift and have artificially low samples because of that.</p>
|
||||||
|
<p>The solution to this problem is based on the fact that the clock drift is only a problem
|
||||||
|
for one of the sides of the connection. Only when your delay measurements keep increasing
|
||||||
|
is it a problem. If your delay measurements keep decreasing, the samples will simply push
|
||||||
|
down the delay base along with it. With this in mind, we can simply keep track of the
|
||||||
|
other end's delay measurements as well, applying the same logic to it. Whenever the
|
||||||
|
other end's base delay is adjusted downwards, we adjust our base delay upwards by the same
|
||||||
|
amount.</p>
|
||||||
|
<p>This will accurately keep the base delay updated with the clock drift and improve
|
||||||
|
the delay measurements. The figure on the right shows the absolute timestamp differences
|
||||||
|
along with the base delay. The slope of the measurements is caused by clock drift.</p>
|
||||||
|
<p>For more information on the clock drift compensation, see the slides from BitTorrent's
|
||||||
|
presentation at <a class="reference external" href="http://www.usenix.org/event/iptps10/tech/slides/cohen.pdf">IPTPS10</a>.</p>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="features">
|
||||||
|
<h2>features</h2>
|
||||||
|
<p>libtorrent's uTP implementation includes the following features:</p>
|
||||||
|
<ul class="simple">
|
||||||
|
<li>Path MTU discovery, including jumbo frames and detecting restricted
|
||||||
|
MTU tunnels. Binary search packet sizes to find the largest non-fragmented.</li>
|
||||||
|
<li>Selective ACK. The ability to acknowledge individual packets in the
|
||||||
|
event of packet loss</li>
|
||||||
|
<li>Fast resend. The first time a packet is lost, it's resent immediately.
|
||||||
|
Triggered by duplicate ACKs.</li>
|
||||||
|
<li>Nagle's algorithm. Minimize protocol overhead by attempting to lump
|
||||||
|
full packets of payload together before sending a packet.</li>
|
||||||
|
<li>Delayed ACKs to minimize protocol overhead.</li>
|
||||||
|
<li>Microsecond resolution timestamps.</li>
|
||||||
|
<li>Advertised receive window, to support download rate limiting.</li>
|
||||||
|
<li>Correct handling of wrapping sequence numbers.</li>
|
||||||
|
<li>Easy configuration of target-delay, gain-factor, timeouts, delayed-ack
|
||||||
|
and socket buffers.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="footer">
|
||||||
|
<span>Copyright © 2005 Rasterbar Software.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
_uacct = "UA-1599045-1";
|
||||||
|
urchinTracker();
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
347
docs/utp.rst
Normal file
347
docs/utp.rst
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
=================
|
||||||
|
libtorrent manual
|
||||||
|
=================
|
||||||
|
|
||||||
|
:Author: Arvid Norberg, arvid@rasterbar.com
|
||||||
|
:Version: 0.16.0
|
||||||
|
|
||||||
|
.. contents:: Table of contents
|
||||||
|
:depth: 2
|
||||||
|
:backlinks: none
|
||||||
|
|
||||||
|
uTP
|
||||||
|
===
|
||||||
|
|
||||||
|
uTP (uTorrent transport protocol) is a transport protocol which uses one-way
|
||||||
|
delay measurements for its congestion controller. This article is about uTP
|
||||||
|
in general and specifically about libtorrent's implementation of it.
|
||||||
|
|
||||||
|
rationale
|
||||||
|
---------
|
||||||
|
|
||||||
|
One of the most common problems users are experiencing using bittorrent is
|
||||||
|
that their internet "stops working". This can be caused by a number of things,
|
||||||
|
for example:
|
||||||
|
|
||||||
|
1. a home router that crashes or slows down when its NAT pin-hole
|
||||||
|
table overflows, triggered by DHT or simply many TCP connections.
|
||||||
|
|
||||||
|
2. a home router that crashes or slows down by UDP traffic (caused by
|
||||||
|
the DHT)
|
||||||
|
|
||||||
|
3. a home DSL or cable modem having its send buffer filled up by outgoing
|
||||||
|
data, and the buffer fits seconds worth of bytes. This adds seconds
|
||||||
|
of delay on interactive traffic. For a web site that needs 10 round
|
||||||
|
trips to load this may mean 10s of seconds of delay to load compared
|
||||||
|
to without bittorrent. Skype or other delay sensitive applications
|
||||||
|
would be affected even more.
|
||||||
|
|
||||||
|
This document will cover (3).
|
||||||
|
|
||||||
|
Typically this is solved by asking the user to enter a number of bytes
|
||||||
|
that the client is allowed to send per second (i.e. setting an upload
|
||||||
|
rate limit). The common recommendation is to set this limit to 80% of the
|
||||||
|
uplink's capacity. This is to leave some headroom for things like TCP
|
||||||
|
ACKs as well as the user's interactive use of the connection such as
|
||||||
|
browsing the web or checking email.
|
||||||
|
|
||||||
|
There are two major drawbacks with this technique:
|
||||||
|
|
||||||
|
1. The user needs to actively make this setting (very few protocols
|
||||||
|
require the user to provide this sort of information). This also
|
||||||
|
means the user needs to figure out what its up-link capacity is.
|
||||||
|
This is unfortunately a number that many ISPs are not advertizing
|
||||||
|
(because it's often much lower than the download capacity) which
|
||||||
|
might make it hard to find.
|
||||||
|
|
||||||
|
2. The 20% headroom is wasted most of the time. Whenever the user
|
||||||
|
is not using the internet connection for anything, those extra 20%
|
||||||
|
could have been used by bittorrent to upload, but they're already
|
||||||
|
allocated for interactive traffic. On top of that, 20% of the up-link
|
||||||
|
is often not enough to give a good and responsive browsing experience.
|
||||||
|
|
||||||
|
The ideal bandwidth allocation would be to use 100% for bittorrent when
|
||||||
|
there is no interactive cross traffic, and 100% for interactive traffic
|
||||||
|
whenever there is any. This would not waste any bandwidth while the user
|
||||||
|
is idling, and it would make for a much better experience when the user
|
||||||
|
is using the internet connection for other things.
|
||||||
|
|
||||||
|
This is what uTP does.
|
||||||
|
|
||||||
|
TCP
|
||||||
|
---
|
||||||
|
|
||||||
|
The reason TCP will fill the send buffer, and cause the delay on all traffic,
|
||||||
|
is because its congestion control is *only* based on packet loss (and timeout).
|
||||||
|
|
||||||
|
Since the modem is buffering, packets won't get dropped until the entire queue
|
||||||
|
is full, and no more packets will fit. The packets will be dropped, TCP will
|
||||||
|
detect this within an RTT or so. When TCP notices a packet loss, it will slow
|
||||||
|
down its send rate and the queue will start to drain again. However, TCP will
|
||||||
|
immediately start to ramp up its send rate again until the buffer is full and
|
||||||
|
it detects packet loss again.
|
||||||
|
|
||||||
|
TCP is designed to fully utilize the link capacity, without causing congestion.
|
||||||
|
Whenever it sense congestion (through packet loss) it backs off. TCP is not
|
||||||
|
designed to keep delays low. When you get the first packet loss (assuming the
|
||||||
|
kind of queue described above, tail-queue) it is already too late. Your queue
|
||||||
|
is full and you have the maximum amount of delay your modem can provide.
|
||||||
|
|
||||||
|
TCP controls its send rate by limiting the number of bytes in-flight at any
|
||||||
|
given time. This limit is called congestion window (*cwnd* for short). During
|
||||||
|
steady state, the congestion window is constantly increasing linearly. Each
|
||||||
|
packet that is successfully transferred will increase cwnd.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
cwnd
|
||||||
|
send_rate = ----
|
||||||
|
RTT
|
||||||
|
|
||||||
|
|
||||||
|
Send rate is proportional to cwnd divided by RTT. A smaller cwnd will cause
|
||||||
|
the send rate to be lower and a larger cwnd will cause the send rate to be
|
||||||
|
higher.
|
||||||
|
|
||||||
|
Using a congestion window instead of controlling the rate directly is simple
|
||||||
|
because it also introduces an upper bound for memory usage for packets that
|
||||||
|
haven't been ACKed yet and needs to be kept around.
|
||||||
|
|
||||||
|
The behavior of TCP, where it bumps up against the ceiling, backs off and then
|
||||||
|
starts increasing again until it hits the ceiling again, forms a saw tooth shape.
|
||||||
|
If the modem wouldn't have any send buffer at all, a single TCP stream would
|
||||||
|
not be able to fully utilize the link because of this behavior, since it would
|
||||||
|
only fully utilize the link right before the packet loss and the back-off.
|
||||||
|
|
||||||
|
LEDBAT congestion controller
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
The congestion controller in uTP is called LEDBAT_, which also is an IETF working
|
||||||
|
group attempting to standardize it. The congestion controller, on top of reacting
|
||||||
|
to packet loss the same way TCP does, also reacts to changes in delays.
|
||||||
|
|
||||||
|
For any uTP (or LEDBAT_) implementation, there is a target delay. This is the
|
||||||
|
amount of delay that is acceptable, and is in fact targeted for the connection.
|
||||||
|
The target delay is defined to 25 ms in LEDBAT_, uTorrent uses 100 ms and
|
||||||
|
libtorrent uses 75 ms. Whenever a delay measurement is lower than the target,
|
||||||
|
cwnd is increased proportional to (target_delay - delay). Whenever the measurement
|
||||||
|
is higher than the target, cwnd is decreased proportional to (delay - target_delay).
|
||||||
|
|
||||||
|
It can simply be expressed as::
|
||||||
|
|
||||||
|
cwnd += gain * (target_delay - delay)
|
||||||
|
|
||||||
|
.. image:: cwnd_thumb.png
|
||||||
|
:target: cwnd.png
|
||||||
|
:align: right
|
||||||
|
|
||||||
|
Similarly to TCP, this is scaled so that the increase is evened out over one RTT.
|
||||||
|
|
||||||
|
The linear controller will adjust the cwnd more for delays that are far off the
|
||||||
|
target, and less for delays that are close to the target. This makes it converge
|
||||||
|
at the target delay. Although, due to noise there is almost always some amount of
|
||||||
|
oscillation. This oscillation is typically smaller than the saw tooth TCP forms.
|
||||||
|
|
||||||
|
The figure to the right shows how (TCP) cross traffic causese uTP to essentially
|
||||||
|
entirely stop sending anything. Its delay measurements are mostly well above the target
|
||||||
|
during this time. The cross traffic is only a single TCP stream in this test.
|
||||||
|
|
||||||
|
As soon as the cross traffic ceases, uTP will pick up its original send rate within
|
||||||
|
a second.
|
||||||
|
|
||||||
|
Since uTP constantly measures the delay, with every single packet, the reaction time
|
||||||
|
to cross traffic causing delays is a single RTT (typically a fraction of a second).
|
||||||
|
|
||||||
|
one way delays
|
||||||
|
--------------
|
||||||
|
|
||||||
|
uTP measures the delay imposed on packets being sent to the other end
|
||||||
|
of the connection. This measurement only includes buffering delay along
|
||||||
|
the link, not propagation delay (the speed of light times distance) nor
|
||||||
|
the routing delay (the time routers spend figuring out where to forward
|
||||||
|
the packet). It does this by always comparing all measurements to a
|
||||||
|
baseline measurement, to cancel out any fixed delay. By focusing on the
|
||||||
|
variable delay along a link, it will specifically detect points where
|
||||||
|
there might be congestion, since those points will have buffers.
|
||||||
|
|
||||||
|
.. image:: delays_thumb.png
|
||||||
|
:target: delays.png
|
||||||
|
:align: right
|
||||||
|
|
||||||
|
Delay on the return link is explicitly not included in the delay measurement.
|
||||||
|
This is because in a peer-to-peer application, the other end is likely to also
|
||||||
|
be connected via a modem, with the same send buffer restrictions as we assume
|
||||||
|
for the sending side. The other end having its send queue full is not an indication
|
||||||
|
of congestion on the path going the other way.
|
||||||
|
|
||||||
|
In order to measure one way delays for packets, we cannot rely on clocks being
|
||||||
|
synchronized, especially not at the microsecond level. Instead, the actual time
|
||||||
|
it takes for a packet to arrive at the destination is not measured, only the changes
|
||||||
|
in the transit time is measured.
|
||||||
|
|
||||||
|
Each packet that is sent includes a time stamp of the current time, in microseconds,
|
||||||
|
of the sending machine. The receiving machine calculates the difference between its
|
||||||
|
own timestamp and the one in the packet and sends this back in the ACK. This difference,
|
||||||
|
since it is in microseconds, will essentially be a random 32 bit number. However,
|
||||||
|
the difference will stay somewhat similar over time. Any changes in this difference
|
||||||
|
indicates that packets are either going through faster or slower.
|
||||||
|
|
||||||
|
In order to measure the one-way buffering delay, a base delay is established. The
|
||||||
|
base delay is the lowest ever seen value of the time stamp difference. Each delay
|
||||||
|
sample we receive back, is compared against the base delay and the delay is the
|
||||||
|
difference.
|
||||||
|
|
||||||
|
This is the delay that's fed into the congestion controller.
|
||||||
|
|
||||||
|
A histogram of typical delay measurements is shown to the right. This is from
|
||||||
|
a transfer between a cable modem connection and a DSL connection.
|
||||||
|
|
||||||
|
The details of the delay measurements are slightly more complicated since the
|
||||||
|
values needs to be able to wrap (cross the 2^32 boundry and start over at 0).
|
||||||
|
|
||||||
|
Path MTU discovery
|
||||||
|
------------------
|
||||||
|
|
||||||
|
MTU is short for *Maximum Transfer Unit* and describes the largest packet size that
|
||||||
|
can be sent over a link. Any datagrams which size exceeds this limit will either
|
||||||
|
be *fragmented* or dropped. A fragmented datagram means that the payload is split up
|
||||||
|
in multiple packets, each with its own individual packet header.
|
||||||
|
|
||||||
|
There are several reasons to avoid sending datagrams that get fragmented:
|
||||||
|
|
||||||
|
1. A fragmented datagram is more likely to be lost. If any fragment is lost,
|
||||||
|
the whole datagram is dropped.
|
||||||
|
|
||||||
|
2. Bandwidth is likely to be wasted. If the datagram size is not divisible
|
||||||
|
by the MTU the last packet will not contain as much payload as it could, and the
|
||||||
|
payload over protocol header ratio decreases.
|
||||||
|
|
||||||
|
3. It's expensive to fragment datagrams. Few routers are optimized to handle large
|
||||||
|
numbers of fragmented packets. Datagrams that have to fragment are likely to
|
||||||
|
be delayed significantly, and contribute to more CPU being used on routers.
|
||||||
|
Typically fragmentation (and other advanced IP features) are implemented in
|
||||||
|
software (slow) and not hardware (fast).
|
||||||
|
|
||||||
|
The path MTU is the lowest MTU of any link along a path from two endpoints on the
|
||||||
|
internet. The MTU bottleneck isn't necessarily at one of the endpoints, but can
|
||||||
|
be anywhere in between.
|
||||||
|
|
||||||
|
The most common MTU is 1500 bytes, which is the largest packet size for ethernet
|
||||||
|
networks. Many home DSL connections, however, tunnel IP through PPPoE (Point to
|
||||||
|
Point Protocol over Ethernet. Yes, that is the old dial-up modem protocol). This
|
||||||
|
protocol uses up 8 bytes per packet for its own header.
|
||||||
|
|
||||||
|
If the user happens to be on an internet connection over a VPN, it will add another
|
||||||
|
layer, with its own packet headers.
|
||||||
|
|
||||||
|
In short; if you would pick the largest possible packet size on an ethernet network,
|
||||||
|
1472, and stick with it, you would be quite likely to generate fragments for a lot
|
||||||
|
of connections. The fragments that will be created will be very small and especially
|
||||||
|
inflate the overhead waste.
|
||||||
|
|
||||||
|
The other approach of picking a very conservative packet size, that would be very
|
||||||
|
unlikely to get fragmented has the following drawbacks:
|
||||||
|
|
||||||
|
1. People on good, normal, networks will be penalized with a small packet size.
|
||||||
|
Both in terms of router load but also bandwidth waste.
|
||||||
|
|
||||||
|
2. Software routers are typically not limited by the number of bytes they can route,
|
||||||
|
but the number of packets. Small packets means more of them, and more load on
|
||||||
|
software routers.
|
||||||
|
|
||||||
|
The solution to the problem of finding the optimal packet size, is to dynamically
|
||||||
|
adjust the packet size and search for the largest size that can make it through
|
||||||
|
without being fragmented along the path.
|
||||||
|
|
||||||
|
To help do this, you can set the DF bit (Don't Fragment) in your Datagrams. This
|
||||||
|
asks routers that otherwise would fragment packets to instead drop them, and send
|
||||||
|
back an ICMP message reporting the MTU of the link the packet couldn't fit. With
|
||||||
|
this message, it's very simple to discover the path MTU. You simply mark your packets
|
||||||
|
not to be fragmented, and change your packet size whenever you receive the ICMP
|
||||||
|
packet-too-big message.
|
||||||
|
|
||||||
|
Unfortunately it's not quite that simple. There are a significant number of firewalls
|
||||||
|
in the wild blocking all ICMP messages. This means we can't rely on them, we also have
|
||||||
|
to guess that a packet was dropped because of its size. This is done by only marking
|
||||||
|
certain packets with DF, and if all other packets go through, except for the MTU probes,
|
||||||
|
we know that we need to lower our packet sizes.
|
||||||
|
|
||||||
|
If we set up bounds for the path MTU (say the minimum internet MTU, 576 and ethernet's 1500),
|
||||||
|
we can do a binary search for the MTU. This would let us find it in just a few round-trips.
|
||||||
|
|
||||||
|
On top of this, libtorrent has an optimization where it figures out which interface a
|
||||||
|
uTP connection will be sent over, and initialize the MTU ceiling to that interface's MTU.
|
||||||
|
This means that a VPN tunnel would advertize its MTU as lower, and the uTP connection would
|
||||||
|
immediately know to send smaller packets, no search required. It also has the side-effect
|
||||||
|
of being able to use much larger packet sizes for non-ethernet interfaces or ethernet links
|
||||||
|
with jumbo frames.
|
||||||
|
|
||||||
|
clock drift
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. image:: our_delay_base_thumb.png
|
||||||
|
:target: our_delay_base.png
|
||||||
|
:align: right
|
||||||
|
|
||||||
|
Clock drift is clocks progressing at different rates. It's different from clock
|
||||||
|
skew which means clocks set to different values (but which may progress at the same
|
||||||
|
rate).
|
||||||
|
|
||||||
|
Any clock drift between the two machines involved in a uTP transfer will result
|
||||||
|
in systematically inflated or deflated delay measurements.
|
||||||
|
|
||||||
|
This can be solved by letting the base delay be the lowest seen sample in the last
|
||||||
|
*n* minutes. This is a trade-off between seeing a single packet go straight through
|
||||||
|
the queue, with no delay, and the amount of clock drift one can assume on normal computers.
|
||||||
|
|
||||||
|
It turns out that it's fairly safe to assume that one of your packets will in fact go
|
||||||
|
straight through without any significant delay, once every 20 minutes or so. However,
|
||||||
|
the clock drift between normal computers can be as much as 17 ms in 10 minutes. 17 ms
|
||||||
|
is quite significant, especially if your target delay is 25 ms (as in the LEDBAT_ spec).
|
||||||
|
|
||||||
|
Clocks progresses at different rates depending on temperature. This means computers
|
||||||
|
running hot are likely to have a clock drift compared to computers running cool.
|
||||||
|
|
||||||
|
So, by updating the delay base periodically based on the lowest seen sample, you'll either
|
||||||
|
end up changing it upwards (artificaially making the delay samples appear small) without
|
||||||
|
the congestion or delay actually having changed, or you'll end up with a significant clock
|
||||||
|
drift and have artificially low samples because of that.
|
||||||
|
|
||||||
|
The solution to this problem is based on the fact that the clock drift is only a problem
|
||||||
|
for one of the sides of the connection. Only when your delay measurements keep increasing
|
||||||
|
is it a problem. If your delay measurements keep decreasing, the samples will simply push
|
||||||
|
down the delay base along with it. With this in mind, we can simply keep track of the
|
||||||
|
other end's delay measurements as well, applying the same logic to it. Whenever the
|
||||||
|
other end's base delay is adjusted downwards, we adjust our base delay upwards by the same
|
||||||
|
amount.
|
||||||
|
|
||||||
|
This will accurately keep the base delay updated with the clock drift and improve
|
||||||
|
the delay measurements. The figure on the right shows the absolute timestamp differences
|
||||||
|
along with the base delay. The slope of the measurements is caused by clock drift.
|
||||||
|
|
||||||
|
For more information on the clock drift compensation, see the slides from BitTorrent's
|
||||||
|
presentation at IPTPS10_.
|
||||||
|
|
||||||
|
.. _IPTPS10: http://www.usenix.org/event/iptps10/tech/slides/cohen.pdf
|
||||||
|
.. _LEDBAT: https://datatracker.ietf.org/doc/draft-ietf-ledbat-congestion/
|
||||||
|
|
||||||
|
features
|
||||||
|
--------
|
||||||
|
|
||||||
|
libtorrent's uTP implementation includes the following features:
|
||||||
|
|
||||||
|
* Path MTU discovery, including jumbo frames and detecting restricted
|
||||||
|
MTU tunnels. Binary search packet sizes to find the largest non-fragmented.
|
||||||
|
* Selective ACK. The ability to acknowledge individual packets in the
|
||||||
|
event of packet loss
|
||||||
|
* Fast resend. The first time a packet is lost, it's resent immediately.
|
||||||
|
Triggered by duplicate ACKs.
|
||||||
|
* Nagle's algorithm. Minimize protocol overhead by attempting to lump
|
||||||
|
full packets of payload together before sending a packet.
|
||||||
|
* Delayed ACKs to minimize protocol overhead.
|
||||||
|
* Microsecond resolution timestamps.
|
||||||
|
* Advertised receive window, to support download rate limiting.
|
||||||
|
* Correct handling of wrapping sequence numbers.
|
||||||
|
* Easy configuration of target-delay, gain-factor, timeouts, delayed-ack
|
||||||
|
and socket buffers.
|
||||||
|
|
@ -3,7 +3,8 @@ example_programs = \
|
|||||||
dump_torrent \
|
dump_torrent \
|
||||||
enum_if \
|
enum_if \
|
||||||
make_torrent \
|
make_torrent \
|
||||||
simple_client
|
simple_client \
|
||||||
|
utp_test
|
||||||
|
|
||||||
if ENABLE_EXAMPLES
|
if ENABLE_EXAMPLES
|
||||||
bin_PROGRAMS = $(example_programs)
|
bin_PROGRAMS = $(example_programs)
|
||||||
|
@ -174,6 +174,7 @@ bool print_file_progress = false;
|
|||||||
bool show_pad_files = false;
|
bool show_pad_files = false;
|
||||||
bool show_dht_status = false;
|
bool show_dht_status = false;
|
||||||
bool sequential_download = false;
|
bool sequential_download = false;
|
||||||
|
bool print_utp_stats = false;
|
||||||
|
|
||||||
bool print_ip = true;
|
bool print_ip = true;
|
||||||
bool print_as = false;
|
bool print_as = false;
|
||||||
@ -384,7 +385,7 @@ int peer_index(libtorrent::tcp::endpoint addr, std::vector<libtorrent::peer_info
|
|||||||
void print_peer_info(std::string& out, std::vector<libtorrent::peer_info> const& peers)
|
void print_peer_info(std::string& out, std::vector<libtorrent::peer_info> const& peers)
|
||||||
{
|
{
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
if (print_ip) out += "IP ";
|
if (print_ip) out += "IP ";
|
||||||
#ifndef TORRENT_DISABLE_GEO_IP
|
#ifndef TORRENT_DISABLE_GEO_IP
|
||||||
if (print_as) out += "AS ";
|
if (print_as) out += "AS ";
|
||||||
#endif
|
#endif
|
||||||
@ -409,8 +410,8 @@ void print_peer_info(std::string& out, std::vector<libtorrent::peer_info> const&
|
|||||||
|
|
||||||
if (print_ip)
|
if (print_ip)
|
||||||
{
|
{
|
||||||
error_code ec;
|
snprintf(str, sizeof(str), "%-30s %-22s", (print_endpoint(i->ip) +
|
||||||
snprintf(str, sizeof(str), "%-22s %22s ", print_endpoint(i->ip).c_str()
|
(i->connection_type == peer_info::bittorrent_utp ? " [uTP]" : "")).c_str()
|
||||||
, print_endpoint(i->local_endpoint).c_str());
|
, print_endpoint(i->local_endpoint).c_str());
|
||||||
out += str;
|
out += str;
|
||||||
}
|
}
|
||||||
@ -425,7 +426,7 @@ void print_peer_info(std::string& out, std::vector<libtorrent::peer_info> const&
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
snprintf(str, sizeof(str)
|
snprintf(str, sizeof(str)
|
||||||
, "%s%s (%s|%s) %s%s (%s|%s) %s%3d (%3d) %3d %c%c%c%c%c%c%c%c%c%c%c%c%c%c %c%c%c%c%c%c "
|
, "%s%s (%s|%s) %s%s (%s|%s) %s%3d (%3d) %3d %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c%c%c%c%c%c "
|
||||||
, esc("32"), add_suffix(i->down_speed, "/s").c_str()
|
, esc("32"), add_suffix(i->down_speed, "/s").c_str()
|
||||||
, add_suffix(i->total_download).c_str(), add_suffix(i->download_rate_peak, "/s").c_str()
|
, add_suffix(i->total_download).c_str(), add_suffix(i->download_rate_peak, "/s").c_str()
|
||||||
, esc("31"), add_suffix(i->up_speed, "/s").c_str(), add_suffix(i->total_upload).c_str()
|
, esc("31"), add_suffix(i->up_speed, "/s").c_str(), add_suffix(i->total_upload).c_str()
|
||||||
@ -456,6 +457,8 @@ void print_peer_info(std::string& out, std::vector<libtorrent::peer_info> const&
|
|||||||
#else
|
#else
|
||||||
, '.'
|
, '.'
|
||||||
#endif
|
#endif
|
||||||
|
, (i->flags & peer_info::holepunched)?'h':'.'
|
||||||
|
|
||||||
, (i->source & peer_info::tracker)?'T':'_'
|
, (i->source & peer_info::tracker)?'T':'_'
|
||||||
, (i->source & peer_info::pex)?'P':'_'
|
, (i->source & peer_info::pex)?'P':'_'
|
||||||
, (i->source & peer_info::dht)?'D':'_'
|
, (i->source & peer_info::dht)?'D':'_'
|
||||||
@ -833,9 +836,12 @@ int main(int argc, char* argv[])
|
|||||||
" -L <user:passwd> Use the specified username and password for the\n"
|
" -L <user:passwd> Use the specified username and password for the\n"
|
||||||
" proxy specified by -P\n"
|
" proxy specified by -P\n"
|
||||||
" -H Don't start DHT\n"
|
" -H Don't start DHT\n"
|
||||||
|
" -M Disable TCP/uTP bandwidth balancing\n"
|
||||||
" -W <num peers> Set the max number of peers to keep in the peer list\n"
|
" -W <num peers> Set the max number of peers to keep in the peer list\n"
|
||||||
" -N Do not attempt to use UPnP and NAT-PMP to forward ports\n"
|
" -N Do not attempt to use UPnP and NAT-PMP to forward ports\n"
|
||||||
" -Y Rate limit local peers\n"
|
" -Y Rate limit local peers\n"
|
||||||
|
" -y Disable TCP connections (disable outgoing TCP and reject\n"
|
||||||
|
" incoming TCP connections)\n"
|
||||||
" -q <num loops> automatically quit the client after <num loops> of refreshes\n"
|
" -q <num loops> automatically quit the client after <num loops> of refreshes\n"
|
||||||
" this is useful for scripting tests\n"
|
" this is useful for scripting tests\n"
|
||||||
" "
|
" "
|
||||||
@ -903,8 +909,6 @@ int main(int argc, char* argv[])
|
|||||||
{
|
{
|
||||||
if (argv[i][0] != '-')
|
if (argv[i][0] != '-')
|
||||||
{
|
{
|
||||||
// interpret this as a torrent
|
|
||||||
|
|
||||||
// match it against the <hash>@<tracker> format
|
// match it against the <hash>@<tracker> format
|
||||||
if (strlen(argv[i]) > 45
|
if (strlen(argv[i]) > 45
|
||||||
&& is_hex(argv[i], 40)
|
&& is_hex(argv[i], 40)
|
||||||
@ -955,7 +959,7 @@ int main(int argc, char* argv[])
|
|||||||
case 'U': torrent_upload_limit = atoi(arg) * 1000; break;
|
case 'U': torrent_upload_limit = atoi(arg) * 1000; break;
|
||||||
case 'D': torrent_download_limit = atoi(arg) * 1000; break;
|
case 'D': torrent_download_limit = atoi(arg) * 1000; break;
|
||||||
case 'm': monitor_dir = arg; break;
|
case 'm': monitor_dir = arg; break;
|
||||||
case 'M': share_mode = true; --i; break;
|
case 'Q': share_mode = true; --i; break;
|
||||||
case 'b': bind_to_interface = arg; break;
|
case 'b': bind_to_interface = arg; break;
|
||||||
case 'w': settings.urlseed_wait_retry = atoi(arg); break;
|
case 'w': settings.urlseed_wait_retry = atoi(arg); break;
|
||||||
case 't': poll_interval = atoi(arg); break;
|
case 't': poll_interval = atoi(arg); break;
|
||||||
@ -1006,6 +1010,8 @@ int main(int argc, char* argv[])
|
|||||||
case 'A': settings.allowed_fast_set_size = atoi(arg); break;
|
case 'A': settings.allowed_fast_set_size = atoi(arg); break;
|
||||||
case 'R': settings.read_cache_line_size = atoi(arg); break;
|
case 'R': settings.read_cache_line_size = atoi(arg); break;
|
||||||
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 'y': settings.enable_outgoing_tcp = false; settings.enable_incoming_tcp = false; --i; break;
|
||||||
case 'P':
|
case 'P':
|
||||||
{
|
{
|
||||||
char* port = (char*) strrchr(arg, ':');
|
char* port = (char*) strrchr(arg, ':');
|
||||||
@ -1297,6 +1303,7 @@ int main(int argc, char* argv[])
|
|||||||
if (c == 'h') show_pad_files = !show_pad_files;
|
if (c == 'h') show_pad_files = !show_pad_files;
|
||||||
if (c == 'a') print_piece_bar = !print_piece_bar;
|
if (c == 'a') print_piece_bar = !print_piece_bar;
|
||||||
if (c == 'g') show_dht_status = !show_dht_status;
|
if (c == 'g') show_dht_status = !show_dht_status;
|
||||||
|
if (c == 'u') print_utp_stats = !print_utp_stats;
|
||||||
// toggle columns
|
// toggle columns
|
||||||
if (c == '1') print_ip = !print_ip;
|
if (c == '1') print_ip = !print_ip;
|
||||||
if (c == '2') print_as = !print_as;
|
if (c == '2') print_as = !print_as;
|
||||||
@ -1566,6 +1573,15 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (print_utp_stats)
|
||||||
|
{
|
||||||
|
snprintf(str, sizeof(str), "uTP idle: %d syn: %d est: %d fin: %d wait: %d\n"
|
||||||
|
, sess_stat.utp_stats.num_idle, sess_stat.utp_stats.num_syn_sent
|
||||||
|
, sess_stat.utp_stats.num_connected, sess_stat.utp_stats.num_fin_sent
|
||||||
|
, sess_stat.utp_stats.num_close_wait);
|
||||||
|
out += str;
|
||||||
|
}
|
||||||
|
|
||||||
if (active_handle.is_valid())
|
if (active_handle.is_valid())
|
||||||
{
|
{
|
||||||
torrent_handle h = active_handle;
|
torrent_handle h = active_handle;
|
||||||
|
@ -61,15 +61,16 @@ int main()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%-18s%-18s%-35sinterface name\n", "destination", "network", "gateway");
|
printf("%-18s%-18s%-35s%-7sinterface\n", "destination", "network", "gateway", "mtu");
|
||||||
|
|
||||||
for (std::vector<ip_route>::const_iterator i = routes.begin()
|
for (std::vector<ip_route>::const_iterator i = routes.begin()
|
||||||
, end(routes.end()); i != end; ++i)
|
, end(routes.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
printf("%-18s%-18s%-35s%s\n"
|
printf("%-18s%-18s%-35s%-7d%s\n"
|
||||||
, i->destination.to_string(ec).c_str()
|
, i->destination.to_string(ec).c_str()
|
||||||
, i->netmask.to_string(ec).c_str()
|
, i->netmask.to_string(ec).c_str()
|
||||||
, i->gateway.to_string(ec).c_str()
|
, i->gateway.to_string(ec).c_str()
|
||||||
|
, i->mtu
|
||||||
, i->name);
|
, i->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,15 +83,16 @@ int main()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%-18s%-18s%-35sflags\n", "address", "netmask", "name");
|
printf("%-35s%-18s%-40s%-8sflags\n", "address", "netmask", "name", "mtu");
|
||||||
|
|
||||||
for (std::vector<ip_interface>::const_iterator i = net.begin()
|
for (std::vector<ip_interface>::const_iterator i = net.begin()
|
||||||
, end(net.end()); i != end; ++i)
|
, end(net.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
printf("%-18s%-18s%-35s%s%s%s\n"
|
printf("%-35s%-18s%-40s%-8d%s%s%s\n"
|
||||||
, i->interface_address.to_string(ec).c_str()
|
, i->interface_address.to_string(ec).c_str()
|
||||||
, i->netmask.to_string(ec).c_str()
|
, i->netmask.to_string(ec).c_str()
|
||||||
, i->name
|
, i->name
|
||||||
|
, i->mtu
|
||||||
, (is_multicast(i->interface_address)?"multicast ":"")
|
, (is_multicast(i->interface_address)?"multicast ":"")
|
||||||
, (is_local(i->interface_address)?"local ":"")
|
, (is_local(i->interface_address)?"local ":"")
|
||||||
, (is_loopback(i->interface_address)?"loopback ":"")
|
, (is_loopback(i->interface_address)?"loopback ":"")
|
||||||
|
48
examples/utp_test.cpp
Normal file
48
examples/utp_test.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "libtorrent/error_code.hpp"
|
||||||
|
#include "libtorrent/session.hpp"
|
||||||
|
#include "libtorrent/socket_type.hpp"
|
||||||
|
#include "libtorrent/utp_socket_manager.hpp"
|
||||||
|
#include "libtorrent/utp_stream.hpp"
|
||||||
|
|
||||||
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
void on_connect(error_code const& e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_udp_receive(error_code const& e, udp::endpoint const& ep
|
||||||
|
, char const* buf, int size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_utp_incoming(void* userdata
|
||||||
|
, boost::shared_ptr<utp_stream> const& utp_sock)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
//int rtt, rtt_var;
|
||||||
|
//int max_window, cur_window;
|
||||||
|
//int delay_factor, window_factor, scaled_gain;
|
||||||
|
|
||||||
|
/*session s;
|
||||||
|
s.listen_on(std::make_pair(6881, 6889));*/
|
||||||
|
|
||||||
|
io_service ios;
|
||||||
|
connection_queue cc(ios);
|
||||||
|
udp_socket udp_sock(ios, boost::bind(&on_udp_receive, _1, _2, _3, _4), cc);
|
||||||
|
|
||||||
|
void* userdata;
|
||||||
|
utp_socket_manager utp_sockets(udp_sock, boost::bind(&on_utp_incoming, _1, _2), userdata);
|
||||||
|
|
||||||
|
/*error_code ec;
|
||||||
|
utp_stream sock(ios, cc);
|
||||||
|
sock.bind(udp::endpoint(address_v4::any(), 0), ec);
|
||||||
|
|
||||||
|
tcp::endpoint ep(address_v4::from_string("239.192.152.143", ec), 6771);
|
||||||
|
|
||||||
|
sock.async_connect(ep, boost::bind(on_connect, _1));*/
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -94,6 +94,7 @@ nobase_include_HEADERS = \
|
|||||||
storage_defs.hpp \
|
storage_defs.hpp \
|
||||||
thread.hpp \
|
thread.hpp \
|
||||||
time.hpp \
|
time.hpp \
|
||||||
|
timestamp_history.hpp \
|
||||||
torrent_handle.hpp \
|
torrent_handle.hpp \
|
||||||
torrent.hpp \
|
torrent.hpp \
|
||||||
torrent_info.hpp \
|
torrent_info.hpp \
|
||||||
@ -102,6 +103,8 @@ nobase_include_HEADERS = \
|
|||||||
udp_tracker_connection.hpp \
|
udp_tracker_connection.hpp \
|
||||||
union_endpoint.hpp \
|
union_endpoint.hpp \
|
||||||
upnp.hpp \
|
upnp.hpp \
|
||||||
|
utp_socket_manager.hpp \
|
||||||
|
utp_stream.hpp \
|
||||||
utf8.hpp \
|
utf8.hpp \
|
||||||
version.hpp \
|
version.hpp \
|
||||||
web_peer_connection.hpp \
|
web_peer_connection.hpp \
|
||||||
|
@ -51,11 +51,17 @@ std::string demangle(char const* name);
|
|||||||
|
|
||||||
#if (defined __linux__ || defined __MACH__) && defined __GNUC__
|
#if (defined __linux__ || defined __MACH__) && defined __GNUC__
|
||||||
|
|
||||||
|
#if TORRENT_USE_IOSTREAM
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#endif
|
||||||
|
|
||||||
TORRENT_EXPORT void assert_fail(const char* expr, int line, char const* file, char const* function, char const* val);
|
TORRENT_EXPORT void assert_fail(const char* expr, int line, char const* file, char const* function, char const* val);
|
||||||
#define TORRENT_ASSERT(x) do { if (x) {} else assert_fail(#x, __LINE__, __FILE__, __PRETTY_FUNCTION__, 0); } while (false)
|
#define TORRENT_ASSERT(x) do { if (x) {} else assert_fail(#x, __LINE__, __FILE__, __PRETTY_FUNCTION__, 0); } while (false)
|
||||||
|
#if TORRENT_USE_IOSTREAM
|
||||||
#define TORRENT_ASSERT_VAL(x, y) do { if (x) {} else { std::stringstream __s__; __s__ << #y ": " << y; assert_fail(#x, __LINE__, __FILE__, __PRETTY_FUNCTION__, __s__.str().c_str()); } } while (false)
|
#define TORRENT_ASSERT_VAL(x, y) do { if (x) {} else { std::stringstream __s__; __s__ << #y ": " << y; assert_fail(#x, __LINE__, __FILE__, __PRETTY_FUNCTION__, __s__.str().c_str()); } } while (false)
|
||||||
|
#else
|
||||||
|
#define TORRENT_ASSERT_VAL(x, y) TORRENT_ASSERT(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
@ -82,6 +82,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "libtorrent/deadline_timer.hpp"
|
#include "libtorrent/deadline_timer.hpp"
|
||||||
#include "libtorrent/socket_io.hpp" // for print_address
|
#include "libtorrent/socket_io.hpp" // for print_address
|
||||||
#include "libtorrent/address.hpp"
|
#include "libtorrent/address.hpp"
|
||||||
|
#include "libtorrent/utp_socket_manager.hpp"
|
||||||
|
|
||||||
#ifdef TORRENT_STATS
|
#ifdef TORRENT_STATS
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -522,6 +523,15 @@ namespace libtorrent
|
|||||||
bandwidth_channel m_local_download_channel;
|
bandwidth_channel m_local_download_channel;
|
||||||
bandwidth_channel m_local_upload_channel;
|
bandwidth_channel m_local_upload_channel;
|
||||||
|
|
||||||
|
// all tcp peer connections are subject to these
|
||||||
|
// bandwidth limits. Local peers are excempted
|
||||||
|
// from this limit. The purpose is to be able to
|
||||||
|
// throttle TCP that passes over the internet
|
||||||
|
// bottleneck (i.e. modem) to avoid starving out
|
||||||
|
// uTP connections.
|
||||||
|
bandwidth_channel m_tcp_download_channel;
|
||||||
|
bandwidth_channel m_tcp_upload_channel;
|
||||||
|
|
||||||
bandwidth_channel* m_bandwidth_channel[2];
|
bandwidth_channel* m_bandwidth_channel[2];
|
||||||
|
|
||||||
tracker_manager m_tracker_manager;
|
tracker_manager m_tracker_manager;
|
||||||
@ -725,6 +735,8 @@ namespace libtorrent
|
|||||||
|
|
||||||
rate_limited_udp_socket m_udp_socket;
|
rate_limited_udp_socket m_udp_socket;
|
||||||
|
|
||||||
|
utp_socket_manager m_utp_socket_manager;
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
pe_settings m_pe_settings;
|
pe_settings m_pe_settings;
|
||||||
#endif
|
#endif
|
||||||
|
@ -49,6 +49,7 @@ namespace libtorrent
|
|||||||
TORRENT_EXPORT bool is_loopback(address const& addr);
|
TORRENT_EXPORT bool is_loopback(address const& addr);
|
||||||
TORRENT_EXPORT bool is_multicast(address const& addr);
|
TORRENT_EXPORT bool is_multicast(address const& addr);
|
||||||
TORRENT_EXPORT bool is_any(address const& addr);
|
TORRENT_EXPORT bool is_any(address const& addr);
|
||||||
|
TORRENT_EXPORT bool is_teredo(address const& addr);
|
||||||
TORRENT_EXPORT int cidr_distance(address const& a1, address const& a2);
|
TORRENT_EXPORT int cidr_distance(address const& a1, address const& a2);
|
||||||
|
|
||||||
// determines if the operating system supports IPv6
|
// determines if the operating system supports IPv6
|
||||||
|
@ -102,7 +102,12 @@ namespace libtorrent
|
|||||||
|
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
enum { upload_only_msg = 2, share_mode_msg = 3 };
|
enum
|
||||||
|
{
|
||||||
|
upload_only_msg = 2,
|
||||||
|
holepunch_msg = 3,
|
||||||
|
share_mode_msg = 4
|
||||||
|
};
|
||||||
|
|
||||||
~bt_peer_connection();
|
~bt_peer_connection();
|
||||||
|
|
||||||
@ -140,6 +145,20 @@ namespace libtorrent
|
|||||||
num_supported_messages
|
num_supported_messages
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum hp_message_t
|
||||||
|
{
|
||||||
|
// msg_types
|
||||||
|
hp_rendezvous = 0,
|
||||||
|
hp_connect = 1,
|
||||||
|
hp_failed = 2,
|
||||||
|
|
||||||
|
// error codes
|
||||||
|
hp_no_such_peer = 1,
|
||||||
|
hp_not_connected = 2,
|
||||||
|
hp_no_support = 3,
|
||||||
|
hp_no_self = 4
|
||||||
|
};
|
||||||
|
|
||||||
// called from the main loop when this connection has any
|
// called from the main loop when this connection has any
|
||||||
// work to do.
|
// work to do.
|
||||||
|
|
||||||
@ -151,6 +170,9 @@ namespace libtorrent
|
|||||||
virtual void get_specific_peer_info(peer_info& p) const;
|
virtual void get_specific_peer_info(peer_info& p) const;
|
||||||
virtual bool in_handshake() const;
|
virtual bool in_handshake() const;
|
||||||
|
|
||||||
|
bool supports_holepunch() const { return m_holepunch_id != 0; }
|
||||||
|
void write_holepunch_msg(int type, tcp::endpoint const& ep, int error);
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
bool support_extensions() const { return m_supports_extensions; }
|
bool support_extensions() const { return m_supports_extensions; }
|
||||||
#endif
|
#endif
|
||||||
@ -183,6 +205,7 @@ namespace libtorrent
|
|||||||
void on_have_none(int received);
|
void on_have_none(int received);
|
||||||
void on_reject_request(int received);
|
void on_reject_request(int received);
|
||||||
void on_allowed_fast(int received);
|
void on_allowed_fast(int received);
|
||||||
|
void on_holepunch();
|
||||||
|
|
||||||
void on_extended(int received);
|
void on_extended(int received);
|
||||||
|
|
||||||
@ -283,7 +306,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
peer_connection::append_send_buffer(buffer, size, destructor);
|
peer_connection::append_send_buffer(buffer, size, destructor, true);
|
||||||
}
|
}
|
||||||
void setup_send();
|
void setup_send();
|
||||||
|
|
||||||
@ -366,6 +389,9 @@ private:
|
|||||||
// 0 if not supported
|
// 0 if not supported
|
||||||
int m_upload_only_id;
|
int m_upload_only_id;
|
||||||
|
|
||||||
|
// the message ID for holepunch messages
|
||||||
|
int m_holepunch_id;
|
||||||
|
|
||||||
// the message ID for share mode message
|
// the message ID for share mode message
|
||||||
// 0 if not supported
|
// 0 if not supported
|
||||||
int m_share_mode_id;
|
int m_share_mode_id;
|
||||||
|
@ -42,11 +42,13 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// the interface should not have a netmask
|
||||||
struct ip_interface
|
struct ip_interface
|
||||||
{
|
{
|
||||||
address interface_address;
|
address interface_address;
|
||||||
address netmask;
|
address netmask;
|
||||||
char name[64];
|
char name[64];
|
||||||
|
int mtu;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ip_route
|
struct ip_route
|
||||||
@ -55,6 +57,7 @@ namespace libtorrent
|
|||||||
address netmask;
|
address netmask;
|
||||||
address gateway;
|
address gateway;
|
||||||
char name[64];
|
char name[64];
|
||||||
|
int mtu;
|
||||||
};
|
};
|
||||||
|
|
||||||
// returns a list of the configured IP interfaces
|
// returns a list of the configured IP interfaces
|
||||||
@ -64,9 +67,8 @@ namespace libtorrent
|
|||||||
|
|
||||||
TORRENT_EXPORT std::vector<ip_route> enum_routes(io_service& ios, error_code& ec);
|
TORRENT_EXPORT std::vector<ip_route> enum_routes(io_service& ios, error_code& ec);
|
||||||
|
|
||||||
// returns true if the specified address is on the same
|
// return (a1 & mask) == (a2 & mask)
|
||||||
// local network as the specified interface
|
TORRENT_EXPORT bool match_addr_mask(address const& a1, address const& a2, address const& mask);
|
||||||
TORRENT_EXPORT bool in_subnet(address const& addr, ip_interface const& iface);
|
|
||||||
|
|
||||||
// returns true if the specified address is on the same
|
// returns true if the specified address is on the same
|
||||||
// local network as us
|
// local network as us
|
||||||
|
@ -165,7 +165,7 @@ namespace libtorrent
|
|||||||
pex_message_too_large,
|
pex_message_too_large,
|
||||||
invalid_pex_message,
|
invalid_pex_message,
|
||||||
invalid_lt_tracker_message,
|
invalid_lt_tracker_message,
|
||||||
reserved108,
|
too_frequent_pex,
|
||||||
reserved109,
|
reserved109,
|
||||||
reserved110,
|
reserved110,
|
||||||
reserved111,
|
reserved111,
|
||||||
|
@ -90,6 +90,8 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
virtual ~peer_plugin() {}
|
virtual ~peer_plugin() {}
|
||||||
|
|
||||||
|
virtual char const* type() const { return ""; }
|
||||||
|
|
||||||
// can add entries to the extension handshake
|
// can add entries to the extension handshake
|
||||||
// this is not called for web seeds
|
// this is not called for web seeds
|
||||||
virtual void add_handshake(entry&) {}
|
virtual void add_handshake(entry&) {}
|
||||||
|
@ -39,10 +39,12 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
struct proxy_settings;
|
struct proxy_settings;
|
||||||
|
struct utp_socket_manager;
|
||||||
|
|
||||||
bool instantiate_connection(io_service& ios
|
bool instantiate_connection(io_service& ios
|
||||||
, proxy_settings const& ps, socket_type& s
|
, proxy_settings const& ps, socket_type& s
|
||||||
, void* ssl_context = 0);
|
, void* ssl_context = 0
|
||||||
|
, utp_socket_manager* sm = 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -93,6 +93,18 @@ namespace libtorrent
|
|||||||
value = max3<temp1, temp2, temp3>::value
|
value = max3<temp1, temp2, temp3>::value
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8>
|
||||||
|
struct max8
|
||||||
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
temp1 = max<v1,v2>::value,
|
||||||
|
temp2 = max3<v3,v4,v5>::value,
|
||||||
|
temp3 = max3<v6,v7,v8>::value,
|
||||||
|
value = max3<temp1, temp2, temp3>::value
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
108
include/libtorrent/packet_buffer.hpp
Normal file
108
include/libtorrent/packet_buffer.hpp
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2010, Arvid Norberg, Daniel Wallin.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TORRENT_PACKET_BUFFER_HPP_INCLUDED
|
||||||
|
#define TORRENT_PACKET_BUFFER_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include "boost/cstdint.hpp"
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
// this is a circular buffer that automatically resizes
|
||||||
|
// itself as elements are inserted. Elements are indexed
|
||||||
|
// by integers and are assumed to be sequential. Unless the
|
||||||
|
// old elements are removed when new elements are inserted,
|
||||||
|
// the buffer will be resized.
|
||||||
|
|
||||||
|
// if m_mask is 0xf, m_array has 16 elements
|
||||||
|
// m_cursor is the lowest index that has an element
|
||||||
|
// it also determines which indices the other slots
|
||||||
|
// refers to. Since it's a circular buffer, it wraps
|
||||||
|
// around. For example
|
||||||
|
|
||||||
|
// m_cursor = 9
|
||||||
|
// | refers to index 14
|
||||||
|
// | |
|
||||||
|
// V V
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | | | | | | | | | | | | | | | | | m_mask = 0xf
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// ^
|
||||||
|
// |
|
||||||
|
// refers to index 15
|
||||||
|
|
||||||
|
// whenever the element at the cursor is removed, the
|
||||||
|
// cursor is bumped to the next occupied element
|
||||||
|
|
||||||
|
class packet_buffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef boost::uint32_t index_type;
|
||||||
|
|
||||||
|
packet_buffer();
|
||||||
|
~packet_buffer();
|
||||||
|
|
||||||
|
void* insert(index_type idx, void* value);
|
||||||
|
|
||||||
|
std::size_t size() const
|
||||||
|
{ return m_size; }
|
||||||
|
|
||||||
|
std::size_t capacity() const
|
||||||
|
{ return m_capacity; }
|
||||||
|
|
||||||
|
void* at(index_type idx) const;
|
||||||
|
|
||||||
|
void* remove(index_type idx);
|
||||||
|
|
||||||
|
void reserve(std::size_t size);
|
||||||
|
|
||||||
|
index_type cursor() const
|
||||||
|
{ return m_first; }
|
||||||
|
|
||||||
|
index_type span() const
|
||||||
|
{ return (m_last - m_first) & 0xffff; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void** m_storage;
|
||||||
|
std::size_t m_capacity;
|
||||||
|
std::size_t m_size;
|
||||||
|
|
||||||
|
// This defines the first index that is part of the m_storage.
|
||||||
|
// The last index is (m_first + (m_capacity - 1)) & 0xffff.
|
||||||
|
index_type m_first;
|
||||||
|
index_type m_last;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TORRENT_PACKET_BUFFER_HPP_INCLUDED
|
||||||
|
|
@ -78,6 +78,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "libtorrent/bandwidth_socket.hpp"
|
#include "libtorrent/bandwidth_socket.hpp"
|
||||||
#include "libtorrent/socket_type_fwd.hpp"
|
#include "libtorrent/socket_type_fwd.hpp"
|
||||||
#include "libtorrent/error_code.hpp"
|
#include "libtorrent/error_code.hpp"
|
||||||
|
#include "libtorrent/sliding_average.hpp"
|
||||||
|
|
||||||
#ifdef TORRENT_STATS
|
#ifdef TORRENT_STATS
|
||||||
#include "libtorrent/aux_/session_impl.hpp"
|
#include "libtorrent/aux_/session_impl.hpp"
|
||||||
@ -86,9 +87,11 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
class torrent;
|
class torrent;
|
||||||
struct peer_plugin;
|
|
||||||
struct peer_info;
|
struct peer_info;
|
||||||
struct disk_io_job;
|
struct disk_io_job;
|
||||||
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
|
struct peer_plugin;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
@ -202,6 +205,7 @@ namespace libtorrent
|
|||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
void add_extension(boost::shared_ptr<peer_plugin>);
|
void add_extension(boost::shared_ptr<peer_plugin>);
|
||||||
|
peer_plugin const* find_plugin(char const* type);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// this function is called once the torrent associated
|
// this function is called once the torrent associated
|
||||||
@ -284,6 +288,14 @@ namespace libtorrent
|
|||||||
void set_upload_only(bool u);
|
void set_upload_only(bool u);
|
||||||
bool upload_only() const { return m_upload_only; }
|
bool upload_only() const { return m_upload_only; }
|
||||||
|
|
||||||
|
void set_holepunch_mode()
|
||||||
|
{
|
||||||
|
m_holepunch_mode = true;
|
||||||
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
(*m_logger) << time_now_string() << "*** HOLEPUNCH MODE ***\n";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// will send a keep-alive message to the peer
|
// will send a keep-alive message to the peer
|
||||||
void keep_alive();
|
void keep_alive();
|
||||||
|
|
||||||
@ -341,6 +353,9 @@ namespace libtorrent
|
|||||||
void on_timeout();
|
void on_timeout();
|
||||||
// this will cause this peer_connection to be disconnected.
|
// this will cause this peer_connection to be disconnected.
|
||||||
virtual void disconnect(error_code const& ec, int error = 0);
|
virtual void disconnect(error_code const& ec, int error = 0);
|
||||||
|
// called when a connect attempt fails (not when an
|
||||||
|
// established connection fails)
|
||||||
|
void connect_failed(error_code const& e);
|
||||||
bool is_disconnecting() const { return m_disconnecting; }
|
bool is_disconnecting() const { return m_disconnecting; }
|
||||||
|
|
||||||
// this is called when the connection attempt has succeeded
|
// this is called when the connection attempt has succeeded
|
||||||
@ -522,11 +537,17 @@ namespace libtorrent
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class Destructor>
|
template <class Destructor>
|
||||||
void append_send_buffer(char* buffer, int size, Destructor const& destructor)
|
void append_send_buffer(char* buffer, int size, Destructor const& destructor
|
||||||
|
, bool encrypted = false)
|
||||||
{
|
{
|
||||||
#if defined TORRENT_STATS && defined TORRENT_DISK_STATS
|
#if defined TORRENT_STATS && defined TORRENT_DISK_STATS
|
||||||
log_buffer_usage(buffer, size, "queued send buffer");
|
log_buffer_usage(buffer, size, "queued send buffer");
|
||||||
#endif
|
#endif
|
||||||
|
// bittorrent connections should never use this function, since
|
||||||
|
// they might be encrypted and this would circumvent the actual
|
||||||
|
// encryption. bt_peer_connection overrides this function with
|
||||||
|
// its own version.
|
||||||
|
TORRENT_ASSERT(encrypted || type() != bittorrent_connection);
|
||||||
m_send_buffer.append_buffer(buffer, size, size, destructor);
|
m_send_buffer.append_buffer(buffer, size, size, destructor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,6 +655,8 @@ namespace libtorrent
|
|||||||
|
|
||||||
bool verify_piece(peer_request const& p) const;
|
bool verify_piece(peer_request const& p) const;
|
||||||
|
|
||||||
|
void update_desired_queue_size();
|
||||||
|
|
||||||
// the bandwidth channels, upload and download
|
// the bandwidth channels, upload and download
|
||||||
// keeps track of the current quotas
|
// keeps track of the current quotas
|
||||||
bandwidth_channel m_bandwidth_channel[num_channels];
|
bandwidth_channel m_bandwidth_channel[num_channels];
|
||||||
@ -665,6 +688,10 @@ namespace libtorrent
|
|||||||
// web seeds also has a limit on the queue size.
|
// web seeds also has a limit on the queue size.
|
||||||
int m_max_out_request_queue;
|
int m_max_out_request_queue;
|
||||||
|
|
||||||
|
// the average rate of receiving complete piece messages
|
||||||
|
sliding_average<20> m_piece_rate;
|
||||||
|
sliding_average<20> m_send_rate;
|
||||||
|
|
||||||
void set_timeout(int s) { m_timeout = s; }
|
void set_timeout(int s) { m_timeout = s; }
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
@ -711,6 +738,7 @@ namespace libtorrent
|
|||||||
// the time when we last got a part of a
|
// the time when we last got a part of a
|
||||||
// piece packet from this peer
|
// piece packet from this peer
|
||||||
ptime m_last_piece;
|
ptime m_last_piece;
|
||||||
|
|
||||||
// the time we sent a request to
|
// the time we sent a request to
|
||||||
// this peer the last time
|
// this peer the last time
|
||||||
ptime m_last_request;
|
ptime m_last_request;
|
||||||
@ -1076,6 +1104,9 @@ namespace libtorrent
|
|||||||
// set to true when we've sent the first round of suggests
|
// set to true when we've sent the first round of suggests
|
||||||
bool m_sent_suggests:1;
|
bool m_sent_suggests:1;
|
||||||
|
|
||||||
|
// set to true while we're trying to holepunch
|
||||||
|
bool m_holepunch_mode:1;
|
||||||
|
|
||||||
// when this is set, the transfer stats for this connection
|
// when this is set, the transfer stats for this connection
|
||||||
// is not included in the torrent or session stats
|
// is not included in the torrent or session stats
|
||||||
bool m_ignore_stats:1;
|
bool m_ignore_stats:1;
|
||||||
|
@ -59,7 +59,8 @@ namespace libtorrent
|
|||||||
seed = 0x400,
|
seed = 0x400,
|
||||||
optimistic_unchoke = 0x800,
|
optimistic_unchoke = 0x800,
|
||||||
snubbed = 0x1000,
|
snubbed = 0x1000,
|
||||||
upload_only = 0x2000
|
upload_only = 0x2000,
|
||||||
|
holepunched = 0x4000
|
||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
, rc4_encrypted = 0x100000,
|
, rc4_encrypted = 0x100000,
|
||||||
plaintext_encrypted = 0x200000
|
plaintext_encrypted = 0x200000
|
||||||
@ -186,7 +187,8 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
standard_bittorrent = 0,
|
standard_bittorrent = 0,
|
||||||
web_seed = 1,
|
web_seed = 1,
|
||||||
http_seed = 2
|
http_seed = 2,
|
||||||
|
bittorrent_utp = 3
|
||||||
};
|
};
|
||||||
int connection_type;
|
int connection_type;
|
||||||
|
|
||||||
|
@ -164,7 +164,8 @@ namespace libtorrent
|
|||||||
// 43 1 1 failcount, connectable, optimistically_unchoked, seed
|
// 43 1 1 failcount, connectable, optimistically_unchoked, seed
|
||||||
// 44 1 1 fast_reconnects, trust_points
|
// 44 1 1 fast_reconnects, trust_points
|
||||||
// 45 1 1 source, pe_support, is_v6_addr
|
// 45 1 1 source, pe_support, is_v6_addr
|
||||||
// 46 1 1 on_parole, banned, added_to_dht
|
// 46 1 1 on_parole, banned, added_to_dht, supports_utp,
|
||||||
|
// supports_holepunch
|
||||||
// 47 1 1 <padding>
|
// 47 1 1 <padding>
|
||||||
// 48
|
// 48
|
||||||
struct TORRENT_EXPORT peer
|
struct TORRENT_EXPORT peer
|
||||||
@ -311,6 +312,11 @@ namespace libtorrent
|
|||||||
// pinged by the DHT
|
// pinged by the DHT
|
||||||
bool added_to_dht:1;
|
bool added_to_dht:1;
|
||||||
#endif
|
#endif
|
||||||
|
// we think this peer supports uTP
|
||||||
|
bool supports_utp:1;
|
||||||
|
// we have been connected via uTP at least once
|
||||||
|
bool confirmed_supports_utp:1;
|
||||||
|
bool supports_holepunch:1;
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
bool in_use:1;
|
bool in_use:1;
|
||||||
#endif
|
#endif
|
||||||
|
@ -222,6 +222,11 @@ namespace libtorrent
|
|||||||
, default_peer_upload_rate(0)
|
, default_peer_upload_rate(0)
|
||||||
, default_peer_download_rate(0)
|
, default_peer_download_rate(0)
|
||||||
, broadcast_lsd(false)
|
, broadcast_lsd(false)
|
||||||
|
, enable_outgoing_utp(true)
|
||||||
|
, enable_incoming_utp(true)
|
||||||
|
, enable_outgoing_tcp(true)
|
||||||
|
, enable_incoming_tcp(true)
|
||||||
|
, max_pex_peers(200)
|
||||||
, ignore_resume_timestamps(false)
|
, ignore_resume_timestamps(false)
|
||||||
, anonymous_mode(false)
|
, anonymous_mode(false)
|
||||||
, tick_interval(100)
|
, tick_interval(100)
|
||||||
@ -234,6 +239,17 @@ namespace libtorrent
|
|||||||
, unchoke_slots_limit(8)
|
, unchoke_slots_limit(8)
|
||||||
, half_open_limit(0)
|
, half_open_limit(0)
|
||||||
, connections_limit(200)
|
, connections_limit(200)
|
||||||
|
, utp_target_delay(75) // milliseconds
|
||||||
|
, utp_gain_factor(1500) // bytes per rtt
|
||||||
|
, utp_min_timeout(500) // milliseconds
|
||||||
|
, utp_syn_resends(2)
|
||||||
|
, utp_fin_resends(2)
|
||||||
|
, utp_num_resends(6)
|
||||||
|
, utp_connect_timeout(3000) // milliseconds
|
||||||
|
, utp_delayed_ack(0) // milliseconds
|
||||||
|
, utp_dynamic_sock_buf(true)
|
||||||
|
, mixed_mode_algorithm(peer_proportional)
|
||||||
|
, rate_limit_utp(false)
|
||||||
, listen_queue_size(5)
|
, listen_queue_size(5)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -856,6 +872,24 @@ namespace libtorrent
|
|||||||
// a network is known not to support multicast, this can be enabled
|
// a network is known not to support multicast, this can be enabled
|
||||||
bool broadcast_lsd;
|
bool broadcast_lsd;
|
||||||
|
|
||||||
|
// when set to true, libtorrent will try to make outgoing utp connections
|
||||||
|
bool enable_outgoing_utp;
|
||||||
|
|
||||||
|
// if set to false, libtorrent will reject incoming utp connections
|
||||||
|
bool enable_incoming_utp;
|
||||||
|
|
||||||
|
// when set to false, no outgoing TCP connections will be made
|
||||||
|
bool enable_outgoing_tcp;
|
||||||
|
|
||||||
|
// if set to false, libtorrent will reject incoming tcp connections
|
||||||
|
bool enable_incoming_tcp;
|
||||||
|
|
||||||
|
// the max number of peers we accept from pex messages from a single peer.
|
||||||
|
// this limits the number of concurrent peers any of our peers claims to
|
||||||
|
// be connected to. If they clain to be connected to more than this, we'll
|
||||||
|
// ignore any peer that exceeds this limit
|
||||||
|
int max_pex_peers;
|
||||||
|
|
||||||
// when set to true, the file modification time is ignored when loading
|
// when set to true, the file modification time is ignored when loading
|
||||||
// resume data. The resume data includes the expected timestamp of each
|
// resume data. The resume data includes the expected timestamp of each
|
||||||
// file and is typically compared to make sure the files haven't changed
|
// file and is typically compared to make sure the files haven't changed
|
||||||
@ -903,6 +937,57 @@ namespace libtorrent
|
|||||||
// the max number of connections in the session
|
// the max number of connections in the session
|
||||||
int connections_limit;
|
int connections_limit;
|
||||||
|
|
||||||
|
// target delay, milliseconds
|
||||||
|
int utp_target_delay;
|
||||||
|
|
||||||
|
// max number of bytes to increase cwnd per rtt in uTP
|
||||||
|
// congestion controller
|
||||||
|
int utp_gain_factor;
|
||||||
|
|
||||||
|
// the shortest allowed uTP connection timeout in milliseconds
|
||||||
|
// defaults to 500 milliseconds. The shorter timeout, the
|
||||||
|
// faster the connection recovers from a loss of an entire window
|
||||||
|
int utp_min_timeout;
|
||||||
|
|
||||||
|
// the number of SYN packets that are sent before giving up
|
||||||
|
int utp_syn_resends;
|
||||||
|
|
||||||
|
// the number of resent packets sent on a closed socket before giving up
|
||||||
|
int utp_fin_resends;
|
||||||
|
|
||||||
|
// the number of times to send a packet before giving up
|
||||||
|
int utp_num_resends;
|
||||||
|
|
||||||
|
// initial timeout for uTP SYN packets
|
||||||
|
int utp_connect_timeout;
|
||||||
|
|
||||||
|
// number of milliseconds of delaying ACKing packets the most
|
||||||
|
int utp_delayed_ack;
|
||||||
|
|
||||||
|
// set to true if the uTP socket buffer size is allowed to increase
|
||||||
|
// dynamically based on the NIC MTU setting. This is true by default
|
||||||
|
// and improves uTP performance for networks with larger frame sizes
|
||||||
|
// including loopback
|
||||||
|
bool utp_dynamic_sock_buf;
|
||||||
|
|
||||||
|
enum bandwidth_mixed_algo_t
|
||||||
|
{
|
||||||
|
// disables the mixed mode bandwidth balancing
|
||||||
|
prefer_tcp = 0,
|
||||||
|
|
||||||
|
// does not throttle uTP, throttles TCP to the same proportion
|
||||||
|
// of throughput as there are TCP connections
|
||||||
|
peer_proportional = 1
|
||||||
|
|
||||||
|
};
|
||||||
|
// the algorithm to use to balance bandwidth between tcp
|
||||||
|
// connections and uTP connections
|
||||||
|
int mixed_mode_algorithm;
|
||||||
|
|
||||||
|
// set to true if uTP connections should be rate limited
|
||||||
|
// defaults to false
|
||||||
|
bool rate_limit_utp;
|
||||||
|
|
||||||
// this is the number passed in to listen(). i.e.
|
// this is the number passed in to listen(). i.e.
|
||||||
// the number of connections to accept while we're
|
// the number of connections to accept while we're
|
||||||
// not waiting in an accept() call.
|
// not waiting in an accept() call.
|
||||||
@ -915,7 +1000,9 @@ namespace libtorrent
|
|||||||
dht_settings()
|
dht_settings()
|
||||||
: max_peers_reply(100)
|
: max_peers_reply(100)
|
||||||
, search_branching(5)
|
, search_branching(5)
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
, service_port(0)
|
, service_port(0)
|
||||||
|
#endif
|
||||||
, max_fail_count(20)
|
, max_fail_count(20)
|
||||||
, max_torrent_search_reply(20)
|
, max_torrent_search_reply(20)
|
||||||
{}
|
{}
|
||||||
@ -928,9 +1015,11 @@ namespace libtorrent
|
|||||||
// searching the DHT.
|
// searching the DHT.
|
||||||
int search_branching;
|
int search_branching;
|
||||||
|
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
// the listen port for the dht. This is a UDP port.
|
// the listen port for the dht. This is a UDP port.
|
||||||
// zero means use the same as the tcp interface
|
// zero means use the same as the tcp interface
|
||||||
int service_port;
|
int service_port;
|
||||||
|
#endif
|
||||||
|
|
||||||
// the maximum number of times a node can fail
|
// the maximum number of times a node can fail
|
||||||
// in a row before it is removed from the table.
|
// in a row before it is removed from the table.
|
||||||
|
@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
#include "libtorrent/size_type.hpp"
|
#include "libtorrent/size_type.hpp"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
@ -53,6 +54,15 @@ namespace libtorrent
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct utp_status
|
||||||
|
{
|
||||||
|
int num_idle;
|
||||||
|
int num_syn_sent;
|
||||||
|
int num_connected;
|
||||||
|
int num_fin_sent;
|
||||||
|
int num_close_wait;
|
||||||
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT session_status
|
struct TORRENT_EXPORT session_status
|
||||||
{
|
{
|
||||||
bool has_incoming_connections;
|
bool has_incoming_connections;
|
||||||
@ -107,6 +117,8 @@ namespace libtorrent
|
|||||||
int dht_total_allocations;
|
int dht_total_allocations;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
utp_status utp_stats;
|
||||||
|
|
||||||
int peerlist_size;
|
int peerlist_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,6 +30,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef TORRENT_SLIDING_AVERAGE_HPP_INCLUDED
|
||||||
|
#define TORRENT_SLIDING_AVERAGE_HPP_INCLUDED
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
// a sliding average accumulator. Add samples to it and it
|
// a sliding average accumulator. Add samples to it and it
|
||||||
@ -70,3 +73,5 @@ private:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@ -146,6 +146,40 @@ namespace libtorrent
|
|||||||
size_t size(Protocol const&) const { return sizeof(m_value); }
|
size_t size(Protocol const&) const { return sizeof(m_value); }
|
||||||
char m_value;
|
char m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined IP_DONTFRAG || defined IP_MTU_DISCOVER || defined IP_DONTFRAGMENT
|
||||||
|
#define TORRENT_HAS_DONT_FRAGMENT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TORRENT_HAS_DONT_FRAGMENT
|
||||||
|
struct dont_fragment
|
||||||
|
{
|
||||||
|
dont_fragment(bool val)
|
||||||
|
#ifdef IP_PMTUDISCOVER_DO
|
||||||
|
: m_value(val ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT) {}
|
||||||
|
#else
|
||||||
|
: m_value(val) {}
|
||||||
|
#endif
|
||||||
|
template<class Protocol>
|
||||||
|
int level(Protocol const&) const { return IPPROTO_IP; }
|
||||||
|
template<class Protocol>
|
||||||
|
int name(Protocol const&) const
|
||||||
|
#if defined IP_DONTFRAG
|
||||||
|
{ return IP_DONTFRAG; }
|
||||||
|
#elif defined IP_MTU_DISCOVER
|
||||||
|
{ return IP_MTU_DISCOVER; }
|
||||||
|
#elif defined IP_DONTFRAGMENT
|
||||||
|
{ return IP_DONTFRAGMENT; }
|
||||||
|
#else
|
||||||
|
{}
|
||||||
|
#endif
|
||||||
|
template<class Protocol>
|
||||||
|
int const* data(Protocol const&) const { return &m_value; }
|
||||||
|
template<class Protocol>
|
||||||
|
size_t size(Protocol const&) const { return sizeof(m_value); }
|
||||||
|
int m_value;
|
||||||
|
};
|
||||||
|
#endif // TORRENT_HAS_DONT_FRAGMENT
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TORRENT_SOCKET_HPP_INCLUDED
|
#endif // TORRENT_SOCKET_HPP_INCLUDED
|
||||||
|
@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "libtorrent/socks5_stream.hpp"
|
#include "libtorrent/socks5_stream.hpp"
|
||||||
#include "libtorrent/http_stream.hpp"
|
#include "libtorrent/http_stream.hpp"
|
||||||
#include "libtorrent/i2p_stream.hpp"
|
#include "libtorrent/i2p_stream.hpp"
|
||||||
|
#include "libtorrent/utp_stream.hpp"
|
||||||
#include "libtorrent/io_service.hpp"
|
#include "libtorrent/io_service.hpp"
|
||||||
#include "libtorrent/max.hpp"
|
#include "libtorrent/max.hpp"
|
||||||
#include "libtorrent/assert.hpp"
|
#include "libtorrent/assert.hpp"
|
||||||
@ -96,6 +97,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
get<socks5_stream>()->x; break; \
|
get<socks5_stream>()->x; break; \
|
||||||
case socket_type_int_impl<http_stream>::value: \
|
case socket_type_int_impl<http_stream>::value: \
|
||||||
get<http_stream>()->x; break; \
|
get<http_stream>()->x; break; \
|
||||||
|
case socket_type_int_impl<utp_stream>::value: \
|
||||||
|
get<utp_stream>()->x; break; \
|
||||||
TORRENT_SOCKTYPE_I2P_FORWARD(x) \
|
TORRENT_SOCKTYPE_I2P_FORWARD(x) \
|
||||||
TORRENT_SOCKTYPE_SSL_FORWARD(x) \
|
TORRENT_SOCKTYPE_SSL_FORWARD(x) \
|
||||||
default: TORRENT_ASSERT(false); \
|
default: TORRENT_ASSERT(false); \
|
||||||
@ -109,6 +112,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
return get<socks5_stream>()->x; \
|
return get<socks5_stream>()->x; \
|
||||||
case socket_type_int_impl<http_stream>::value: \
|
case socket_type_int_impl<http_stream>::value: \
|
||||||
return get<http_stream>()->x; \
|
return get<http_stream>()->x; \
|
||||||
|
case socket_type_int_impl<utp_stream>::value: \
|
||||||
|
return get<utp_stream>()->x; \
|
||||||
TORRENT_SOCKTYPE_I2P_FORWARD_RET(x, def) \
|
TORRENT_SOCKTYPE_I2P_FORWARD_RET(x, def) \
|
||||||
TORRENT_SOCKTYPE_SSL_FORWARD_RET(x, def) \
|
TORRENT_SOCKTYPE_SSL_FORWARD_RET(x, def) \
|
||||||
default: TORRENT_ASSERT(false); return def; \
|
default: TORRENT_ASSERT(false); return def; \
|
||||||
@ -133,36 +138,38 @@ namespace libtorrent
|
|||||||
struct socket_type_int_impl<http_stream>
|
struct socket_type_int_impl<http_stream>
|
||||||
{ enum { value = 3 }; };
|
{ enum { value = 3 }; };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct socket_type_int_impl<utp_stream>
|
||||||
|
{ enum { value = 4 }; };
|
||||||
|
|
||||||
#if TORRENT_USE_I2P
|
#if TORRENT_USE_I2P
|
||||||
template <>
|
template <>
|
||||||
struct socket_type_int_impl<i2p_stream>
|
struct socket_type_int_impl<i2p_stream>
|
||||||
{ enum { value = 4 }; };
|
{ enum { value = 5 }; };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TORRENT_USE_OPENSSL
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
template <>
|
template <>
|
||||||
struct socket_type_int_impl<ssl_stream<stream_socket> >
|
struct socket_type_int_impl<ssl_stream<stream_socket> >
|
||||||
{ enum { value = 5 }; };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct socket_type_int_impl<ssl_stream<socks5_stream> >
|
|
||||||
{ enum { value = 6 }; };
|
{ enum { value = 6 }; };
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct socket_type_int_impl<ssl_stream<http_stream> >
|
struct socket_type_int_impl<ssl_stream<socks5_stream> >
|
||||||
{ enum { value = 7 }; };
|
{ enum { value = 7 }; };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct socket_type_int_impl<ssl_stream<http_stream> >
|
||||||
|
{ enum { value = 8 }; };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct TORRENT_EXPORT socket_type
|
struct TORRENT_EXPORT socket_type
|
||||||
{
|
{
|
||||||
typedef stream_socket::lowest_layer_type lowest_layer_type;
|
|
||||||
typedef stream_socket::endpoint_type endpoint_type;
|
typedef stream_socket::endpoint_type endpoint_type;
|
||||||
typedef stream_socket::protocol_type protocol_type;
|
typedef stream_socket::protocol_type protocol_type;
|
||||||
|
|
||||||
explicit socket_type(io_service& ios): m_io_service(ios), m_type(0) {}
|
explicit socket_type(io_service& ios): m_io_service(ios), m_type(0) {}
|
||||||
~socket_type();
|
~socket_type();
|
||||||
|
|
||||||
lowest_layer_type& lowest_layer();
|
|
||||||
io_service& get_io_service() const;
|
io_service& get_io_service() const;
|
||||||
bool is_open() const;
|
bool is_open() const;
|
||||||
|
|
||||||
@ -253,10 +260,11 @@ namespace libtorrent
|
|||||||
|
|
||||||
io_service& m_io_service;
|
io_service& m_io_service;
|
||||||
int m_type;
|
int m_type;
|
||||||
enum { storage_size = max7<
|
enum { storage_size = max8<
|
||||||
sizeof(stream_socket)
|
sizeof(stream_socket)
|
||||||
, sizeof(socks5_stream)
|
, sizeof(socks5_stream)
|
||||||
, sizeof(http_stream)
|
, sizeof(http_stream)
|
||||||
|
, sizeof(utp_stream)
|
||||||
#if TORRENT_USE_I2P
|
#if TORRENT_USE_I2P
|
||||||
, sizeof(i2p_stream)
|
, sizeof(i2p_stream)
|
||||||
#else
|
#else
|
||||||
|
80
include/libtorrent/timestamp_history.hpp
Normal file
80
include/libtorrent/timestamp_history.hpp
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2009, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TIMESTAMP_HISTORY_HPP
|
||||||
|
#define TIMESTAMP_HISTORY_HPP
|
||||||
|
|
||||||
|
#include "boost/cstdint.hpp"
|
||||||
|
#include "libtorrent/assert.hpp"
|
||||||
|
|
||||||
|
namespace libtorrent {
|
||||||
|
|
||||||
|
// timestamp history keeps a history of the lowest timestamps we've
|
||||||
|
// seen in the last 20 minutes
|
||||||
|
struct timestamp_history
|
||||||
|
{
|
||||||
|
enum { history_size = 20 };
|
||||||
|
|
||||||
|
timestamp_history() : m_index(0), m_initialized(false), m_base(0), m_num_samples(0) {}
|
||||||
|
bool initialized() const { return m_initialized; }
|
||||||
|
|
||||||
|
// add a sample to the timestamp history. If step is true, it's been
|
||||||
|
// a minute since the last step
|
||||||
|
boost::uint32_t add_sample(boost::uint32_t sample, bool step);
|
||||||
|
boost::uint32_t base() const { TORRENT_ASSERT(m_initialized); return m_base; }
|
||||||
|
void adjust_base(int change);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// this is a circular buffer
|
||||||
|
boost::uint32_t m_history[history_size];
|
||||||
|
|
||||||
|
// and this is the index we're currently at
|
||||||
|
// in the circular buffer
|
||||||
|
boost::uint16_t m_index;
|
||||||
|
|
||||||
|
bool m_initialized:1;
|
||||||
|
|
||||||
|
// this is the lowest sample seen in the
|
||||||
|
// last 'history_size' minutes
|
||||||
|
boost::uint32_t m_base;
|
||||||
|
|
||||||
|
// this is the number of samples since the
|
||||||
|
// last time we stepped one minute. If we
|
||||||
|
// don't have enough samples, we won't step
|
||||||
|
int m_num_samples;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -91,6 +91,7 @@ namespace libtorrent
|
|||||||
struct tracker_request;
|
struct tracker_request;
|
||||||
struct add_torrent_params;
|
struct add_torrent_params;
|
||||||
struct storage_interface;
|
struct storage_interface;
|
||||||
|
struct bt_peer_connection;
|
||||||
|
|
||||||
namespace aux
|
namespace aux
|
||||||
{
|
{
|
||||||
@ -136,6 +137,15 @@ namespace libtorrent
|
|||||||
// it will initialize the storage and the piece-picker
|
// it will initialize the storage and the piece-picker
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
|
// find the peer that introduced us to the given endpoint. This is
|
||||||
|
// used when trying to holepunch. We need the introducer so that we
|
||||||
|
// can send a rendezvous connect message
|
||||||
|
bt_peer_connection* find_introducer(tcp::endpoint const& ep) const;
|
||||||
|
|
||||||
|
// if we're connected to a peer at ep, return its peer connection
|
||||||
|
// only count BitTorrent peers
|
||||||
|
bt_peer_connection* find_peer(tcp::endpoint const& ep) const;
|
||||||
|
|
||||||
void on_resume_data_checked(int ret, disk_io_job const& j);
|
void on_resume_data_checked(int ret, disk_io_job const& j);
|
||||||
void on_force_recheck(int ret, disk_io_job const& j);
|
void on_force_recheck(int ret, disk_io_job const& j);
|
||||||
void on_piece_checked(int ret, disk_io_job const& j);
|
void on_piece_checked(int ret, disk_io_job const& j);
|
||||||
@ -291,7 +301,7 @@ namespace libtorrent
|
|||||||
tcp::endpoint get_interface() const;
|
tcp::endpoint get_interface() const;
|
||||||
|
|
||||||
void connect_to_url_seed(std::list<web_seed_entry>::iterator url);
|
void connect_to_url_seed(std::list<web_seed_entry>::iterator url);
|
||||||
bool connect_to_peer(policy::peer* peerinfo);
|
bool connect_to_peer(policy::peer* peerinfo, bool ignore_limit = false);
|
||||||
|
|
||||||
void set_ratio(float r)
|
void set_ratio(float r)
|
||||||
{ TORRENT_ASSERT(r >= 0.0f); m_ratio = r; }
|
{ TORRENT_ASSERT(r >= 0.0f); m_ratio = r; }
|
||||||
|
@ -82,13 +82,31 @@ namespace libtorrent
|
|||||||
proxy_settings const& get_proxy_settings() { return m_proxy_settings; }
|
proxy_settings const& get_proxy_settings() { return m_proxy_settings; }
|
||||||
|
|
||||||
bool is_closed() const { return m_abort; }
|
bool is_closed() const { return m_abort; }
|
||||||
tcp::endpoint local_endpoint() const
|
tcp::endpoint local_endpoint(error_code& ec) const
|
||||||
{
|
{
|
||||||
error_code ec;
|
|
||||||
udp::endpoint ep = m_ipv4_sock.local_endpoint(ec);
|
udp::endpoint ep = m_ipv4_sock.local_endpoint(ec);
|
||||||
return tcp::endpoint(ep.address(), ep.port());
|
return tcp::endpoint(ep.address(), ep.port());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_buf_size(int s);
|
||||||
|
|
||||||
|
template <class SocketOption>
|
||||||
|
void set_option(SocketOption const& opt, error_code& ec)
|
||||||
|
{
|
||||||
|
m_ipv4_sock.set_option(opt, ec);
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
m_ipv6_sock.set_option(opt, ec);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class SocketOption>
|
||||||
|
void get_option(SocketOption& opt, error_code& ec)
|
||||||
|
{
|
||||||
|
m_ipv4_sock.get_option(opt, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
udp::endpoint proxy_addr() const { return m_proxy_addr; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
struct queued_packet
|
struct queued_packet
|
||||||
@ -129,6 +147,8 @@ namespace libtorrent
|
|||||||
void wrap(char const* hostname, int port, char const* p, int len, error_code& ec);
|
void wrap(char const* hostname, int port, char const* p, int len, error_code& ec);
|
||||||
void unwrap(error_code const& e, char const* buf, int size);
|
void unwrap(error_code const& e, char const* buf, int size);
|
||||||
|
|
||||||
|
void maybe_realloc_buffers();
|
||||||
|
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
#if defined BOOST_HAS_PTHREADS
|
#if defined BOOST_HAS_PTHREADS
|
||||||
mutable pthread_t m_thread;
|
mutable pthread_t m_thread;
|
||||||
@ -146,12 +166,14 @@ namespace libtorrent
|
|||||||
|
|
||||||
udp::socket m_ipv4_sock;
|
udp::socket m_ipv4_sock;
|
||||||
udp::endpoint m_v4_ep;
|
udp::endpoint m_v4_ep;
|
||||||
char m_v4_buf[1600];
|
int m_v4_buf_size;
|
||||||
|
char* m_v4_buf;
|
||||||
|
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
udp::socket m_ipv6_sock;
|
udp::socket m_ipv6_sock;
|
||||||
udp::endpoint m_v6_ep;
|
udp::endpoint m_v6_ep;
|
||||||
char m_v6_buf[1600];
|
int m_v6_buf_size;
|
||||||
|
char* m_v6_buf;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int m_bind_port;
|
int m_bind_port;
|
||||||
@ -166,6 +188,11 @@ namespace libtorrent
|
|||||||
bool m_queue_packets;
|
bool m_queue_packets;
|
||||||
bool m_tunnel_packets;
|
bool m_tunnel_packets;
|
||||||
bool m_abort;
|
bool m_abort;
|
||||||
|
// this is set to true to indicate that the m_v4_buf
|
||||||
|
// and m_v6_buf should be reallocated to the size
|
||||||
|
// of the buffer size members the next time their
|
||||||
|
// read handler gets triggered
|
||||||
|
bool m_reallocate_buffers;
|
||||||
udp::endpoint m_proxy_addr;
|
udp::endpoint m_proxy_addr;
|
||||||
// while we're connecting to the proxy
|
// while we're connecting to the proxy
|
||||||
// we have to queue the packets, we'll flush
|
// we have to queue the packets, we'll flush
|
||||||
|
116
include/libtorrent/utp_socket_manager.hpp
Normal file
116
include/libtorrent/utp_socket_manager.hpp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2009, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TORRENT_UTP_SOCKET_MANAGER_HPP_INCLUDED
|
||||||
|
#define TORRENT_UTP_SOCKET_MANAGER_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "libtorrent/socket_type.hpp"
|
||||||
|
#include "libtorrent/session_status.hpp"
|
||||||
|
#include "libtorrent/enum_net.hpp"
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
class udp_socket;
|
||||||
|
class utp_stream;
|
||||||
|
struct utp_socket_impl;
|
||||||
|
|
||||||
|
typedef boost::function<void(boost::shared_ptr<socket_type> const&)> incoming_utp_callback_t;
|
||||||
|
|
||||||
|
struct utp_socket_manager
|
||||||
|
{
|
||||||
|
utp_socket_manager(session_settings const& sett, udp_socket& s, incoming_utp_callback_t cb);
|
||||||
|
~utp_socket_manager();
|
||||||
|
|
||||||
|
void get_status(utp_status& s) const;
|
||||||
|
|
||||||
|
// return false if this is not a uTP packet
|
||||||
|
bool incoming_packet(char const* p, int size, udp::endpoint const& ep);
|
||||||
|
|
||||||
|
void tick(ptime now);
|
||||||
|
|
||||||
|
tcp::endpoint local_endpoint(error_code& ec) const;
|
||||||
|
|
||||||
|
// flags for send_packet
|
||||||
|
enum { dont_fragment = 1 };
|
||||||
|
void send_packet(udp::endpoint const& ep, char const* p, int len
|
||||||
|
, error_code& ec, int flags = 0);
|
||||||
|
|
||||||
|
// internal, used by utp_stream
|
||||||
|
void remove_socket(boost::uint16_t id);
|
||||||
|
|
||||||
|
utp_socket_impl* new_utp_socket(utp_stream* str);
|
||||||
|
int gain_factor() const { return m_sett.utp_gain_factor; }
|
||||||
|
int target_delay() const { return m_sett.utp_target_delay * 1000; }
|
||||||
|
int syn_resends() const { return m_sett.utp_syn_resends; }
|
||||||
|
int fin_resends() const { return m_sett.utp_fin_resends; }
|
||||||
|
int num_resends() const { return m_sett.utp_num_resends; }
|
||||||
|
int connect_timeout() const { return m_sett.utp_connect_timeout; }
|
||||||
|
int delayed_ack() const { return m_sett.utp_delayed_ack; }
|
||||||
|
int min_timeout() const { return m_sett.utp_min_timeout; }
|
||||||
|
bool allow_dynamic_sock_buf() const { return m_sett.utp_dynamic_sock_buf; }
|
||||||
|
|
||||||
|
void mtu_for_dest(address const& addr, int& link_mtu, int& utp_mtu);
|
||||||
|
void set_sock_buf(int size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
udp_socket& m_sock;
|
||||||
|
incoming_utp_callback_t m_cb;
|
||||||
|
|
||||||
|
// replace with a hash-map
|
||||||
|
typedef std::multimap<boost::uint16_t, utp_socket_impl*> socket_map_t;
|
||||||
|
socket_map_t m_utp_sockets;
|
||||||
|
|
||||||
|
// the last socket we received a packet on
|
||||||
|
utp_socket_impl* m_last_socket;
|
||||||
|
|
||||||
|
int m_new_connection;
|
||||||
|
|
||||||
|
session_settings const& m_sett;
|
||||||
|
|
||||||
|
// this is a copy of the routing table, used
|
||||||
|
// to initialize MTU sizes of uTP sockets
|
||||||
|
std::vector<ip_route> m_routes;
|
||||||
|
|
||||||
|
// the timestamp for the last time we updated
|
||||||
|
// the routing table
|
||||||
|
ptime m_last_route_update;
|
||||||
|
|
||||||
|
// the buffer size of the socket. This is used
|
||||||
|
// to now lower the buffer size
|
||||||
|
int m_sock_buf_size;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
386
include/libtorrent/utp_stream.hpp
Normal file
386
include/libtorrent/utp_stream.hpp
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2009, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TORRENT_UTP_STREAM_HPP_INCLUDED
|
||||||
|
#define TORRENT_UTP_STREAM_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include "libtorrent/connection_queue.hpp"
|
||||||
|
#include "libtorrent/proxy_base.hpp"
|
||||||
|
#include "libtorrent/udp_socket.hpp"
|
||||||
|
#include "libtorrent/io.hpp"
|
||||||
|
#include "libtorrent/packet_buffer.hpp"
|
||||||
|
#include "libtorrent/error_code.hpp"
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/function/function1.hpp>
|
||||||
|
#include <boost/function/function2.hpp>
|
||||||
|
|
||||||
|
#define CCONTROL_TARGET 100
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
struct utp_socket_manager;
|
||||||
|
|
||||||
|
// some MTU and protocol header sizes constants
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TORRENT_IPV4_HEADER = 20,
|
||||||
|
TORRENT_IPV6_HEADER = 40,
|
||||||
|
TORRENT_UDP_HEADER = 8,
|
||||||
|
TORRENT_SOCKS5_HEADER = 6, // plus the size of the destination address
|
||||||
|
|
||||||
|
TORRENT_ETHERNET_MTU = 1500,
|
||||||
|
TORRENT_TEREDO_MTU = 1280,
|
||||||
|
TORRENT_INET_MIN_MTU = 576,
|
||||||
|
TORRENT_INET_MAX_MTU = 0xffff
|
||||||
|
};
|
||||||
|
|
||||||
|
// the point of the bif_endian_int is two-fold
|
||||||
|
// one purpuse is to not have any alignment requirements
|
||||||
|
// so that any byffer received from the network can be cast
|
||||||
|
// to it and read as an integer of various sizes without
|
||||||
|
// triggering a bus error. The other purpose is to convert
|
||||||
|
// from network byte order to host byte order when read and
|
||||||
|
// written, to offer a convenient interface to both interpreting
|
||||||
|
// and writing network packets
|
||||||
|
template <class T> struct big_endian_int
|
||||||
|
{
|
||||||
|
big_endian_int& operator=(T v)
|
||||||
|
{
|
||||||
|
char* p = m_storage;
|
||||||
|
detail::write_impl(v, p);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
operator T() const
|
||||||
|
{
|
||||||
|
const char* p = m_storage;
|
||||||
|
return detail::read_impl(p, detail::type<T>());
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
char m_storage[sizeof(T)];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef big_endian_int<boost::uint64_t> be_uint64;
|
||||||
|
typedef big_endian_int<boost::uint32_t> be_uint32;
|
||||||
|
typedef big_endian_int<boost::uint16_t> be_uint16;
|
||||||
|
typedef big_endian_int<boost::int64_t> be_int64;
|
||||||
|
typedef big_endian_int<boost::int32_t> be_int32;
|
||||||
|
typedef big_endian_int<boost::int16_t> be_int16;
|
||||||
|
|
||||||
|
/*
|
||||||
|
uTP header from BEP 29
|
||||||
|
|
||||||
|
0 4 8 16 24 32
|
||||||
|
+-------+-------+---------------+---------------+---------------+
|
||||||
|
| type | ver | extension | connection_id |
|
||||||
|
+-------+-------+---------------+---------------+---------------+
|
||||||
|
| timestamp_microseconds |
|
||||||
|
+---------------+---------------+---------------+---------------+
|
||||||
|
| timestamp_difference_microseconds |
|
||||||
|
+---------------+---------------+---------------+---------------+
|
||||||
|
| wnd_size |
|
||||||
|
+---------------+---------------+---------------+---------------+
|
||||||
|
| seq_nr | ack_nr |
|
||||||
|
+---------------+---------------+---------------+---------------+
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum type { ST_DATA = 0, ST_FIN, ST_STATE, ST_RESET, ST_SYN, NUM_TYPES };
|
||||||
|
|
||||||
|
struct utp_header
|
||||||
|
{
|
||||||
|
unsigned char type_ver;
|
||||||
|
unsigned char extension;
|
||||||
|
be_uint16 connection_id;
|
||||||
|
be_uint32 timestamp_microseconds;
|
||||||
|
be_uint32 timestamp_difference_microseconds;
|
||||||
|
be_uint32 wnd_size;
|
||||||
|
be_uint16 seq_nr;
|
||||||
|
be_uint16 ack_nr;
|
||||||
|
|
||||||
|
int get_type() const { return type_ver >> 4; }
|
||||||
|
int get_version() const { return type_ver & 0xf; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct utp_socket_impl;
|
||||||
|
|
||||||
|
utp_socket_impl* construct_utp_impl(boost::uint16_t recv_id
|
||||||
|
, boost::uint16_t send_id, void* userdata
|
||||||
|
, utp_socket_manager* sm);
|
||||||
|
void detach_utp_impl(utp_socket_impl* s);
|
||||||
|
void delete_utp_impl(utp_socket_impl* s);
|
||||||
|
bool should_delete(utp_socket_impl* s);
|
||||||
|
void tick_utp_impl(utp_socket_impl* s, ptime const& now);
|
||||||
|
void utp_init_mtu(utp_socket_impl* s, int link_mtu, int utp_mtu);
|
||||||
|
bool utp_incoming_packet(utp_socket_impl* s, char const* p
|
||||||
|
, int size, udp::endpoint const& ep, ptime receive_time);
|
||||||
|
bool utp_match(utp_socket_impl* s, udp::endpoint const& ep, boost::uint16_t id);
|
||||||
|
udp::endpoint utp_remote_endpoint(utp_socket_impl* s);
|
||||||
|
boost::uint16_t utp_receive_id(utp_socket_impl* s);
|
||||||
|
int utp_socket_state(utp_socket_impl const* s);
|
||||||
|
|
||||||
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||||
|
int socket_impl_size();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// this is the user-level stream interface to utp sockets.
|
||||||
|
// the reason why it's split up in a utp_stream class and
|
||||||
|
// an implementation class is because the socket state has
|
||||||
|
// to be able to out-live the user level socket. For instance
|
||||||
|
// when sending data on a stream and then closing it, the
|
||||||
|
// state holding the send buffer has to be kept around until
|
||||||
|
// it has been flushed, which may be longer than the client
|
||||||
|
// will keep the utp_stream object around for.
|
||||||
|
// for more details, see utp_socket_impl, which is analogous
|
||||||
|
// to the kernel state for a socket. It's defined in utp_stream.cpp
|
||||||
|
class utp_stream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef stream_socket::endpoint_type endpoint_type;
|
||||||
|
typedef stream_socket::protocol_type protocol_type;
|
||||||
|
|
||||||
|
explicit utp_stream(asio::io_service& io_service);
|
||||||
|
~utp_stream();
|
||||||
|
|
||||||
|
// used for incoming connections
|
||||||
|
void set_impl(utp_socket_impl* s);
|
||||||
|
utp_socket_impl* get_impl();
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
template <class IO_Control_Command>
|
||||||
|
void io_control(IO_Control_Command& ioc) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class IO_Control_Command>
|
||||||
|
void io_control(IO_Control_Command& ioc, error_code& ec) {}
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
void bind(endpoint_type const& endpoint) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void bind(endpoint_type const& endpoint, error_code& ec);
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
template <class SettableSocketOption>
|
||||||
|
void set_option(SettableSocketOption const& opt) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class SettableSocketOption>
|
||||||
|
error_code set_option(SettableSocketOption const& opt, error_code& ec) { return ec; }
|
||||||
|
|
||||||
|
void close();
|
||||||
|
void close(error_code const& ec) { close(); }
|
||||||
|
bool is_open() const { return m_open; }
|
||||||
|
|
||||||
|
int read_buffer_size() const;
|
||||||
|
static void on_read(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
|
||||||
|
static void on_write(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
|
||||||
|
static void on_connect(void* self, error_code const& ec, bool kill);
|
||||||
|
|
||||||
|
typedef void(*handler_t)(void*, size_t, error_code const&, bool);
|
||||||
|
typedef void(*connect_handler_t)(void*, error_code const&, bool);
|
||||||
|
|
||||||
|
void add_read_buffer(void* buf, size_t len);
|
||||||
|
void set_read_handler(handler_t h);
|
||||||
|
void add_write_buffer(void const* buf, size_t len);
|
||||||
|
void set_write_handler(handler_t h);
|
||||||
|
size_t read_some(bool clear_buffers);
|
||||||
|
|
||||||
|
void do_connect(tcp::endpoint const& ep, connect_handler_t h);
|
||||||
|
|
||||||
|
endpoint_type local_endpoint() const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
return local_endpoint(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint_type local_endpoint(error_code& ec) const;
|
||||||
|
|
||||||
|
endpoint_type remote_endpoint() const
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
return remote_endpoint(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint_type remote_endpoint(error_code& ec) const;
|
||||||
|
|
||||||
|
std::size_t available() const;
|
||||||
|
std::size_t available(error_code& ec) const { return available(); }
|
||||||
|
|
||||||
|
asio::io_service& io_service()
|
||||||
|
{ return m_io_service; }
|
||||||
|
|
||||||
|
template <class Handler>
|
||||||
|
void async_connect(endpoint_type const& endpoint, Handler const& handler)
|
||||||
|
{
|
||||||
|
if (!endpoint.address().is_v4())
|
||||||
|
{
|
||||||
|
error_code ec = asio::error::operation_not_supported;
|
||||||
|
m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_impl == 0)
|
||||||
|
{
|
||||||
|
m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_connect_handler = handler;
|
||||||
|
do_connect(endpoint, &utp_stream::on_connect);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Mutable_Buffers, class Handler>
|
||||||
|
void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
|
||||||
|
{
|
||||||
|
if (m_impl == 0)
|
||||||
|
{
|
||||||
|
m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TORRENT_ASSERT(!m_read_handler);
|
||||||
|
if (m_read_handler)
|
||||||
|
{
|
||||||
|
m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (typename Mutable_Buffers::const_iterator i = buffers.begin()
|
||||||
|
, end(buffers.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(buffer_size(*i) > 0);
|
||||||
|
using asio::buffer_cast;
|
||||||
|
using asio::buffer_size;
|
||||||
|
add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
|
||||||
|
}
|
||||||
|
m_read_handler = handler;
|
||||||
|
set_read_handler(&utp_stream::on_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_async_connect(endpoint_type const& ep
|
||||||
|
, boost::function<void(error_code const&)> const& handler);
|
||||||
|
|
||||||
|
template <class Protocol>
|
||||||
|
void open(Protocol const& p, error_code& ec)
|
||||||
|
{ m_open = true; }
|
||||||
|
|
||||||
|
template <class Protocol>
|
||||||
|
void open(Protocol const& p)
|
||||||
|
{ m_open = true; }
|
||||||
|
|
||||||
|
template <class Mutable_Buffers>
|
||||||
|
std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(!m_read_handler);
|
||||||
|
if (m_impl == 0)
|
||||||
|
{
|
||||||
|
ec = asio::error::not_connected;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read_buffer_size() == 0)
|
||||||
|
{
|
||||||
|
ec = asio::error::would_block;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
int buf_size = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (typename Mutable_Buffers::const_iterator i = buffers.begin()
|
||||||
|
, end(buffers.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
using asio::buffer_cast;
|
||||||
|
using asio::buffer_size;
|
||||||
|
add_read_buffer(buffer_cast<void*>(*i), buffer_size(*i));
|
||||||
|
#ifdef TORRENT_DEBUG
|
||||||
|
buf_size += buffer_size(*i);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
std::size_t ret = read_some(true);
|
||||||
|
TORRENT_ASSERT(int(ret) <= buf_size);
|
||||||
|
TORRENT_ASSERT(ret > 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Const_Buffers>
|
||||||
|
std::size_t write_some(Const_Buffers const& buffers, error_code& ec)
|
||||||
|
{
|
||||||
|
// TODO: implement
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Const_Buffers, class Handler>
|
||||||
|
void async_write_some(Const_Buffers const& buffers, Handler const& handler)
|
||||||
|
{
|
||||||
|
if (m_impl == 0)
|
||||||
|
{
|
||||||
|
m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TORRENT_ASSERT(!m_write_handler);
|
||||||
|
if (m_write_handler)
|
||||||
|
{
|
||||||
|
m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (typename Const_Buffers::const_iterator i = buffers.begin()
|
||||||
|
, end(buffers.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(buffer_size(*i) > 0);
|
||||||
|
using asio::buffer_cast;
|
||||||
|
using asio::buffer_size;
|
||||||
|
add_write_buffer((void*)buffer_cast<void const*>(*i), buffer_size(*i));
|
||||||
|
}
|
||||||
|
m_write_handler = handler;
|
||||||
|
set_write_handler(&utp_stream::on_write);
|
||||||
|
}
|
||||||
|
|
||||||
|
//private:
|
||||||
|
|
||||||
|
void cancel_handlers(error_code const&);
|
||||||
|
|
||||||
|
boost::function1<void, error_code const&> m_connect_handler;
|
||||||
|
boost::function2<void, error_code const&, std::size_t> m_read_handler;
|
||||||
|
boost::function2<void, error_code const&, std::size_t> m_write_handler;
|
||||||
|
|
||||||
|
asio::io_service& m_io_service;
|
||||||
|
utp_socket_impl* m_impl;
|
||||||
|
bool m_open;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -83,6 +83,12 @@ for l in f:
|
|||||||
if 'std::string::append' in fun: fold = indentation
|
if 'std::string::append' in fun: fold = indentation
|
||||||
if 'getipnodebyname' == fun: fold = indentation
|
if 'getipnodebyname' == fun: fold = indentation
|
||||||
if '__gnu_debug::_Safe_iterator<std::' in fun: fold = indentation
|
if '__gnu_debug::_Safe_iterator<std::' in fun: fold = indentation
|
||||||
|
if 'fflush' == fun: fold = indentation
|
||||||
|
if 'vfprintf' == fun: fold = indentation
|
||||||
|
if 'fprintf' == fun: fold = indentation
|
||||||
|
if 'BN_mod_exp' == fun: fold = indentation
|
||||||
|
if 'BN_CTX_free' == fun: fold = indentation
|
||||||
|
if 'cerror' == fun: fold = indentation
|
||||||
|
|
||||||
list = []
|
list = []
|
||||||
for k in fun_samples:
|
for k in fun_samples:
|
||||||
|
@ -38,6 +38,8 @@ substitute_file('docs/manual.rst')
|
|||||||
substitute_file('docs/building.rst')
|
substitute_file('docs/building.rst')
|
||||||
substitute_file('docs/features.rst')
|
substitute_file('docs/features.rst')
|
||||||
substitute_file('docs/contributing.rst')
|
substitute_file('docs/contributing.rst')
|
||||||
|
substitute_file('docs/utp.rst')
|
||||||
|
substitute_file('docs/make_torrent.rst')
|
||||||
substitute_file('docs/tuning.rst')
|
substitute_file('docs/tuning.rst')
|
||||||
substitute_file('Jamfile')
|
substitute_file('Jamfile')
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ libtorrent_rasterbar_la_SOURCES = \
|
|||||||
pe_crypto.cpp \
|
pe_crypto.cpp \
|
||||||
peer_connection.cpp \
|
peer_connection.cpp \
|
||||||
piece_picker.cpp \
|
piece_picker.cpp \
|
||||||
|
packet_buffer.cpp \
|
||||||
policy.cpp \
|
policy.cpp \
|
||||||
puff.cpp \
|
puff.cpp \
|
||||||
session.cpp \
|
session.cpp \
|
||||||
@ -76,12 +77,15 @@ libtorrent_rasterbar_la_SOURCES = \
|
|||||||
torrent_handle.cpp \
|
torrent_handle.cpp \
|
||||||
torrent_info.cpp \
|
torrent_info.cpp \
|
||||||
time.cpp \
|
time.cpp \
|
||||||
|
timestamp_history.cpp \
|
||||||
tracker_manager.cpp \
|
tracker_manager.cpp \
|
||||||
udp_socket.cpp \
|
udp_socket.cpp \
|
||||||
udp_tracker_connection.cpp \
|
udp_tracker_connection.cpp \
|
||||||
upnp.cpp \
|
upnp.cpp \
|
||||||
ut_metadata.cpp \
|
ut_metadata.cpp \
|
||||||
ut_pex.cpp \
|
ut_pex.cpp \
|
||||||
|
utp_socket_manager.cpp \
|
||||||
|
utp_stream.cpp \
|
||||||
web_peer_connection.cpp \
|
web_peer_connection.cpp \
|
||||||
\
|
\
|
||||||
$(KADEMLIA_SOURCES) \
|
$(KADEMLIA_SOURCES) \
|
||||||
|
@ -108,6 +108,18 @@ namespace libtorrent
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TORRENT_EXPORT bool is_teredo(address const& addr)
|
||||||
|
{
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
if (!addr.is_v6()) return false;
|
||||||
|
boost::uint8_t teredo_prefix[] = {0x20, 0x01, 0, 0};
|
||||||
|
address_v6::bytes_type b = addr.to_v6().to_bytes();
|
||||||
|
return memcmp(&b[0], teredo_prefix, 4) == 0;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool supports_ipv6()
|
bool supports_ipv6()
|
||||||
{
|
{
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
|
@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "libtorrent/alert_types.hpp"
|
#include "libtorrent/alert_types.hpp"
|
||||||
#include "libtorrent/invariant_check.hpp"
|
#include "libtorrent/invariant_check.hpp"
|
||||||
#include "libtorrent/io.hpp"
|
#include "libtorrent/io.hpp"
|
||||||
|
#include "libtorrent/socket_io.hpp"
|
||||||
#include "libtorrent/version.hpp"
|
#include "libtorrent/version.hpp"
|
||||||
#include "libtorrent/extensions.hpp"
|
#include "libtorrent/extensions.hpp"
|
||||||
#include "libtorrent/aux_/session_impl.hpp"
|
#include "libtorrent/aux_/session_impl.hpp"
|
||||||
@ -258,7 +259,7 @@ namespace libtorrent
|
|||||||
write_bitfield();
|
write_bitfield();
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
if (m_supports_dht_port && m_ses.m_dht)
|
if (m_supports_dht_port && m_ses.m_dht)
|
||||||
write_dht_port(m_ses.get_dht_settings().service_port);
|
write_dht_port(m_ses.m_external_udp_port);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,8 +391,9 @@ namespace libtorrent
|
|||||||
if (is_queued()) p.flags |= peer_info::queued;
|
if (is_queued()) p.flags |= peer_info::queued;
|
||||||
|
|
||||||
p.client = m_client_version;
|
p.client = m_client_version;
|
||||||
p.connection_type = peer_info::standard_bittorrent;
|
p.connection_type = get_socket()->get<utp_stream>()
|
||||||
|
? peer_info::bittorrent_utp
|
||||||
|
: peer_info::standard_bittorrent;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bt_peer_connection::in_handshake() const
|
bool bt_peer_connection::in_handshake() const
|
||||||
@ -657,6 +659,7 @@ namespace libtorrent
|
|||||||
|
|
||||||
void bt_peer_connection::append_const_send_buffer(char const* buffer, int size)
|
void bt_peer_connection::append_const_send_buffer(char const* buffer, int size)
|
||||||
{
|
{
|
||||||
|
TORRENT_ASSERT(!m_rc4_encrypted || send_buffer_size() == m_encrypted_bytes);
|
||||||
// if we're encrypting this buffer, we need to make a copy
|
// if we're encrypting this buffer, we need to make a copy
|
||||||
// since we'll mutate it
|
// since we'll mutate it
|
||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
@ -1349,7 +1352,7 @@ namespace libtorrent
|
|||||||
m_supports_dht_port = true;
|
m_supports_dht_port = true;
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
if (m_supports_dht_port && m_ses.m_dht)
|
if (m_supports_dht_port && m_ses.m_dht)
|
||||||
write_dht_port(m_ses.get_dht_settings().service_port);
|
write_dht_port(m_ses.m_external_udp_port);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1443,6 +1446,203 @@ namespace libtorrent
|
|||||||
incoming_allowed_fast(index);
|
incoming_allowed_fast(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------
|
||||||
|
// -------- RENDEZVOUS ---------
|
||||||
|
// -----------------------------
|
||||||
|
|
||||||
|
void bt_peer_connection::on_holepunch()
|
||||||
|
{
|
||||||
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
if (!packet_finished()) return;
|
||||||
|
|
||||||
|
// we can't accept holepunch messages from peers
|
||||||
|
// that don't support the holepunch extension
|
||||||
|
// because we wouldn't be able to respond
|
||||||
|
if (m_holepunch_id == 0) return;
|
||||||
|
|
||||||
|
buffer::const_interval recv_buffer = receive_buffer();
|
||||||
|
TORRENT_ASSERT(*recv_buffer.begin == msg_extended);
|
||||||
|
++recv_buffer.begin;
|
||||||
|
TORRENT_ASSERT(*recv_buffer.begin == holepunch_msg);
|
||||||
|
++recv_buffer.begin;
|
||||||
|
|
||||||
|
const char* ptr = recv_buffer.begin;
|
||||||
|
|
||||||
|
// ignore invalid messages
|
||||||
|
if (recv_buffer.left() < 2) return;
|
||||||
|
|
||||||
|
int msg_type = detail::read_uint8(ptr);
|
||||||
|
int addr_type = detail::read_uint8(ptr);
|
||||||
|
|
||||||
|
tcp::endpoint ep;
|
||||||
|
|
||||||
|
if (addr_type == 0)
|
||||||
|
{
|
||||||
|
if (recv_buffer.left() < 2 + 4 + 2) return;
|
||||||
|
// IPv4 address
|
||||||
|
ep = detail::read_v4_endpoint<tcp::endpoint>(ptr);
|
||||||
|
}
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
else if (addr_type == 1)
|
||||||
|
{
|
||||||
|
// IPv6 address
|
||||||
|
if (recv_buffer.left() < 2 + 18 + 2) return;
|
||||||
|
ep = detail::read_v6_endpoint<tcp::endpoint>(ptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||||
|
error_code ec;
|
||||||
|
static const char* hp_msg_name[] = {"rendezvous", "connect", "failed"};
|
||||||
|
(*m_logger) << time_now_string() << " <== HOLEPUNCH [ msg:"
|
||||||
|
<< (msg_type >= 0 && msg_type < 3 ? hp_msg_name[msg_type] : "unknown message type")
|
||||||
|
<< " from:" << remote().address().to_string(ec)
|
||||||
|
<< " to: unknown address type ]\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return; // unknown address type
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
||||||
|
if (!t) return;
|
||||||
|
|
||||||
|
switch (msg_type)
|
||||||
|
{
|
||||||
|
case hp_rendezvous: // rendezvous
|
||||||
|
{
|
||||||
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||||
|
error_code ec;
|
||||||
|
(*m_logger) << time_now_string() << " <== HOLEPUNCH [ msg:rendezvous"
|
||||||
|
<< " to:" << ep.address().to_string(ec) << " ]\n";
|
||||||
|
#endif
|
||||||
|
// this peer is asking us to introduce it to
|
||||||
|
// the peer at 'ep'. We need to find which of
|
||||||
|
// our connections points to that endpoint
|
||||||
|
bt_peer_connection* p = t->find_peer(ep);
|
||||||
|
if (p == 0)
|
||||||
|
{
|
||||||
|
// we're not connected to this peer
|
||||||
|
write_holepunch_msg(hp_failed, ep, hp_not_connected);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!p->supports_holepunch())
|
||||||
|
{
|
||||||
|
write_holepunch_msg(hp_failed, ep, hp_no_support);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p == this)
|
||||||
|
{
|
||||||
|
write_holepunch_msg(hp_failed, ep, hp_no_self);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_holepunch_msg(hp_connect, ep, 0);
|
||||||
|
p->write_holepunch_msg(hp_connect, remote(), 0);
|
||||||
|
} break;
|
||||||
|
case hp_connect:
|
||||||
|
{
|
||||||
|
// add or find the peer with this endpoint
|
||||||
|
policy::peer* p = t->get_policy().add_peer(ep, peer_id(0), peer_info::pex, 0);
|
||||||
|
if (p == 0 || p->connection)
|
||||||
|
{
|
||||||
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||||
|
error_code ec;
|
||||||
|
(*m_logger) << time_now_string() << " <== HOLEPUNCH [ msg:connect"
|
||||||
|
<< " to:" << ep.address().to_string(ec) << " error:failed to add peer ]\n";
|
||||||
|
#endif
|
||||||
|
// we either couldn't add this peer, or it's
|
||||||
|
// already connected. Just ignore the connect message
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p->banned)
|
||||||
|
{
|
||||||
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||||
|
error_code ec;
|
||||||
|
(*m_logger) << time_now_string() << " <== HOLEPUNCH [ msg:connect"
|
||||||
|
<< " to:" << ep.address().to_string(ec) << " error:peer banned ]\n";
|
||||||
|
#endif
|
||||||
|
// this peer is banned, don't connect to it
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
// to make sure we use the uTP protocol
|
||||||
|
p->supports_utp = true;
|
||||||
|
// #error make sure we make this a connection candidate
|
||||||
|
// in case it has too many failures for instance
|
||||||
|
t->connect_to_peer(p, true);
|
||||||
|
// mark this connection to be in holepunch mode
|
||||||
|
// so that it will retry faster and stick to uTP while it's
|
||||||
|
// retrying
|
||||||
|
if (p->connection)
|
||||||
|
p->connection->set_holepunch_mode();
|
||||||
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||||
|
error_code ec;
|
||||||
|
(*m_logger) << time_now_string() << " <== HOLEPUNCH [ msg:connect"
|
||||||
|
<< " to:" << ep.address().to_string(ec) << " ]\n";
|
||||||
|
#endif
|
||||||
|
} break;
|
||||||
|
case hp_failed:
|
||||||
|
{
|
||||||
|
boost::uint32_t error = detail::read_uint32(ptr);
|
||||||
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||||
|
error_code ec;
|
||||||
|
char const* err_msg[] = {"no such peer", "not connected", "no support", "no self"};
|
||||||
|
(*m_logger) << time_now_string() << " <== HOLEPUNCH [ msg:failed"
|
||||||
|
" error:" << error <<
|
||||||
|
" msg:" << ((error >= 0 && error < 4)?err_msg[error]:"unknown message id") <<
|
||||||
|
" ]\n";
|
||||||
|
#endif
|
||||||
|
// #error deal with holepunch errors
|
||||||
|
} break;
|
||||||
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
(*m_logger) << time_now_string() << " <== HOLEPUNCH ["
|
||||||
|
" msg:unknown message type (" << msg_type << ")"
|
||||||
|
<< " to:" << ep.address().to_string(ec) << " ]\n";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_peer_connection::write_holepunch_msg(int type, tcp::endpoint const& ep, int error)
|
||||||
|
{
|
||||||
|
char buf[35];
|
||||||
|
char* ptr = buf + 6;
|
||||||
|
detail::write_uint8(type, ptr);
|
||||||
|
if (ep.address().is_v4()) detail::write_uint8(0, ptr);
|
||||||
|
else detail::write_uint8(1, ptr);
|
||||||
|
detail::write_endpoint(ep, ptr);
|
||||||
|
|
||||||
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||||
|
error_code ec;
|
||||||
|
static const char* hp_msg_name[] = {"rendezvous", "connect", "failed"};
|
||||||
|
static const char* hp_error_string[] = {"", "no such peer", "not connected", "no support", "no self"};
|
||||||
|
(*m_logger) << time_now_string() << " ==> HOLEPUNCH [ msg:"
|
||||||
|
<< (type >= 0 && type < 3 ? hp_msg_name[type] : "unknown message type")
|
||||||
|
<< " to:" << ep.address().to_string(ec)
|
||||||
|
<< " error:" << hp_error_string[error]
|
||||||
|
<< " ]\n";
|
||||||
|
#endif
|
||||||
|
if (type == hp_failed)
|
||||||
|
{
|
||||||
|
detail::write_uint32(error, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the packet length and type
|
||||||
|
char* hdr = buf;
|
||||||
|
detail::write_uint32(ptr - buf - 4, hdr);
|
||||||
|
detail::write_uint8(msg_extended, hdr);
|
||||||
|
detail::write_uint8(m_holepunch_id, hdr);
|
||||||
|
|
||||||
|
TORRENT_ASSERT(ptr <= buf + sizeof(buf));
|
||||||
|
|
||||||
|
send_buffer(buf, ptr - buf);
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// --------- EXTENDED ----------
|
// --------- EXTENDED ----------
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
@ -1479,6 +1679,31 @@ namespace libtorrent
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (extended_id == upload_only_msg)
|
||||||
|
{
|
||||||
|
if (!packet_finished()) return;
|
||||||
|
bool ul = detail::read_uint8(recv_buffer.begin);
|
||||||
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
(*m_logger) << time_now_string() << " <== UPLOAD_ONLY [ " << (ul?"true":"false") << " ]\n";
|
||||||
|
#endif
|
||||||
|
set_upload_only(ul);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extended_id == holepunch_msg)
|
||||||
|
{
|
||||||
|
if (!packet_finished()) return;
|
||||||
|
on_holepunch();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
if (packet_finished())
|
||||||
|
(*m_logger) << time_now_string() << " <== EXTENSION MESSAGE ["
|
||||||
|
" msg:" << extended_id <<
|
||||||
|
" size:" << packet_size() << " ]\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
for (extension_list_t::iterator i = m_extensions.begin()
|
for (extension_list_t::iterator i = m_extensions.begin()
|
||||||
, end(m_extensions.end()); i != end; ++i)
|
, end(m_extensions.end()); i != end; ++i)
|
||||||
@ -1549,7 +1774,10 @@ namespace libtorrent
|
|||||||
|
|
||||||
// upload_only
|
// upload_only
|
||||||
if (lazy_entry const* m = root.dict_find_dict("m"))
|
if (lazy_entry const* m = root.dict_find_dict("m"))
|
||||||
|
{
|
||||||
m_upload_only_id = m->dict_find_int_value("upload_only", 0);
|
m_upload_only_id = m->dict_find_int_value("upload_only", 0);
|
||||||
|
m_holepunch_id = m->dict_find_int_value("ut_holepunch", 0);
|
||||||
|
}
|
||||||
|
|
||||||
// there is supposed to be a remote listen port
|
// there is supposed to be a remote listen port
|
||||||
int listen_port = root.dict_find_int_value("p");
|
int listen_port = root.dict_find_int_value("p");
|
||||||
@ -1929,7 +2157,9 @@ namespace libtorrent
|
|||||||
TORRENT_ASSERT(t);
|
TORRENT_ASSERT(t);
|
||||||
|
|
||||||
m["upload_only"] = upload_only_msg;
|
m["upload_only"] = upload_only_msg;
|
||||||
|
m["ut_holepunch"] = holepunch_msg;
|
||||||
m["share_mode"] = share_mode_msg;
|
m["share_mode"] = share_mode_msg;
|
||||||
|
|
||||||
int complete_ago = -1;
|
int complete_ago = -1;
|
||||||
if (t->last_seen_complete() > 0) complete_ago = t->time_since_complete();
|
if (t->last_seen_complete() > 0) complete_ago = t->time_since_complete();
|
||||||
handshake["complete_ago"] = complete_ago;
|
handshake["complete_ago"] = complete_ago;
|
||||||
@ -1968,6 +2198,19 @@ namespace libtorrent
|
|||||||
(*i)->add_handshake(handshake);
|
(*i)->add_handshake(handshake);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// make sure there are not conflicting extensions
|
||||||
|
std::set<int> ext;
|
||||||
|
for (entry::dictionary_type::const_iterator i = m.begin()
|
||||||
|
, end(m.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
if (i->second.type() != entry::int_t) continue;
|
||||||
|
int val = i->second.integer();
|
||||||
|
TORRENT_ASSERT(ext.find(val) == ext.end());
|
||||||
|
ext.insert(val);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
std::vector<char> msg;
|
std::vector<char> msg;
|
||||||
bencode(std::back_inserter(msg), handshake);
|
bencode(std::back_inserter(msg), handshake);
|
||||||
|
|
||||||
@ -1986,9 +2229,9 @@ namespace libtorrent
|
|||||||
TORRENT_ASSERT(i.begin == i.end);
|
TORRENT_ASSERT(i.begin == i.end);
|
||||||
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING && TORRENT_USE_IOSTREAM
|
#if defined TORRENT_VERBOSE_LOGGING && TORRENT_USE_IOSTREAM
|
||||||
std::stringstream ext;
|
std::stringstream handshake_str;
|
||||||
handshake.print(ext);
|
handshake.print(handshake_str);
|
||||||
(*m_logger) << time_now_string() << " ==> EXTENDED HANDSHAKE: \n" << ext.str();
|
(*m_logger) << time_now_string() << " ==> EXTENDED HANDSHAKE: \n" << handshake_str.str();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
setup_send();
|
setup_send();
|
||||||
@ -2198,6 +2441,8 @@ namespace libtorrent
|
|||||||
(*m_logger) << time_now_string() << " received DH key\n";
|
(*m_logger) << time_now_string() << " received DH key\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TORRENT_ASSERT(!m_rc4_encrypted || send_buffer_size() == m_encrypted_bytes);
|
||||||
|
|
||||||
// PadA/B can be a max of 512 bytes, and 20 bytes more for
|
// PadA/B can be a max of 512 bytes, and 20 bytes more for
|
||||||
// the sync hash (if incoming), or 8 bytes more for the
|
// the sync hash (if incoming), or 8 bytes more for the
|
||||||
// encrypted verification constant (if outgoing). Instead
|
// encrypted verification constant (if outgoing). Instead
|
||||||
@ -2981,7 +3226,7 @@ namespace libtorrent
|
|||||||
write_bitfield();
|
write_bitfield();
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
if (m_supports_dht_port && m_ses.m_dht)
|
if (m_supports_dht_port && m_ses.m_dht)
|
||||||
write_dht_port(m_ses.get_dht_settings().service_port);
|
write_dht_port(m_ses.m_external_udp_port);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
368
src/enum_net.cpp
368
src/enum_net.cpp
@ -33,6 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "libtorrent/config.hpp"
|
#include "libtorrent/config.hpp"
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <stdlib.h> // for wcstombscstombs
|
||||||
#include "libtorrent/enum_net.hpp"
|
#include "libtorrent/enum_net.hpp"
|
||||||
#include "libtorrent/broadcast_socket.hpp"
|
#include "libtorrent/broadcast_socket.hpp"
|
||||||
#include "libtorrent/error_code.hpp"
|
#include "libtorrent/error_code.hpp"
|
||||||
@ -84,31 +85,44 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
namespace libtorrent { namespace
|
namespace libtorrent { namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
address inaddr_to_address(in_addr const* ina)
|
address inaddr_to_address(in_addr const* ina, int len = 4)
|
||||||
{
|
{
|
||||||
typedef asio::ip::address_v4::bytes_type bytes_t;
|
typedef asio::ip::address_v4::bytes_type bytes_t;
|
||||||
bytes_t b;
|
bytes_t b;
|
||||||
std::memcpy(&b[0], ina, b.size());
|
std::memset(&b[0], 0, b.size());
|
||||||
|
if (len > 0) std::memcpy(&b[0], ina, (std::min)(len, int(b.size())));
|
||||||
return address_v4(b);
|
return address_v4(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
address inaddr6_to_address(in6_addr const* ina6)
|
address inaddr6_to_address(in6_addr const* ina6, int len = 16)
|
||||||
{
|
{
|
||||||
typedef asio::ip::address_v6::bytes_type bytes_t;
|
typedef asio::ip::address_v6::bytes_type bytes_t;
|
||||||
bytes_t b;
|
bytes_t b;
|
||||||
std::memcpy(&b[0], ina6, b.size());
|
std::memset(&b[0], 0, b.size());
|
||||||
|
if (len > 0) std::memcpy(&b[0], ina6, (std::min)(len, int(b.size())));
|
||||||
return address_v6(b);
|
return address_v6(b);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
address sockaddr_to_address(sockaddr const* sin)
|
int sockaddr_len(sockaddr const* sin)
|
||||||
{
|
{
|
||||||
if (sin->sa_family == AF_INET)
|
#if defined TORRENT_WINDOWS || TORRENT_MINGW || defined TORRENT_LINUX
|
||||||
return inaddr_to_address(&((sockaddr_in const*)sin)->sin_addr);
|
return sin->sa_family == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
|
||||||
|
#else
|
||||||
|
return sin->sa_len;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
address sockaddr_to_address(sockaddr const* sin, int assume_family = -1)
|
||||||
|
{
|
||||||
|
if (sin->sa_family == AF_INET || assume_family == AF_INET)
|
||||||
|
return inaddr_to_address(&((sockaddr_in const*)sin)->sin_addr
|
||||||
|
, sockaddr_len(sin) - offsetof(sockaddr, sa_data));
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
else if (sin->sa_family == AF_INET6)
|
else if (sin->sa_family == AF_INET6 || assume_family == AF_INET6)
|
||||||
return inaddr6_to_address(&((sockaddr_in6 const*)sin)->sin6_addr);
|
return inaddr6_to_address(&((sockaddr_in6 const*)sin)->sin6_addr
|
||||||
|
, sockaddr_len(sin) - offsetof(sockaddr, sa_data));
|
||||||
#endif
|
#endif
|
||||||
return address();
|
return address();
|
||||||
}
|
}
|
||||||
@ -142,13 +156,15 @@ namespace libtorrent { namespace
|
|||||||
return msg_len;
|
return msg_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_route(nlmsghdr* nl_hdr, ip_route* rt_info)
|
bool parse_route(int s, nlmsghdr* nl_hdr, ip_route* rt_info)
|
||||||
{
|
{
|
||||||
rtmsg* rt_msg = (rtmsg*)NLMSG_DATA(nl_hdr);
|
rtmsg* rt_msg = (rtmsg*)NLMSG_DATA(nl_hdr);
|
||||||
|
|
||||||
if((rt_msg->rtm_family != AF_INET) || (rt_msg->rtm_table != RT_TABLE_MAIN))
|
if((rt_msg->rtm_family != AF_INET && rt_msg->rtm_family != AF_INET6) || (rt_msg->rtm_table != RT_TABLE_MAIN
|
||||||
|
&& rt_msg->rtm_table != RT_TABLE_LOCAL))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
int if_index = 0;
|
||||||
int rt_len = RTM_PAYLOAD(nl_hdr);
|
int rt_len = RTM_PAYLOAD(nl_hdr);
|
||||||
for (rtattr* rt_attr = (rtattr*)RTM_RTA(rt_msg);
|
for (rtattr* rt_attr = (rtattr*)RTM_RTA(rt_msg);
|
||||||
RTA_OK(rt_attr,rt_len); rt_attr = RTA_NEXT(rt_attr,rt_len))
|
RTA_OK(rt_attr,rt_len); rt_attr = RTA_NEXT(rt_attr,rt_len))
|
||||||
@ -156,23 +172,52 @@ namespace libtorrent { namespace
|
|||||||
switch(rt_attr->rta_type)
|
switch(rt_attr->rta_type)
|
||||||
{
|
{
|
||||||
case RTA_OIF:
|
case RTA_OIF:
|
||||||
if_indextoname(*(int*)RTA_DATA(rt_attr), rt_info->name);
|
if_index = *(int*)RTA_DATA(rt_attr);
|
||||||
break;
|
break;
|
||||||
case RTA_GATEWAY:
|
case RTA_GATEWAY:
|
||||||
rt_info->gateway = address_v4(ntohl(*(u_int*)RTA_DATA(rt_attr)));
|
#if TORRENT_USE_IPV6
|
||||||
|
if (rt_msg->rtm_family == AF_INET6)
|
||||||
|
{
|
||||||
|
rt_info->gateway = inaddr6_to_address((in6_addr*)RTA_DATA(rt_attr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
rt_info->gateway = inaddr_to_address((in_addr*)RTA_DATA(rt_attr));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case RTA_DST:
|
case RTA_DST:
|
||||||
rt_info->destination = address_v4(ntohl(*(u_int*)RTA_DATA(rt_attr)));
|
#if TORRENT_USE_IPV6
|
||||||
|
if (rt_msg->rtm_family == AF_INET6)
|
||||||
|
{
|
||||||
|
rt_info->destination = inaddr6_to_address((in6_addr*)RTA_DATA(rt_attr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
rt_info->destination = inaddr_to_address((in_addr*)RTA_DATA(rt_attr));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if_indextoname(if_index, rt_info->name);
|
||||||
|
ifreq req;
|
||||||
|
memset(&req, 0, sizeof(req));
|
||||||
|
if_indextoname(if_index, req.ifr_name);
|
||||||
|
ioctl(s, SIOCGIFMTU, &req);
|
||||||
|
rt_info->mtu = req.ifr_mtu;
|
||||||
|
// obviously this doesn't work correctly. How do you get the netmask for a route?
|
||||||
|
// if (ioctl(s, SIOCGIFNETMASK, &req) == 0) {
|
||||||
|
// rt_info->netmask = sockaddr_to_address(&req.ifr_addr, req.ifr_addr.sa_family);
|
||||||
|
// }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined TORRENT_BSD
|
#if defined TORRENT_BSD
|
||||||
|
|
||||||
bool parse_route(rt_msghdr* rtm, ip_route* rt_info)
|
bool parse_route(int s, rt_msghdr* rtm, ip_route* rt_info)
|
||||||
{
|
{
|
||||||
sockaddr* rti_info[RTAX_MAX];
|
sockaddr* rti_info[RTAX_MAX];
|
||||||
sockaddr* sa = (sockaddr*)(rtm + 1);
|
sockaddr* sa = (sockaddr*)(rtm + 1);
|
||||||
@ -205,9 +250,17 @@ namespace libtorrent { namespace
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
rt_info->gateway = sockaddr_to_address(rti_info[RTAX_GATEWAY]);
|
rt_info->gateway = sockaddr_to_address(rti_info[RTAX_GATEWAY]);
|
||||||
rt_info->netmask = sockaddr_to_address(rti_info[RTAX_NETMASK]);
|
|
||||||
rt_info->destination = sockaddr_to_address(rti_info[RTAX_DST]);
|
rt_info->destination = sockaddr_to_address(rti_info[RTAX_DST]);
|
||||||
|
rt_info->netmask = sockaddr_to_address(rti_info[RTAX_NETMASK]
|
||||||
|
, rt_info->destination.is_v4() ? AF_INET : AF_INET6);
|
||||||
if_indextoname(rtm->rtm_index, rt_info->name);
|
if_indextoname(rtm->rtm_index, rt_info->name);
|
||||||
|
|
||||||
|
ifreq req;
|
||||||
|
memset(&req, 0, sizeof(req));
|
||||||
|
if_indextoname(rtm->rtm_index, req.ifr_name);
|
||||||
|
if (ioctl(s, SIOCGIFMTU, &req) < 0) return false;
|
||||||
|
rt_info->mtu = req.ifr_mtu;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -231,17 +284,29 @@ namespace libtorrent { namespace
|
|||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
bool in_subnet(address const& addr, ip_interface const& iface)
|
// return (a1 & mask) == (a2 & mask)
|
||||||
|
bool match_addr_mask(address const& a1, address const& a2, address const& mask)
|
||||||
{
|
{
|
||||||
if (addr.is_v4() != iface.interface_address.is_v4()) return false;
|
// all 3 addresses needs to belong to the same family
|
||||||
// since netmasks seems unreliable for IPv6 interfaces
|
if (a1.is_v4() != a2.is_v4()) return false;
|
||||||
// (MacOS X returns AF_INET addresses as bitmasks) assume
|
if (a1.is_v4() != mask.is_v4()) return false;
|
||||||
// that any IPv6 address belongs to the subnet of any
|
|
||||||
// interface with an IPv6 address
|
|
||||||
if (addr.is_v6()) return true;
|
|
||||||
|
|
||||||
return (addr.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong())
|
#if TORRENT_USE_IPV6
|
||||||
== (iface.interface_address.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong());
|
if (a1.is_v6())
|
||||||
|
{
|
||||||
|
address_v6::bytes_type b1;
|
||||||
|
address_v6::bytes_type b2;
|
||||||
|
address_v6::bytes_type m;
|
||||||
|
b1 = a1.to_v6().to_bytes();
|
||||||
|
b2 = a2.to_v6().to_bytes();
|
||||||
|
m = mask.to_v6().to_bytes();
|
||||||
|
for (int i = 0; i < b1.size(); ++i)
|
||||||
|
b1[i] &= m[i];
|
||||||
|
return memcmp(&b1[0], &b2[0], b1.size());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return (a1.to_v4().to_ulong() & mask.to_v4().to_ulong())
|
||||||
|
== (a2.to_v4().to_ulong() & mask.to_v4().to_ulong());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool in_local_network(io_service& ios, address const& addr, error_code& ec)
|
bool in_local_network(io_service& ios, address const& addr, error_code& ec)
|
||||||
@ -251,10 +316,56 @@ namespace libtorrent
|
|||||||
for (std::vector<ip_interface>::iterator i = net.begin()
|
for (std::vector<ip_interface>::iterator i = net.begin()
|
||||||
, end(net.end()); i != end; ++i)
|
, end(net.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
if (in_subnet(addr, *i)) return true;
|
if (match_addr_mask(addr, i->interface_address, i->netmask)) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined TORRENT_WINDOWS || defined TORRENT_MINGW
|
||||||
|
address build_netmask(int bits, int family)
|
||||||
|
{
|
||||||
|
if (family == AF_INET)
|
||||||
|
{
|
||||||
|
typedef asio::ip::address_v4::bytes_type bytes_t;
|
||||||
|
bytes_t b;
|
||||||
|
std::memset(&b[0], 0xff, b.size());
|
||||||
|
for (int i = sizeof(bytes_t)/8-1; i > 0; --i)
|
||||||
|
{
|
||||||
|
if (bits < 8)
|
||||||
|
{
|
||||||
|
b[i] <<= bits;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
b[i] = 0;
|
||||||
|
bits -= 8;
|
||||||
|
}
|
||||||
|
return address_v4(b);
|
||||||
|
}
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
else if (family == AF_INET6)
|
||||||
|
{
|
||||||
|
typedef asio::ip::address_v6::bytes_type bytes_t;
|
||||||
|
bytes_t b;
|
||||||
|
std::memset(&b[0], 0xff, b.size());
|
||||||
|
for (int i = sizeof(bytes_t)/8-1; i > 0; --i)
|
||||||
|
{
|
||||||
|
if (bits < 8)
|
||||||
|
{
|
||||||
|
b[i] <<= bits;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
b[i] = 0;
|
||||||
|
bits -= 8;
|
||||||
|
}
|
||||||
|
return address_v6(b);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return address();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
std::vector<ip_interface> enum_net_interfaces(io_service& ios, error_code& ec)
|
std::vector<ip_interface> enum_net_interfaces(io_service& ios, error_code& ec)
|
||||||
{
|
{
|
||||||
@ -295,8 +406,20 @@ namespace libtorrent
|
|||||||
iface.interface_address = sockaddr_to_address(&item.ifr_addr);
|
iface.interface_address = sockaddr_to_address(&item.ifr_addr);
|
||||||
strcpy(iface.name, item.ifr_name);
|
strcpy(iface.name, item.ifr_name);
|
||||||
|
|
||||||
ifreq netmask = item;
|
ifreq req;
|
||||||
if (ioctl(s, SIOCGIFNETMASK, &netmask) < 0)
|
memset(&req, 0, sizeof(req));
|
||||||
|
strncpy(req.ifr_name, item.ifr_name, IF_NAMESIZE);
|
||||||
|
if (ioctl(s, SIOCGIFMTU, &req) < 0)
|
||||||
|
{
|
||||||
|
ec = error_code(errno, asio::error::system_category);
|
||||||
|
close(s);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
iface.mtu = req.ifr_mtu;
|
||||||
|
|
||||||
|
memset(&req, 0, sizeof(req));
|
||||||
|
strncpy(req.ifr_name, item.ifr_name, IF_NAMESIZE);
|
||||||
|
if (ioctl(s, SIOCGIFNETMASK, &req) < 0)
|
||||||
{
|
{
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
if (iface.interface_address.is_v6())
|
if (iface.interface_address.is_v6())
|
||||||
@ -314,7 +437,7 @@ namespace libtorrent
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iface.netmask = sockaddr_to_address(&netmask.ifr_addr);
|
iface.netmask = sockaddr_to_address(&req.ifr_addr, item.ifr_addr.sa_family);
|
||||||
}
|
}
|
||||||
ret.push_back(iface);
|
ret.push_back(iface);
|
||||||
}
|
}
|
||||||
@ -331,6 +454,65 @@ namespace libtorrent
|
|||||||
|
|
||||||
#elif defined TORRENT_WINDOWS || defined TORRENT_MINGW
|
#elif defined TORRENT_WINDOWS || defined TORRENT_MINGW
|
||||||
|
|
||||||
|
// Load Iphlpapi library
|
||||||
|
HMODULE iphlp = LoadLibraryA("Iphlpapi.dll");
|
||||||
|
if (iphlp)
|
||||||
|
{
|
||||||
|
// Get GetAdaptersAddresses() pointer
|
||||||
|
typedef ULONG (WINAPI *GetAdaptersAddresses_t)(ULONG,ULONG,PVOID,PIP_ADAPTER_ADDRESSES,PULONG);
|
||||||
|
GetAdaptersAddresses_t GetAdaptersAddresses = (GetAdaptersAddresses_t)GetProcAddress(
|
||||||
|
iphlp, "GetAdaptersAddresses");
|
||||||
|
|
||||||
|
if (GetAdaptersAddresses)
|
||||||
|
{
|
||||||
|
PIP_ADAPTER_ADDRESSES adapter_addresses = 0;
|
||||||
|
ULONG out_buf_size = 0;
|
||||||
|
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER
|
||||||
|
| GAA_FLAG_SKIP_ANYCAST, NULL, adapter_addresses, &out_buf_size) != ERROR_BUFFER_OVERFLOW)
|
||||||
|
{
|
||||||
|
FreeLibrary(iphlp);
|
||||||
|
ec = asio::error::operation_not_supported;
|
||||||
|
return std::vector<ip_interface>();
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter_addresses = (IP_ADAPTER_ADDRESSES*)malloc(out_buf_size);
|
||||||
|
if (!adapter_addresses)
|
||||||
|
{
|
||||||
|
FreeLibrary(iphlp);
|
||||||
|
ec = asio::error::no_memory;
|
||||||
|
return std::vector<ip_interface>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER
|
||||||
|
| GAA_FLAG_SKIP_ANYCAST, NULL, adapter_addresses, &out_buf_size) == NO_ERROR)
|
||||||
|
{
|
||||||
|
for (PIP_ADAPTER_ADDRESSES adapter = adapter_addresses;
|
||||||
|
adapter != 0; adapter = adapter->Next)
|
||||||
|
{
|
||||||
|
ip_interface r;
|
||||||
|
strncpy(r.name, adapter->AdapterName, sizeof(r.name));
|
||||||
|
r.name[sizeof(r.name)-1] = 0;
|
||||||
|
r.mtu = adapter->Mtu;
|
||||||
|
IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress;
|
||||||
|
while (unicast)
|
||||||
|
{
|
||||||
|
r.interface_address = sockaddr_to_address(unicast->Address.lpSockaddr);
|
||||||
|
|
||||||
|
ret.push_back(r);
|
||||||
|
|
||||||
|
unicast = unicast->Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free memory
|
||||||
|
free(adapter_addresses);
|
||||||
|
FreeLibrary(iphlp);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
FreeLibrary(iphlp);
|
||||||
|
}
|
||||||
|
|
||||||
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
|
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
if (s == SOCKET_ERROR)
|
if (s == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
@ -356,9 +538,11 @@ namespace libtorrent
|
|||||||
for (int i = 0; i < n; ++i)
|
for (int i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
iface.interface_address = sockaddr_to_address(&buffer[i].iiAddress.Address);
|
iface.interface_address = sockaddr_to_address(&buffer[i].iiAddress.Address);
|
||||||
iface.netmask = sockaddr_to_address(&buffer[i].iiNetmask.Address);
|
|
||||||
iface.name[0] = 0;
|
|
||||||
if (iface.interface_address == address_v4::any()) continue;
|
if (iface.interface_address == address_v4::any()) continue;
|
||||||
|
iface.netmask = sockaddr_to_address(&buffer[i].iiNetmask.Address
|
||||||
|
, iface.interface_address.is_v4() ? AF_INET : AF_INET6);
|
||||||
|
iface.name[0] = 0;
|
||||||
|
iface.mtu = 1500; // how to get the MTU?
|
||||||
ret.push_back(iface);
|
ret.push_back(iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,6 +556,7 @@ namespace libtorrent
|
|||||||
for (;i != udp::resolver_iterator(); ++i)
|
for (;i != udp::resolver_iterator(); ++i)
|
||||||
{
|
{
|
||||||
iface.interface_address = i->endpoint().address();
|
iface.interface_address = i->endpoint().address();
|
||||||
|
iface.mtu = 1500;
|
||||||
if (iface.interface_address.is_v4())
|
if (iface.interface_address.is_v4())
|
||||||
iface.netmask = address_v4::netmask(iface.interface_address.to_v4());
|
iface.netmask = address_v4::netmask(iface.interface_address.to_v4());
|
||||||
ret.push_back(iface);
|
ret.push_back(iface);
|
||||||
@ -528,6 +713,12 @@ namespace libtorrent
|
|||||||
|
|
||||||
char* end = buf.get() + needed;
|
char* end = buf.get() + needed;
|
||||||
|
|
||||||
|
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (s < 0)
|
||||||
|
{
|
||||||
|
ec = error_code(errno, asio::error::system_category);
|
||||||
|
return std::vector<ip_route>();
|
||||||
|
}
|
||||||
rt_msghdr* rtm;
|
rt_msghdr* rtm;
|
||||||
for (char* next = buf.get(); next < end; next += rtm->rtm_msglen)
|
for (char* next = buf.get(); next < end; next += rtm->rtm_msglen)
|
||||||
{
|
{
|
||||||
@ -536,11 +727,13 @@ namespace libtorrent
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
ip_route r;
|
ip_route r;
|
||||||
if (parse_route(rtm, &r)) ret.push_back(r);
|
if (parse_route(s, rtm, &r)) ret.push_back(r);
|
||||||
}
|
}
|
||||||
|
close(s);
|
||||||
|
|
||||||
#elif defined TORRENT_WINDOWS || defined TORRENT_MINGW
|
#elif defined TORRENT_WINDOWS || defined TORRENT_MINGW
|
||||||
|
/*
|
||||||
|
move this to enum_net_interfaces
|
||||||
// Load Iphlpapi library
|
// Load Iphlpapi library
|
||||||
HMODULE iphlp = LoadLibraryA("Iphlpapi.dll");
|
HMODULE iphlp = LoadLibraryA("Iphlpapi.dll");
|
||||||
if (!iphlp)
|
if (!iphlp)
|
||||||
@ -596,11 +789,109 @@ namespace libtorrent
|
|||||||
ret.push_back(r);
|
ret.push_back(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free memory
|
// Free memory
|
||||||
free(adapter_info);
|
free(adapter_info);
|
||||||
FreeLibrary(iphlp);
|
FreeLibrary(iphlp);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Load Iphlpapi library
|
||||||
|
HMODULE iphlp = LoadLibraryA("Iphlpapi.dll");
|
||||||
|
if (!iphlp)
|
||||||
|
{
|
||||||
|
ec = asio::error::operation_not_supported;
|
||||||
|
return std::vector<ip_route>();
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef DWORD (WINAPI *GetIpForwardTable2_t)(
|
||||||
|
ADDRESS_FAMILY, PMIB_IPFORWARD_TABLE2*);
|
||||||
|
typedef void (WINAPI *FreeMibTable_t)(PVOID Memory);
|
||||||
|
|
||||||
|
GetIpForwardTable2_t GetIpForwardTable2 = (GetIpForwardTable2_t)GetProcAddress(
|
||||||
|
iphlp, "GetIpForwardTable2");
|
||||||
|
FreeMibTable_t FreeMibTable = (FreeMibTable_t)GetProcAddress(
|
||||||
|
iphlp, "FreeMibTable");
|
||||||
|
if (GetIpForwardTable2 && FreeMibTable)
|
||||||
|
{
|
||||||
|
MIB_IPFORWARD_TABLE2* routes = NULL;
|
||||||
|
int res = GetIpForwardTable2(AF_UNSPEC, &routes);
|
||||||
|
if (res == NO_ERROR)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < routes->NumEntries; ++i)
|
||||||
|
{
|
||||||
|
ip_route r;
|
||||||
|
r.gateway = sockaddr_to_address((const sockaddr*)&routes->Table[i].NextHop);
|
||||||
|
r.destination = sockaddr_to_address(
|
||||||
|
(const sockaddr*)&routes->Table[i].DestinationPrefix.Prefix);
|
||||||
|
r.netmask = build_netmask(routes->Table[i].SitePrefixLength
|
||||||
|
, routes->Table[i].DestinationPrefix.Prefix.si_family);
|
||||||
|
MIB_IFROW ifentry;
|
||||||
|
ifentry.dwIndex = routes->Table[i].InterfaceIndex;
|
||||||
|
if (GetIfEntry(&ifentry) == NO_ERROR)
|
||||||
|
{
|
||||||
|
wcstombs(r.name, ifentry.wszName, sizeof(r.name));
|
||||||
|
r.mtu = ifentry.dwMtu;
|
||||||
|
ret.push_back(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (routes) FreeMibTable(routes);
|
||||||
|
FreeLibrary(iphlp);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get GetIpForwardTable() pointer
|
||||||
|
typedef DWORD (WINAPI *GetIpForwardTable_t)(PMIB_IPFORWARDTABLE pIpForwardTable,PULONG pdwSize,BOOL bOrder);
|
||||||
|
|
||||||
|
GetIpForwardTable_t GetIpForwardTable = (GetIpForwardTable_t)GetProcAddress(
|
||||||
|
iphlp, "GetIpForwardTable");
|
||||||
|
if (!GetIpForwardTable)
|
||||||
|
{
|
||||||
|
FreeLibrary(iphlp);
|
||||||
|
ec = asio::error::operation_not_supported;
|
||||||
|
return std::vector<ip_route>();
|
||||||
|
}
|
||||||
|
|
||||||
|
MIB_IPFORWARDTABLE* routes = NULL;
|
||||||
|
ULONG out_buf_size = 0;
|
||||||
|
if (GetIpForwardTable(routes, &out_buf_size, FALSE) != ERROR_INSUFFICIENT_BUFFER)
|
||||||
|
{
|
||||||
|
FreeLibrary(iphlp);
|
||||||
|
ec = asio::error::operation_not_supported;
|
||||||
|
return std::vector<ip_route>();
|
||||||
|
}
|
||||||
|
|
||||||
|
routes = (MIB_IPFORWARDTABLE*)malloc(out_buf_size);
|
||||||
|
if (!routes)
|
||||||
|
{
|
||||||
|
FreeLibrary(iphlp);
|
||||||
|
ec = asio::error::no_memory;
|
||||||
|
return std::vector<ip_route>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetIpForwardTable(routes, &out_buf_size, FALSE) == NO_ERROR)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < routes->dwNumEntries; ++i)
|
||||||
|
{
|
||||||
|
ip_route r;
|
||||||
|
r.destination = inaddr_to_address((in_addr const*)&routes->table[i].dwForwardDest);
|
||||||
|
r.netmask = inaddr_to_address((in_addr const*)&routes->table[i].dwForwardMask);
|
||||||
|
r.gateway = inaddr_to_address((in_addr const*)&routes->table[i].dwForwardNextHop);
|
||||||
|
MIB_IFROW ifentry;
|
||||||
|
ifentry.dwIndex = routes->table[i].dwForwardIfIndex;
|
||||||
|
if (GetIfEntry(&ifentry) == NO_ERROR)
|
||||||
|
{
|
||||||
|
wcstombs(r.name, ifentry.wszName, sizeof(r.name));
|
||||||
|
r.name[sizeof(r.name)-1] = 0;
|
||||||
|
r.mtu = ifentry.dwMtu;
|
||||||
|
ret.push_back(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free memory
|
||||||
|
free(routes);
|
||||||
|
FreeLibrary(iphlp);
|
||||||
#elif defined TORRENT_LINUX
|
#elif defined TORRENT_LINUX
|
||||||
|
|
||||||
enum { BUFSIZE = 8192 };
|
enum { BUFSIZE = 8192 };
|
||||||
@ -639,11 +930,18 @@ namespace libtorrent
|
|||||||
return std::vector<ip_route>();
|
return std::vector<ip_route>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (s < 0)
|
||||||
|
{
|
||||||
|
ec = error_code(errno, asio::error::system_category);
|
||||||
|
return std::vector<ip_route>();
|
||||||
|
}
|
||||||
for (; NLMSG_OK(nl_msg, len); nl_msg = NLMSG_NEXT(nl_msg, len))
|
for (; NLMSG_OK(nl_msg, len); nl_msg = NLMSG_NEXT(nl_msg, len))
|
||||||
{
|
{
|
||||||
ip_route r;
|
ip_route r;
|
||||||
if (parse_route(nl_msg, &r)) ret.push_back(r);
|
if (parse_route(s, nl_msg, &r)) ret.push_back(r);
|
||||||
}
|
}
|
||||||
|
close(s);
|
||||||
close(sock);
|
close(sock);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -156,7 +156,7 @@ namespace libtorrent
|
|||||||
"pex message too large",
|
"pex message too large",
|
||||||
"invalid pex message",
|
"invalid pex message",
|
||||||
"invalid lt_tracker message",
|
"invalid lt_tracker message",
|
||||||
"",
|
"pex messages sent too frequent (possible attack)",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "libtorrent/socket.hpp"
|
#include "libtorrent/socket.hpp"
|
||||||
#include "libtorrent/session_settings.hpp"
|
#include "libtorrent/session_settings.hpp"
|
||||||
#include "libtorrent/socket_type.hpp"
|
#include "libtorrent/socket_type.hpp"
|
||||||
|
#include "libtorrent/utp_socket_manager.hpp"
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
@ -43,9 +44,15 @@ namespace libtorrent
|
|||||||
|
|
||||||
bool instantiate_connection(io_service& ios
|
bool instantiate_connection(io_service& ios
|
||||||
, proxy_settings const& ps, socket_type& s
|
, proxy_settings const& ps, socket_type& s
|
||||||
, void* ssl_context)
|
, void* ssl_context
|
||||||
|
, utp_socket_manager* sm)
|
||||||
{
|
{
|
||||||
if (ps.type == proxy_settings::none)
|
if (sm)
|
||||||
|
{
|
||||||
|
s.instantiate<utp_stream>(ios);
|
||||||
|
s.get<utp_stream>()->set_impl(sm->new_utp_socket(s.get<utp_stream>()));
|
||||||
|
}
|
||||||
|
else if (ps.type == proxy_settings::none)
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_USE_OPENSSL
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
if (ssl_context)
|
if (ssl_context)
|
||||||
|
@ -248,6 +248,8 @@ namespace libtorrent { namespace
|
|||||||
, m_tp(tp)
|
, m_tp(tp)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
virtual char const* type() const { return "LT_metadata"; }
|
||||||
|
|
||||||
// can add entries to the extension handshake
|
// can add entries to the extension handshake
|
||||||
virtual void add_handshake(entry& h)
|
virtual void add_handshake(entry& h)
|
||||||
{
|
{
|
||||||
|
189
src/packet_buffer.cpp
Normal file
189
src/packet_buffer.cpp
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2010, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h> // free and calloc
|
||||||
|
#include "libtorrent/packet_buffer.hpp"
|
||||||
|
#include "libtorrent/assert.hpp"
|
||||||
|
|
||||||
|
namespace libtorrent {
|
||||||
|
|
||||||
|
bool compare_less_wrap(boost::uint32_t lhs, boost::uint32_t rhs
|
||||||
|
, boost::uint32_t mask);
|
||||||
|
|
||||||
|
packet_buffer::packet_buffer()
|
||||||
|
: m_storage(0)
|
||||||
|
, m_capacity(0)
|
||||||
|
, m_size(0)
|
||||||
|
, m_first(0)
|
||||||
|
, m_last(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
packet_buffer::~packet_buffer()
|
||||||
|
{
|
||||||
|
free(m_storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* packet_buffer::insert(index_type idx, void* value)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT_VAL(idx <= 0xffff, idx);
|
||||||
|
// you're not allowed to insert NULLs!
|
||||||
|
TORRENT_ASSERT(value);
|
||||||
|
|
||||||
|
if (m_size != 0)
|
||||||
|
{
|
||||||
|
if (compare_less_wrap(idx, m_first, 0xffff))
|
||||||
|
{
|
||||||
|
// Index comes before m_first. If we have room, we can simply
|
||||||
|
// adjust m_first backward.
|
||||||
|
|
||||||
|
std::size_t free_space = 0;
|
||||||
|
|
||||||
|
for (index_type i = (m_first - 1) & (m_capacity - 1);
|
||||||
|
i != (m_first & (m_capacity - 1)); i = (i - 1) & (m_capacity - 1))
|
||||||
|
{
|
||||||
|
if (m_storage[i & (m_capacity - 1)])
|
||||||
|
break;
|
||||||
|
++free_space;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((m_first - idx) & 0xffff) > free_space)
|
||||||
|
reserve(((m_first - idx) & 0xffff) + m_capacity - free_space);
|
||||||
|
|
||||||
|
m_first = idx;
|
||||||
|
}
|
||||||
|
else if (idx >= m_first + m_capacity)
|
||||||
|
{
|
||||||
|
reserve(idx - m_first + 1);
|
||||||
|
}
|
||||||
|
else if (idx < m_first)
|
||||||
|
{
|
||||||
|
// We have wrapped.
|
||||||
|
if (idx > ((m_first + m_capacity) & 0xffff) && m_capacity < 0xffff)
|
||||||
|
{
|
||||||
|
reserve(m_capacity + (idx - ((m_first + m_capacity) & 0xffff)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (compare_less_wrap(m_last, (idx + 1) & 0xffff, 0xffff))
|
||||||
|
m_last = (idx + 1) & 0xffff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_first = idx;
|
||||||
|
m_last = (idx + 1) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_capacity == 0) reserve(16);
|
||||||
|
|
||||||
|
void* old_value = m_storage[idx & (m_capacity - 1)];
|
||||||
|
m_storage[idx & (m_capacity - 1)] = value;
|
||||||
|
|
||||||
|
if (m_size++ == 0)
|
||||||
|
{
|
||||||
|
m_first = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
TORRENT_ASSERT_VAL(m_first <= 0xffff, m_first);
|
||||||
|
return old_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* packet_buffer::at(index_type idx) const
|
||||||
|
{
|
||||||
|
if (idx >= m_first + m_capacity)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (compare_less_wrap(idx, m_first, 0xffff))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_storage[idx & (m_capacity - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void packet_buffer::reserve(std::size_t size)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT_VAL(size <= 0xffff, size);
|
||||||
|
std::size_t new_size = m_capacity == 0 ? 16 : m_capacity;
|
||||||
|
|
||||||
|
while (new_size < size)
|
||||||
|
new_size <<= 1;
|
||||||
|
|
||||||
|
void** new_storage = (void**)malloc(sizeof(void*) * new_size);
|
||||||
|
|
||||||
|
for (index_type i = 0; i < new_size; ++i)
|
||||||
|
new_storage[i] = 0;
|
||||||
|
|
||||||
|
for (index_type i = m_first; i < (m_first + m_capacity); ++i)
|
||||||
|
new_storage[i & (new_size - 1)] = m_storage[i & (m_capacity - 1)];
|
||||||
|
|
||||||
|
free(m_storage);
|
||||||
|
|
||||||
|
m_storage = new_storage;
|
||||||
|
m_capacity = new_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* packet_buffer::remove(index_type idx)
|
||||||
|
{
|
||||||
|
// TODO: use compare_less_wrap for this comparison as well
|
||||||
|
if (idx >= m_first + m_capacity)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (compare_less_wrap(idx, m_first, 0xffff))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
void* old_value = m_storage[idx & (m_capacity - 1)];
|
||||||
|
m_storage[idx & (m_capacity - 1)] = 0;
|
||||||
|
|
||||||
|
if (old_value)
|
||||||
|
{
|
||||||
|
--m_size;
|
||||||
|
if (m_size == 0) m_last = m_first;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx == m_first && m_size != 0)
|
||||||
|
{
|
||||||
|
while (!m_storage[++m_first & (m_capacity - 1)]);
|
||||||
|
m_first &= 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((idx + 1) & 0xffff) == m_last && m_size != 0)
|
||||||
|
{
|
||||||
|
while (!m_storage[--m_last & (m_capacity - 1)]);
|
||||||
|
++m_last;
|
||||||
|
m_last &= 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
TORRENT_ASSERT_VAL(m_first <= 0xffff, m_first);
|
||||||
|
return old_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -53,6 +53,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "libtorrent/broadcast_socket.hpp"
|
#include "libtorrent/broadcast_socket.hpp"
|
||||||
#include "libtorrent/torrent.hpp"
|
#include "libtorrent/torrent.hpp"
|
||||||
#include "libtorrent/peer_info.hpp"
|
#include "libtorrent/peer_info.hpp"
|
||||||
|
#include "libtorrent/bt_peer_connection.hpp"
|
||||||
|
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -150,6 +151,7 @@ namespace libtorrent
|
|||||||
, m_bitfield_received(false)
|
, m_bitfield_received(false)
|
||||||
, m_no_download(false)
|
, m_no_download(false)
|
||||||
, m_sent_suggests(false)
|
, m_sent_suggests(false)
|
||||||
|
, m_holepunch_mode(false)
|
||||||
, m_ignore_stats(false)
|
, m_ignore_stats(false)
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
, m_in_constructor(true)
|
, m_in_constructor(true)
|
||||||
@ -195,6 +197,8 @@ namespace libtorrent
|
|||||||
+ to_string(m_remote.port()).elems, m_ses.listen_port());
|
+ to_string(m_remote.port()).elems, m_ses.listen_port());
|
||||||
(*m_logger) << time_now_string() << " *** OUTGOING CONNECTION: "
|
(*m_logger) << time_now_string() << " *** OUTGOING CONNECTION: "
|
||||||
<< print_endpoint(m_remote) << "\n";
|
<< print_endpoint(m_remote) << "\n";
|
||||||
|
if (m_socket->get<utp_stream>()) (*m_logger) << "uTP connection\n";
|
||||||
|
else (*m_logger) << "TCP connection\n";
|
||||||
#endif
|
#endif
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
piece_failed = false;
|
piece_failed = false;
|
||||||
@ -289,6 +293,7 @@ namespace libtorrent
|
|||||||
, m_bitfield_received(false)
|
, m_bitfield_received(false)
|
||||||
, m_no_download(false)
|
, m_no_download(false)
|
||||||
, m_sent_suggests(false)
|
, m_sent_suggests(false)
|
||||||
|
, m_holepunch_mode(false)
|
||||||
, m_ignore_stats(false)
|
, m_ignore_stats(false)
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
, m_in_constructor(true)
|
, m_in_constructor(true)
|
||||||
@ -335,6 +340,8 @@ namespace libtorrent
|
|||||||
+ to_string(remote().port()).elems, m_ses.listen_port());
|
+ to_string(remote().port()).elems, m_ses.listen_port());
|
||||||
(*m_logger) << time_now_string() << " *** INCOMING CONNECTION: "
|
(*m_logger) << time_now_string() << " *** INCOMING CONNECTION: "
|
||||||
<< print_endpoint(m_remote) << "\n";
|
<< print_endpoint(m_remote) << "\n";
|
||||||
|
if (m_socket->get<utp_stream>()) (*m_logger) << "uTP connection\n";
|
||||||
|
else (*m_logger) << "TCP connection\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_GEO_IP
|
#ifndef TORRENT_DISABLE_GEO_IP
|
||||||
@ -557,6 +564,7 @@ namespace libtorrent
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_remote = m_socket->remote_endpoint(ec);
|
m_remote = m_socket->remote_endpoint(ec);
|
||||||
|
TORRENT_ASSERT(m_remote.address() != address_v4::any());
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
disconnect(ec);
|
disconnect(ec);
|
||||||
@ -626,6 +634,16 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
m_extensions.push_back(ext);
|
m_extensions.push_back(ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
peer_plugin const* peer_connection::find_plugin(char const* type)
|
||||||
|
{
|
||||||
|
for (extension_list_t::iterator i = m_extensions.begin()
|
||||||
|
, end(m_extensions.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
if (strcmp((*i)->type(), type) == 0) return (*i).get();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void peer_connection::send_allowed_set()
|
void peer_connection::send_allowed_set()
|
||||||
@ -2215,6 +2233,8 @@ namespace libtorrent
|
|||||||
if (!m_bitfield_received) incoming_have_none();
|
if (!m_bitfield_received) incoming_have_none();
|
||||||
if (is_disconnecting()) return;
|
if (is_disconnecting()) return;
|
||||||
|
|
||||||
|
update_desired_queue_size();
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
for (extension_list_t::iterator i = m_extensions.begin()
|
for (extension_list_t::iterator i = m_extensions.begin()
|
||||||
, end(m_extensions.end()); i != end; ++i)
|
, end(m_extensions.end()); i != end; ++i)
|
||||||
@ -3238,13 +3258,62 @@ namespace libtorrent
|
|||||||
TORRENT_ASSERT(m_ses.is_network_thread());
|
TORRENT_ASSERT(m_ses.is_network_thread());
|
||||||
|
|
||||||
TORRENT_ASSERT(m_connecting);
|
TORRENT_ASSERT(m_connecting);
|
||||||
|
connect_failed(errors::timed_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void peer_connection::connect_failed(error_code const& e)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_connecting);
|
||||||
|
TORRENT_ASSERT(e);
|
||||||
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||||
peer_log("CONNECTION TIMED OUT: %s", print_endpoint(m_remote).c_str());
|
peer_log("CONNECTION FAILED: %s", print_endpoint(m_remote).c_str());
|
||||||
#endif
|
#endif
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||||
(*m_ses.m_logger) << "CONNECTION TIMED OUT: " << print_endpoint(m_remote) << "\n";
|
(*m_ses.m_logger) << "CONNECTION FAILED: " << print_endpoint(m_remote) << "\n";
|
||||||
#endif
|
#endif
|
||||||
disconnect(errors::timed_out, 1);
|
|
||||||
|
if (m_connection_ticket != -1)
|
||||||
|
{
|
||||||
|
m_ses.m_half_open.done(m_connection_ticket);
|
||||||
|
m_connecting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// a connection attempt using uTP just failed
|
||||||
|
// mark this peer as not supporting uTP
|
||||||
|
// we'll never try it again (unless we're trying holepunch)
|
||||||
|
if (m_socket->get<utp_stream>()
|
||||||
|
&& m_peer_info
|
||||||
|
&& m_peer_info->supports_utp
|
||||||
|
&& !m_holepunch_mode)
|
||||||
|
{
|
||||||
|
m_peer_info->supports_utp = false;
|
||||||
|
// reconnect immediately using TCP
|
||||||
|
policy::peer* pi = peer_info_struct();
|
||||||
|
boost::shared_ptr<torrent> t = m_torrent.lock();
|
||||||
|
fast_reconnect(true);
|
||||||
|
disconnect(e, 0);
|
||||||
|
if (t && pi) t->connect_to_peer(pi, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_holepunch_mode)
|
||||||
|
fast_reconnect(true);
|
||||||
|
|
||||||
|
if ((!m_socket->get<utp_stream>() || !m_ses.m_settings.enable_outgoing_tcp)
|
||||||
|
&& m_peer_info
|
||||||
|
&& m_peer_info->supports_holepunch
|
||||||
|
&& !m_holepunch_mode)
|
||||||
|
{
|
||||||
|
boost::shared_ptr<torrent> t = m_torrent.lock();
|
||||||
|
// see if we can try a holepunch
|
||||||
|
bt_peer_connection* p = t->find_introducer(remote());
|
||||||
|
if (p)
|
||||||
|
p->write_holepunch_msg(bt_peer_connection::hp_rendezvous, remote(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect(e, 1);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the error argument defaults to 0, which means deliberate disconnect
|
// the error argument defaults to 0, which means deliberate disconnect
|
||||||
@ -3524,6 +3593,7 @@ namespace libtorrent
|
|||||||
p.flags |= is_seed() ? peer_info::seed : 0;
|
p.flags |= is_seed() ? peer_info::seed : 0;
|
||||||
p.flags |= m_snubbed ? peer_info::snubbed : 0;
|
p.flags |= m_snubbed ? peer_info::snubbed : 0;
|
||||||
p.flags |= m_upload_only ? peer_info::upload_only : 0;
|
p.flags |= m_upload_only ? peer_info::upload_only : 0;
|
||||||
|
p.flags |= m_holepunch_mode ? peer_info::holepunched : 0;
|
||||||
if (peer_info_struct())
|
if (peer_info_struct())
|
||||||
{
|
{
|
||||||
policy::peer* pi = peer_info_struct();
|
policy::peer* pi = peer_info_struct();
|
||||||
@ -3680,6 +3750,37 @@ namespace libtorrent
|
|||||||
m_superseed_piece = index;
|
m_superseed_piece = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void peer_connection::update_desired_queue_size()
|
||||||
|
{
|
||||||
|
if (m_snubbed)
|
||||||
|
{
|
||||||
|
m_desired_queue_size = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int download_rate = statistics().download_rate();
|
||||||
|
|
||||||
|
// calculate the desired download queue size
|
||||||
|
const int queue_time = m_ses.settings().request_queue_time;
|
||||||
|
// (if the latency is more than this, the download will stall)
|
||||||
|
// so, the queue size is queue_time * down_rate / 16 kiB
|
||||||
|
// (16 kB is the size of each request)
|
||||||
|
// the minimum number of requests is 2 and the maximum is 48
|
||||||
|
// the block size doesn't have to be 16. So we first query the
|
||||||
|
// torrent for it
|
||||||
|
boost::shared_ptr<torrent> t = m_torrent.lock();
|
||||||
|
const int block_size = t->block_size();
|
||||||
|
|
||||||
|
TORRENT_ASSERT(block_size > 0);
|
||||||
|
|
||||||
|
m_desired_queue_size = queue_time * download_rate / block_size;
|
||||||
|
|
||||||
|
if (m_desired_queue_size > m_max_out_request_queue)
|
||||||
|
m_desired_queue_size = m_max_out_request_queue;
|
||||||
|
if (m_desired_queue_size < min_request_queue)
|
||||||
|
m_desired_queue_size = min_request_queue;
|
||||||
|
}
|
||||||
|
|
||||||
void peer_connection::second_tick(int tick_interval_ms)
|
void peer_connection::second_tick(int tick_interval_ms)
|
||||||
{
|
{
|
||||||
ptime now = time_now();
|
ptime now = time_now();
|
||||||
@ -3880,36 +3981,13 @@ namespace libtorrent
|
|||||||
|
|
||||||
if (!t->ready_for_connections()) return;
|
if (!t->ready_for_connections()) return;
|
||||||
|
|
||||||
// calculate the desired download queue size
|
update_desired_queue_size();
|
||||||
const int queue_time = m_ses.settings().request_queue_time;
|
|
||||||
// (if the latency is more than this, the download will stall)
|
|
||||||
// so, the queue size is queue_time * down_rate / 16 kiB
|
|
||||||
// (16 kB is the size of each request)
|
|
||||||
// the minimum number of requests is 2 and the maximum is 48
|
|
||||||
// the block size doesn't have to be 16. So we first query the
|
|
||||||
// torrent for it
|
|
||||||
const int block_size = t->block_size();
|
|
||||||
TORRENT_ASSERT(block_size > 0);
|
|
||||||
|
|
||||||
if (m_snubbed)
|
|
||||||
{
|
|
||||||
m_desired_queue_size = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_desired_queue_size = queue_time
|
|
||||||
* statistics().download_rate() / block_size;
|
|
||||||
if (m_desired_queue_size > m_max_out_request_queue)
|
|
||||||
m_desired_queue_size = m_max_out_request_queue;
|
|
||||||
if (m_desired_queue_size < min_request_queue)
|
|
||||||
m_desired_queue_size = min_request_queue;
|
|
||||||
|
|
||||||
if (m_desired_queue_size == m_max_out_request_queue
|
if (m_desired_queue_size == m_max_out_request_queue
|
||||||
&& t->alerts().should_post<performance_alert>())
|
&& t->alerts().should_post<performance_alert>())
|
||||||
{
|
{
|
||||||
t->alerts().post_alert(performance_alert(t->get_handle()
|
t->alerts().post_alert(performance_alert(t->get_handle()
|
||||||
, performance_alert::outstanding_request_limit_reached));
|
, performance_alert::outstanding_request_limit_reached));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int piece_timeout = m_ses.settings().piece_timeout;
|
int piece_timeout = m_ses.settings().piece_timeout;
|
||||||
@ -3926,6 +4004,7 @@ namespace libtorrent
|
|||||||
// allowed to download. If it is impossible to beat the piece
|
// allowed to download. If it is impossible to beat the piece
|
||||||
// timeout at this rate, adjust it to be realistic
|
// timeout at this rate, adjust it to be realistic
|
||||||
|
|
||||||
|
const int block_size = t->block_size();
|
||||||
int rate_limit_timeout = rate_limit / block_size;
|
int rate_limit_timeout = rate_limit / block_size;
|
||||||
if (piece_timeout < rate_limit_timeout) piece_timeout = rate_limit_timeout;
|
if (piece_timeout < rate_limit_timeout) piece_timeout = rate_limit_timeout;
|
||||||
|
|
||||||
@ -4131,8 +4210,11 @@ namespace libtorrent
|
|||||||
// only add new piece-chunks if the send buffer is small enough
|
// only add new piece-chunks if the send buffer is small enough
|
||||||
// otherwise there will be no end to how large it will be!
|
// otherwise there will be no end to how large it will be!
|
||||||
|
|
||||||
int buffer_size_watermark = int(m_statistics.upload_rate())
|
int upload_rate = int(m_statistics.upload_rate());
|
||||||
|
|
||||||
|
int buffer_size_watermark = upload_rate
|
||||||
* m_ses.settings().send_buffer_watermark_factor;
|
* m_ses.settings().send_buffer_watermark_factor;
|
||||||
|
|
||||||
if (buffer_size_watermark < 512) buffer_size_watermark = 512;
|
if (buffer_size_watermark < 512) buffer_size_watermark = 512;
|
||||||
else if (buffer_size_watermark > m_ses.settings().send_buffer_watermark)
|
else if (buffer_size_watermark > m_ses.settings().send_buffer_watermark)
|
||||||
{
|
{
|
||||||
@ -4351,13 +4433,16 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
if (!m_ignore_bandwidth_limits)
|
if (!m_ignore_bandwidth_limits)
|
||||||
{
|
{
|
||||||
|
bool utp = m_socket->get<utp_stream>();
|
||||||
|
|
||||||
// in this case, we have data to send, but no
|
// in this case, we have data to send, but no
|
||||||
// bandwidth. So, we simply request bandwidth
|
// bandwidth. So, we simply request bandwidth
|
||||||
// from the bandwidth manager
|
// from the bandwidth manager
|
||||||
request_upload_bandwidth(
|
request_upload_bandwidth(
|
||||||
&m_ses.m_upload_channel
|
(m_ses.m_settings.rate_limit_utp || !utp) ? &m_ses.m_upload_channel : 0
|
||||||
, &t->m_bandwidth_channel[upload_channel]
|
, &t->m_bandwidth_channel[upload_channel]
|
||||||
, &m_bandwidth_channel[upload_channel]);
|
, &m_bandwidth_channel[upload_channel]
|
||||||
|
, !utp ? &m_ses.m_tcp_upload_channel : 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -4461,13 +4546,16 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
if (!m_ignore_bandwidth_limits)
|
if (!m_ignore_bandwidth_limits)
|
||||||
{
|
{
|
||||||
|
bool utp = m_socket->get<utp_stream>();
|
||||||
|
|
||||||
// in this case, we have outstanding data to
|
// in this case, we have outstanding data to
|
||||||
// receive, but no bandwidth quota. So, we simply
|
// receive, but no bandwidth quota. So, we simply
|
||||||
// request bandwidth from the bandwidth manager
|
// request bandwidth from the bandwidth manager
|
||||||
request_download_bandwidth(
|
request_download_bandwidth(
|
||||||
&m_ses.m_download_channel
|
(m_ses.m_settings.rate_limit_utp || !utp) ? &m_ses.m_download_channel : 0
|
||||||
, &t->m_bandwidth_channel[download_channel]
|
, &t->m_bandwidth_channel[download_channel]
|
||||||
, &m_bandwidth_channel[download_channel]);
|
, &m_bandwidth_channel[download_channel]
|
||||||
|
, !utp ? &m_ses.m_tcp_download_channel : 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -4785,6 +4873,12 @@ namespace libtorrent
|
|||||||
TORRENT_ASSERT(m_ses.is_network_thread());
|
TORRENT_ASSERT(m_ses.is_network_thread());
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
(*m_logger) << time_now_string() << " *** ON_RECEIVE_DATA ["
|
||||||
|
" bytes: " << bytes_transferred <<
|
||||||
|
" error: " << error.message() <<
|
||||||
|
" ]\n";
|
||||||
|
#endif
|
||||||
#if defined TORRENT_ASIO_DEBUGGING
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
complete_async("peer_connection::on_receive_data");
|
complete_async("peer_connection::on_receive_data");
|
||||||
#endif
|
#endif
|
||||||
@ -4816,6 +4910,7 @@ namespace libtorrent
|
|||||||
int num_loops = 0;
|
int num_loops = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
TORRENT_ASSERT(m_recv_pos + bytes_transferred <= m_packet_size);
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
peer_log("<<< read %d bytes", int(bytes_transferred));
|
peer_log("<<< read %d bytes", int(bytes_transferred));
|
||||||
#endif
|
#endif
|
||||||
@ -4869,6 +4964,7 @@ namespace libtorrent
|
|||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
bytes_transferred = try_read(read_sync, ec);
|
bytes_transferred = try_read(read_sync, ec);
|
||||||
|
TORRENT_ASSERT(bytes_transferred > 0 || ec);
|
||||||
if (ec && ec != asio::error::would_block)
|
if (ec && ec != asio::error::would_block)
|
||||||
{
|
{
|
||||||
m_statistics.trancieve_ip_packet(bytes_in_loop, m_remote.address().is_v6());
|
m_statistics.trancieve_ip_packet(bytes_in_loop, m_remote.address().is_v6());
|
||||||
@ -5036,27 +5132,25 @@ namespace libtorrent
|
|||||||
|
|
||||||
if (m_disconnecting) return;
|
if (m_disconnecting) return;
|
||||||
|
|
||||||
m_connecting = false;
|
|
||||||
m_ses.m_half_open.done(m_connection_ticket);
|
|
||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
connect_failed(e);
|
||||||
(*m_ses.m_logger) << time_now_string() << " CONNECTION FAILED: " << print_endpoint(m_remote)
|
|
||||||
<< ": " << e.message() << "\n";
|
|
||||||
#endif
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
||||||
(*m_logger) << time_now_string() << " CONNECTION FAILED: " << print_endpoint(m_remote)
|
|
||||||
<< ": " << e.message() << "\n";
|
|
||||||
#endif
|
|
||||||
disconnect(e, 1);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_connecting = false;
|
||||||
|
m_ses.m_half_open.done(m_connection_ticket);
|
||||||
|
|
||||||
if (m_disconnecting) return;
|
if (m_disconnecting) return;
|
||||||
m_last_receive = time_now();
|
m_last_receive = time_now();
|
||||||
|
|
||||||
|
if (m_socket->get<utp_stream>() && m_peer_info)
|
||||||
|
{
|
||||||
|
m_peer_info->confirmed_supports_utp = true;
|
||||||
|
m_peer_info->supports_utp = false;
|
||||||
|
}
|
||||||
|
|
||||||
// this means the connection just succeeded
|
// this means the connection just succeeded
|
||||||
|
|
||||||
m_statistics.received_synack(m_remote.address().is_v6());
|
m_statistics.received_synack(m_remote.address().is_v6());
|
||||||
@ -5110,6 +5204,13 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
TORRENT_ASSERT(m_ses.is_network_thread());
|
TORRENT_ASSERT(m_ses.is_network_thread());
|
||||||
|
|
||||||
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
(*m_logger) << time_now_string() << " *** ON_SEND_DATA ["
|
||||||
|
" bytes: " << bytes_transferred <<
|
||||||
|
" error: " << error.message() <<
|
||||||
|
" ]\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
#if defined TORRENT_ASIO_DEBUGGING
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
|
@ -108,7 +108,7 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
// returns the rank of a peer's source. We have an affinity
|
// returns the rank of a peer's source. We have an affinity
|
||||||
// to connecting to peers with higher rank. This is to avoid
|
// to connecting to peers with higher rank. This is to avoid
|
||||||
// problems when out peer list is diluted by stale peers from
|
// problems when our peer list is diluted by stale peers from
|
||||||
// the resume data for instance
|
// the resume data for instance
|
||||||
int source_rank(int source_bitmask)
|
int source_rank(int source_bitmask)
|
||||||
{
|
{
|
||||||
@ -1008,6 +1008,10 @@ namespace libtorrent
|
|||||||
p->seed = true;
|
p->seed = true;
|
||||||
++m_num_seeds;
|
++m_num_seeds;
|
||||||
}
|
}
|
||||||
|
if (flags & 0x04)
|
||||||
|
p->supports_utp = true;
|
||||||
|
if (flags & 0x08)
|
||||||
|
p->supports_holepunch = true;
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_GEO_IP
|
#ifndef TORRENT_DISABLE_GEO_IP
|
||||||
int as = m_torrent->session().as_for_ip(p->address());
|
int as = m_torrent->session().as_for_ip(p->address());
|
||||||
@ -1048,6 +1052,10 @@ namespace libtorrent
|
|||||||
if (!p->seed) ++m_num_seeds;
|
if (!p->seed) ++m_num_seeds;
|
||||||
p->seed = true;
|
p->seed = true;
|
||||||
}
|
}
|
||||||
|
if (flags & 0x04)
|
||||||
|
p->supports_utp = true;
|
||||||
|
if (flags & 0x08)
|
||||||
|
p->supports_holepunch = true;
|
||||||
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
||||||
if (p->connection)
|
if (p->connection)
|
||||||
@ -1362,7 +1370,13 @@ namespace libtorrent
|
|||||||
|
|
||||||
TORRENT_ASSERT(c);
|
TORRENT_ASSERT(c);
|
||||||
error_code ec;
|
error_code ec;
|
||||||
TORRENT_ASSERT(c->remote() == c->get_socket()->remote_endpoint(ec) || ec);
|
if (c->remote() != c->get_socket()->remote_endpoint(ec) && !ec)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "c->remote: %s\nc->get_socket()->remote_endpoint: %s\n"
|
||||||
|
, print_endpoint(c->remote()).c_str()
|
||||||
|
, print_endpoint(c->get_socket()->remote_endpoint(ec)).c_str());
|
||||||
|
TORRENT_ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
return std::find_if(
|
return std::find_if(
|
||||||
m_peers.begin()
|
m_peers.begin()
|
||||||
@ -1525,6 +1539,9 @@ namespace libtorrent
|
|||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
, added_to_dht(false)
|
, added_to_dht(false)
|
||||||
#endif
|
#endif
|
||||||
|
, supports_utp(true) // assume peers support utp
|
||||||
|
, confirmed_supports_utp(false)
|
||||||
|
, supports_holepunch(false)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT((src & 0xff) == src);
|
TORRENT_ASSERT((src & 0xff) == src);
|
||||||
}
|
}
|
||||||
|
@ -154,6 +154,9 @@ namespace libtorrent
|
|||||||
set.coalesce_reads = false;
|
set.coalesce_reads = false;
|
||||||
set.coalesce_writes = false;
|
set.coalesce_writes = false;
|
||||||
|
|
||||||
|
// disallow the buffer size to grow for the uTP socket
|
||||||
|
set.utp_dynamic_sock_buf = false;
|
||||||
|
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +229,9 @@ namespace libtorrent
|
|||||||
// connect to us if they want to
|
// connect to us if they want to
|
||||||
set.max_failcount = 1;
|
set.max_failcount = 1;
|
||||||
|
|
||||||
|
// allow the buffer size to grow for the uTP socket
|
||||||
|
set.utp_dynamic_sock_buf = true;
|
||||||
|
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,6 +319,11 @@ namespace aux {
|
|||||||
TORRENT_SETTING(integer, default_peer_upload_rate)
|
TORRENT_SETTING(integer, default_peer_upload_rate)
|
||||||
TORRENT_SETTING(integer, default_peer_download_rate)
|
TORRENT_SETTING(integer, default_peer_download_rate)
|
||||||
TORRENT_SETTING(boolean, broadcast_lsd)
|
TORRENT_SETTING(boolean, broadcast_lsd)
|
||||||
|
TORRENT_SETTING(boolean, enable_outgoing_utp)
|
||||||
|
TORRENT_SETTING(boolean, enable_incoming_utp)
|
||||||
|
TORRENT_SETTING(boolean, enable_outgoing_tcp)
|
||||||
|
TORRENT_SETTING(boolean, enable_incoming_tcp)
|
||||||
|
TORRENT_SETTING(integer, max_pex_peers)
|
||||||
TORRENT_SETTING(boolean, ignore_resume_timestamps)
|
TORRENT_SETTING(boolean, ignore_resume_timestamps)
|
||||||
TORRENT_SETTING(boolean, anonymous_mode)
|
TORRENT_SETTING(boolean, anonymous_mode)
|
||||||
TORRENT_SETTING(integer, tick_interval)
|
TORRENT_SETTING(integer, tick_interval)
|
||||||
@ -329,6 +334,16 @@ namespace aux {
|
|||||||
TORRENT_SETTING(integer, unchoke_slots_limit)
|
TORRENT_SETTING(integer, unchoke_slots_limit)
|
||||||
TORRENT_SETTING(integer, half_open_limit)
|
TORRENT_SETTING(integer, half_open_limit)
|
||||||
TORRENT_SETTING(integer, connections_limit)
|
TORRENT_SETTING(integer, connections_limit)
|
||||||
|
TORRENT_SETTING(integer, utp_target_delay)
|
||||||
|
TORRENT_SETTING(integer, utp_gain_factor)
|
||||||
|
TORRENT_SETTING(integer, utp_syn_resends)
|
||||||
|
TORRENT_SETTING(integer, utp_fin_resends)
|
||||||
|
TORRENT_SETTING(integer, utp_num_resends)
|
||||||
|
TORRENT_SETTING(integer, utp_connect_timeout)
|
||||||
|
TORRENT_SETTING(integer, utp_delayed_ack)
|
||||||
|
TORRENT_SETTING(boolean, utp_dynamic_sock_buf)
|
||||||
|
TORRENT_SETTING(integer, mixed_mode_algorithm)
|
||||||
|
TORRENT_SETTING(boolean, rate_limit_utp)
|
||||||
TORRENT_SETTING(integer, listen_queue_size)
|
TORRENT_SETTING(integer, listen_queue_size)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -482,6 +497,8 @@ namespace aux {
|
|||||||
, boost::bind(&session_impl::on_receive_udp, this, _1, _2, _3, _4)
|
, boost::bind(&session_impl::on_receive_udp, this, _1, _2, _3, _4)
|
||||||
, boost::bind(&session_impl::on_receive_udp_hostname, this, _1, _2, _3, _4)
|
, boost::bind(&session_impl::on_receive_udp_hostname, this, _1, _2, _3, _4)
|
||||||
, m_half_open)
|
, m_half_open)
|
||||||
|
, m_utp_socket_manager(m_settings, m_udp_socket
|
||||||
|
, boost::bind(&session_impl::incoming_connection, this, _1))
|
||||||
, m_timer(m_io_service)
|
, m_timer(m_io_service)
|
||||||
, m_lsd_announce_timer(m_io_service)
|
, m_lsd_announce_timer(m_io_service)
|
||||||
, m_host_resolver(m_io_service)
|
, m_host_resolver(m_io_service)
|
||||||
@ -645,6 +662,7 @@ namespace aux {
|
|||||||
PRINT_SIZEOF(stat)
|
PRINT_SIZEOF(stat)
|
||||||
PRINT_SIZEOF(bandwidth_channel)
|
PRINT_SIZEOF(bandwidth_channel)
|
||||||
PRINT_SIZEOF(policy)
|
PRINT_SIZEOF(policy)
|
||||||
|
(*m_logger) << "sizeof(utp_socket_impl): " << socket_impl_size() << "\n";
|
||||||
|
|
||||||
PRINT_SIZEOF(file_entry)
|
PRINT_SIZEOF(file_entry)
|
||||||
|
|
||||||
@ -1792,12 +1810,15 @@ namespace aux {
|
|||||||
{
|
{
|
||||||
// this is probably a dht message
|
// this is probably a dht message
|
||||||
m_dht->on_receive(ep, buf, len);
|
m_dht->on_receive(ep, buf, len);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_utp_socket_manager.incoming_packet(buf, len, ep))
|
||||||
|
return;
|
||||||
|
|
||||||
// maybe it's a udp tracker response
|
// maybe it's a udp tracker response
|
||||||
else if (m_tracker_manager.incoming_udp(e, ep, buf, len))
|
if (m_tracker_manager.incoming_udp(e, ep, buf, len))
|
||||||
{
|
|
||||||
m_stat.received_tracker_bytes(len + 28);
|
m_stat.received_tracker_bytes(len + 28);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_impl::on_receive_udp_hostname(error_code const& e
|
void session_impl::on_receive_udp_hostname(error_code const& e
|
||||||
@ -1901,10 +1922,34 @@ namespace aux {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TORRENT_ASSERT(endp.address() != address_v4::any());
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
(*m_logger) << time_now_string() << " <== INCOMING CONNECTION " << endp << "\n";
|
(*m_logger) << time_now_string() << " <== INCOMING CONNECTION " << endp << "\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!m_settings.enable_incoming_utp
|
||||||
|
&& s->get<utp_stream>())
|
||||||
|
{
|
||||||
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
|
(*m_logger) << " rejected uTP connection\n";
|
||||||
|
#endif
|
||||||
|
if (m_alerts.should_post<peer_blocked_alert>())
|
||||||
|
m_alerts.post_alert(peer_blocked_alert(torrent_handle(), endp.address()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_settings.enable_incoming_tcp
|
||||||
|
&& s->get<stream_socket>())
|
||||||
|
{
|
||||||
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
|
(*m_logger) << " rejected TCP connection\n";
|
||||||
|
#endif
|
||||||
|
if (m_alerts.should_post<peer_blocked_alert>())
|
||||||
|
m_alerts.post_alert(peer_blocked_alert(torrent_handle(), endp.address()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// local addresses do not count, since it's likely
|
// local addresses do not count, since it's likely
|
||||||
// coming from our own client through local service discovery
|
// coming from our own client through local service discovery
|
||||||
// and it does not reflect whether or not a router is open
|
// and it does not reflect whether or not a router is open
|
||||||
@ -2184,6 +2229,8 @@ namespace aux {
|
|||||||
|
|
||||||
m_last_tick = now;
|
m_last_tick = now;
|
||||||
|
|
||||||
|
m_utp_socket_manager.tick(now);
|
||||||
|
|
||||||
// only tick the following once per second
|
// only tick the following once per second
|
||||||
if (now - m_last_second_tick < seconds(1)) return;
|
if (now - m_last_second_tick < seconds(1)) return;
|
||||||
|
|
||||||
@ -2225,6 +2272,45 @@ namespace aux {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (m_settings.mixed_mode_algorithm)
|
||||||
|
{
|
||||||
|
case session_settings::prefer_tcp:
|
||||||
|
m_tcp_upload_channel.throttle(0);
|
||||||
|
m_tcp_download_channel.throttle(0);
|
||||||
|
break;
|
||||||
|
case session_settings::peer_proportional:
|
||||||
|
{
|
||||||
|
int num_tcp_peers = 0;
|
||||||
|
int num_peers = 0;
|
||||||
|
for (connection_map::iterator i = m_connections.begin()
|
||||||
|
, end(m_connections.end());i != end; ++i)
|
||||||
|
{
|
||||||
|
peer_connection& p = *(*i);
|
||||||
|
if (p.in_handshake()) continue;
|
||||||
|
if (!p.get_socket()->get<utp_stream>()) ++num_tcp_peers;
|
||||||
|
++num_peers;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_peers == 0)
|
||||||
|
{
|
||||||
|
m_tcp_upload_channel.throttle(0);
|
||||||
|
m_tcp_download_channel.throttle(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (num_tcp_peers == 0) num_tcp_peers = 1;
|
||||||
|
int upload_rate = (std::max)(m_stat.upload_rate(), 5000);
|
||||||
|
int download_rate = (std::max)(m_stat.download_rate(), 5000);
|
||||||
|
if (m_upload_channel.throttle()) upload_rate = m_upload_channel.throttle();
|
||||||
|
if (m_download_channel.throttle()) download_rate = m_download_channel.throttle();
|
||||||
|
|
||||||
|
m_tcp_upload_channel.throttle(upload_rate * num_tcp_peers / num_peers);
|
||||||
|
m_tcp_download_channel.throttle(download_rate * num_tcp_peers / num_peers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef TORRENT_STATS
|
#ifdef TORRENT_STATS
|
||||||
++m_second_counter;
|
++m_second_counter;
|
||||||
int downloading_torrents = 0;
|
int downloading_torrents = 0;
|
||||||
@ -3682,6 +3768,8 @@ namespace aux {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
m_utp_socket_manager.get_status(s.utp_stats);
|
||||||
|
|
||||||
int peerlist_size = 0;
|
int peerlist_size = 0;
|
||||||
for (torrent_map::const_iterator i = m_torrents.begin()
|
for (torrent_map::const_iterator i = m_torrents.begin()
|
||||||
, end(m_torrents.end()); i != end; ++i)
|
, end(m_torrents.end()); i != end; ++i)
|
||||||
|
@ -53,6 +53,9 @@ namespace libtorrent
|
|||||||
case socket_type_int_impl<http_stream>::value:
|
case socket_type_int_impl<http_stream>::value:
|
||||||
get<http_stream>()->~http_stream();
|
get<http_stream>()->~http_stream();
|
||||||
break;
|
break;
|
||||||
|
case socket_type_int_impl<utp_stream>::value:
|
||||||
|
get<utp_stream>()->~utp_stream();
|
||||||
|
break;
|
||||||
#if TORRENT_USE_I2P
|
#if TORRENT_USE_I2P
|
||||||
case socket_type_int_impl<i2p_stream>::value:
|
case socket_type_int_impl<i2p_stream>::value:
|
||||||
get<i2p_stream>()->~i2p_stream();
|
get<i2p_stream>()->~i2p_stream();
|
||||||
@ -69,6 +72,7 @@ namespace libtorrent
|
|||||||
get<ssl_stream<http_stream> >()->~ssl_stream();
|
get<ssl_stream<http_stream> >()->~ssl_stream();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
default: TORRENT_ASSERT(false);
|
||||||
}
|
}
|
||||||
m_type = 0;
|
m_type = 0;
|
||||||
}
|
}
|
||||||
@ -88,6 +92,9 @@ namespace libtorrent
|
|||||||
case socket_type_int_impl<http_stream>::value:
|
case socket_type_int_impl<http_stream>::value:
|
||||||
new ((http_stream*)m_data) http_stream(m_io_service);
|
new ((http_stream*)m_data) http_stream(m_io_service);
|
||||||
break;
|
break;
|
||||||
|
case socket_type_int_impl<utp_stream>::value:
|
||||||
|
new ((utp_stream*)m_data) utp_stream(m_io_service);
|
||||||
|
break;
|
||||||
#if TORRENT_USE_I2P
|
#if TORRENT_USE_I2P
|
||||||
case socket_type_int_impl<i2p_stream>::value:
|
case socket_type_int_impl<i2p_stream>::value:
|
||||||
new ((i2p_stream*)m_data) i2p_stream(m_io_service);
|
new ((i2p_stream*)m_data) i2p_stream(m_io_service);
|
||||||
@ -110,6 +117,7 @@ namespace libtorrent
|
|||||||
, *((boost::asio::ssl::context*)userdata));
|
, *((boost::asio::ssl::context*)userdata));
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
default: TORRENT_ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_type = type;
|
m_type = type;
|
||||||
@ -127,9 +135,6 @@ namespace libtorrent
|
|||||||
TORRENT_SOCKTYPE_FORWARD_RET(is_open(), false)
|
TORRENT_SOCKTYPE_FORWARD_RET(is_open(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
socket_type::lowest_layer_type& socket_type::lowest_layer()
|
|
||||||
{ TORRENT_SOCKTYPE_FORWARD_RET(lowest_layer(), *((lowest_layer_type*)m_data)) }
|
|
||||||
|
|
||||||
void socket_type::open(protocol_type const& p, error_code& ec)
|
void socket_type::open(protocol_type const& p, error_code& ec)
|
||||||
{ TORRENT_SOCKTYPE_FORWARD(open(p, ec)) }
|
{ TORRENT_SOCKTYPE_FORWARD(open(p, ec)) }
|
||||||
|
|
||||||
|
@ -347,10 +347,10 @@ namespace libtorrent
|
|||||||
storage(file_storage const& fs, file_storage const* mapped, std::string const& path
|
storage(file_storage const& fs, file_storage const* mapped, std::string const& path
|
||||||
, file_pool& fp, std::vector<boost::uint8_t> const& file_prio)
|
, file_pool& fp, std::vector<boost::uint8_t> const& file_prio)
|
||||||
: m_files(fs)
|
: m_files(fs)
|
||||||
|
, m_file_priority(file_prio)
|
||||||
, m_pool(fp)
|
, m_pool(fp)
|
||||||
, m_page_size(page_size())
|
, m_page_size(page_size())
|
||||||
, m_allocate_files(false)
|
, m_allocate_files(false)
|
||||||
, m_file_priority(file_prio)
|
|
||||||
{
|
{
|
||||||
if (mapped) m_mapped_files.reset(new file_storage(*mapped));
|
if (mapped) m_mapped_files.reset(new file_storage(*mapped));
|
||||||
|
|
||||||
|
105
src/timestamp_history.cpp
Normal file
105
src/timestamp_history.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2009, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "libtorrent/timestamp_history.hpp"
|
||||||
|
|
||||||
|
namespace libtorrent {
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TIME_MASK = 0xffffffff
|
||||||
|
};
|
||||||
|
// defined in utp_stream.cpp
|
||||||
|
bool compare_less_wrap(boost::uint32_t lhs, boost::uint32_t rhs
|
||||||
|
, boost::uint32_t mask);
|
||||||
|
|
||||||
|
boost::uint32_t timestamp_history::add_sample(boost::uint32_t sample, bool step)
|
||||||
|
{
|
||||||
|
if (!m_initialized)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < history_size; ++i)
|
||||||
|
m_history[i] = sample;
|
||||||
|
m_base = sample;
|
||||||
|
m_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
++m_num_samples;
|
||||||
|
|
||||||
|
// if sample is less than base, update the base
|
||||||
|
// and update the history entry (because it will
|
||||||
|
// be less than that too)
|
||||||
|
if (compare_less_wrap(sample, m_base, TIME_MASK))
|
||||||
|
{
|
||||||
|
m_base = sample;
|
||||||
|
m_history[m_index] = sample;
|
||||||
|
}
|
||||||
|
// if sample is less than our history entry, update it
|
||||||
|
else if (compare_less_wrap(sample, m_history[m_index], TIME_MASK))
|
||||||
|
{
|
||||||
|
m_history[m_index] = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::uint32_t ret = sample - m_base;
|
||||||
|
|
||||||
|
// don't step base delay history unless we have at least 120
|
||||||
|
// samples. Anything less would suggest that the connection is
|
||||||
|
// essentially idle and the samples are probably not very reliable
|
||||||
|
if (step && m_num_samples > 120)
|
||||||
|
{
|
||||||
|
m_num_samples = 0;
|
||||||
|
m_index = (m_index + 1) % history_size;
|
||||||
|
|
||||||
|
m_history[m_index] = sample;
|
||||||
|
// update m_base
|
||||||
|
m_base = sample;
|
||||||
|
for (int i = 0; i < history_size; ++i)
|
||||||
|
{
|
||||||
|
if (compare_less_wrap(m_history[i], m_base, TIME_MASK))
|
||||||
|
m_base = m_history[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timestamp_history::adjust_base(int change)
|
||||||
|
{
|
||||||
|
m_base += change;
|
||||||
|
// make sure this adjustment sticks by updating all history slots
|
||||||
|
for (int i = 0; i < history_size; ++i)
|
||||||
|
{
|
||||||
|
if (compare_less_wrap(m_history[i], m_base, TIME_MASK))
|
||||||
|
m_history[i] = m_base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -313,6 +313,9 @@ namespace libtorrent
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// defined in ut_pex.cpp
|
||||||
|
bool was_introduced_by(peer_plugin const*, tcp::endpoint const&);
|
||||||
|
|
||||||
torrent::torrent(
|
torrent::torrent(
|
||||||
session_impl& ses
|
session_impl& ses
|
||||||
, tcp::endpoint const& net_interface
|
, tcp::endpoint const& net_interface
|
||||||
@ -986,6 +989,33 @@ namespace libtorrent
|
|||||||
, shared_from_this(), _1, _2));
|
, shared_from_this(), _1, _2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bt_peer_connection* torrent::find_introducer(tcp::endpoint const& ep) const
|
||||||
|
{
|
||||||
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
|
for (const_peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i)
|
||||||
|
{
|
||||||
|
if ((*i)->type() != peer_connection::bittorrent_connection) continue;
|
||||||
|
bt_peer_connection* p = (bt_peer_connection*)(*i);
|
||||||
|
if (!p->supports_holepunch()) continue;
|
||||||
|
peer_plugin const* pp = p->find_plugin("ut_pex");
|
||||||
|
if (!pp) continue;
|
||||||
|
if (was_introduced_by(pp, ep)) return (bt_peer_connection*)p;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_peer_connection* torrent::find_peer(tcp::endpoint const& ep) const
|
||||||
|
{
|
||||||
|
for (const_peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i)
|
||||||
|
{
|
||||||
|
peer_connection* p = *i;
|
||||||
|
if (p->type() != peer_connection::bittorrent_connection) continue;
|
||||||
|
if (p->remote() == ep) return (bt_peer_connection*)p;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void torrent::on_resume_data_checked(int ret, disk_io_job const& j)
|
void torrent::on_resume_data_checked(int ret, disk_io_job const& j)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(m_ses.is_network_thread());
|
TORRENT_ASSERT(m_ses.is_network_thread());
|
||||||
@ -4366,7 +4396,7 @@ namespace libtorrent
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool torrent::connect_to_peer(policy::peer* peerinfo)
|
bool torrent::connect_to_peer(policy::peer* peerinfo, bool ignore_limit)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
@ -4390,8 +4420,8 @@ namespace libtorrent
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TORRENT_ASSERT(want_more_peers());
|
TORRENT_ASSERT(want_more_peers() || ignore_limit);
|
||||||
TORRENT_ASSERT(m_ses.num_connections() < m_ses.settings().connections_limit);
|
TORRENT_ASSERT(m_ses.num_connections() < m_ses.settings().connections_limit || ignore_limit);
|
||||||
|
|
||||||
tcp::endpoint a(peerinfo->ip());
|
tcp::endpoint a(peerinfo->ip());
|
||||||
TORRENT_ASSERT((m_ses.m_ip_filter.access(peerinfo->address()) & ip_filter::blocked) == 0);
|
TORRENT_ASSERT((m_ses.m_ip_filter.access(peerinfo->address()) & ip_filter::blocked) == 0);
|
||||||
@ -4412,7 +4442,21 @@ namespace libtorrent
|
|||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
bool ret = instantiate_connection(m_ses.m_io_service, m_ses.proxy(), *s);
|
// this is where we determine if we open a regular TCP connection
|
||||||
|
// or a uTP connection. If the m_utp_socket_manager pointer is not passed in
|
||||||
|
// we'll instantiate a TCP connection
|
||||||
|
utp_socket_manager* sm = 0;
|
||||||
|
|
||||||
|
if (m_ses.m_settings.enable_outgoing_utp
|
||||||
|
&& (!m_ses.m_settings.enable_outgoing_tcp
|
||||||
|
|| peerinfo->supports_utp
|
||||||
|
|| peerinfo->confirmed_supports_utp))
|
||||||
|
sm = &m_ses.m_utp_socket_manager;
|
||||||
|
|
||||||
|
// don't make a TCP connection if it's disabled
|
||||||
|
if (sm == 0 && !m_ses.m_settings.enable_outgoing_tcp) return false;
|
||||||
|
|
||||||
|
bool ret = instantiate_connection(m_ses.m_io_service, m_ses.proxy(), *s, 0, sm);
|
||||||
(void)ret;
|
(void)ret;
|
||||||
TORRENT_ASSERT(ret);
|
TORRENT_ASSERT(ret);
|
||||||
}
|
}
|
||||||
|
@ -59,8 +59,12 @@ udp_socket::udp_socket(asio::io_service& ios
|
|||||||
: m_callback(c)
|
: m_callback(c)
|
||||||
, m_callback2(c2)
|
, m_callback2(c2)
|
||||||
, m_ipv4_sock(ios)
|
, m_ipv4_sock(ios)
|
||||||
|
, m_v4_buf_size(0)
|
||||||
|
, m_v4_buf(0)
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
, m_ipv6_sock(ios)
|
, m_ipv6_sock(ios)
|
||||||
|
, m_v6_buf_size(0)
|
||||||
|
, m_v6_buf(0)
|
||||||
#endif
|
#endif
|
||||||
, m_bind_port(0)
|
, m_bind_port(0)
|
||||||
, m_outstanding(0)
|
, m_outstanding(0)
|
||||||
@ -71,6 +75,7 @@ udp_socket::udp_socket(asio::io_service& ios
|
|||||||
, m_queue_packets(false)
|
, m_queue_packets(false)
|
||||||
, m_tunnel_packets(false)
|
, m_tunnel_packets(false)
|
||||||
, m_abort(false)
|
, m_abort(false)
|
||||||
|
, m_reallocate_buffers(false)
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
m_magic = 0x1337;
|
m_magic = 0x1337;
|
||||||
@ -79,11 +84,22 @@ udp_socket::udp_socket(asio::io_service& ios
|
|||||||
#if defined BOOST_HAS_PTHREADS
|
#if defined BOOST_HAS_PTHREADS
|
||||||
m_thread = 0;
|
m_thread = 0;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_v4_buf_size = 1600;
|
||||||
|
m_v4_buf = (char*)malloc(m_v4_buf_size);
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
m_v6_buf_size = 1600;
|
||||||
|
m_v6_buf = (char*)malloc(m_v6_buf_size);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
udp_socket::~udp_socket()
|
udp_socket::~udp_socket()
|
||||||
{
|
{
|
||||||
|
free(m_v4_buf);
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
free(m_v6_buf);
|
||||||
|
#endif
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
TORRENT_ASSERT(m_magic == 0x1337);
|
TORRENT_ASSERT(m_magic == 0x1337);
|
||||||
TORRENT_ASSERT(!m_callback || !m_started);
|
TORRENT_ASSERT(!m_callback || !m_started);
|
||||||
@ -168,6 +184,18 @@ void udp_socket::send(udp::endpoint const& ep, char const* p, int len, error_cod
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void udp_socket::maybe_realloc_buffers()
|
||||||
|
{
|
||||||
|
if (m_reallocate_buffers)
|
||||||
|
{
|
||||||
|
m_v4_buf = (char*)realloc(m_v4_buf, m_v4_buf_size);
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
m_v6_buf = (char*)realloc(m_v6_buf, m_v6_buf_size);
|
||||||
|
#endif
|
||||||
|
m_reallocate_buffers = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_transferred)
|
void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_transferred)
|
||||||
{
|
{
|
||||||
#if defined TORRENT_ASIO_DEBUGGING
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
@ -211,6 +239,7 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_
|
|||||||
#ifndef BOOST_NO_EXCEPTIONS
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
} catch(std::exception&) {}
|
} catch(std::exception&) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// don't stop listening on recoverable errors
|
// don't stop listening on recoverable errors
|
||||||
if (e != asio::error::host_unreachable
|
if (e != asio::error::host_unreachable
|
||||||
&& e != asio::error::fault
|
&& e != asio::error::fault
|
||||||
@ -230,17 +259,19 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_
|
|||||||
|
|
||||||
if (m_abort) return;
|
if (m_abort) return;
|
||||||
|
|
||||||
|
maybe_realloc_buffers();
|
||||||
|
|
||||||
#if defined TORRENT_ASIO_DEBUGGING
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
add_outstanding_async("udp_socket::on_read");
|
add_outstanding_async("udp_socket::on_read");
|
||||||
#endif
|
#endif
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
if (s == &m_ipv4_sock)
|
if (s == &m_ipv4_sock)
|
||||||
#endif
|
#endif
|
||||||
s->async_receive_from(asio::buffer(m_v4_buf, sizeof(m_v4_buf))
|
s->async_receive_from(asio::buffer(m_v4_buf, m_v4_buf_size)
|
||||||
, m_v4_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2));
|
, m_v4_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2));
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
else
|
else
|
||||||
s->async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf))
|
s->async_receive_from(asio::buffer(m_v6_buf, m_v6_buf_size)
|
||||||
, m_v6_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2));
|
, m_v6_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -277,10 +308,12 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_
|
|||||||
|
|
||||||
if (m_abort) return;
|
if (m_abort) return;
|
||||||
|
|
||||||
|
maybe_realloc_buffers();
|
||||||
|
|
||||||
#if defined TORRENT_ASIO_DEBUGGING
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
add_outstanding_async("udp_socket::on_read");
|
add_outstanding_async("udp_socket::on_read");
|
||||||
#endif
|
#endif
|
||||||
s->async_receive_from(asio::buffer(m_v4_buf, sizeof(m_v4_buf))
|
s->async_receive_from(asio::buffer(m_v4_buf, m_v4_buf_size)
|
||||||
, m_v4_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2));
|
, m_v4_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2));
|
||||||
}
|
}
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
@ -307,10 +340,12 @@ void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_
|
|||||||
|
|
||||||
if (m_abort) return;
|
if (m_abort) return;
|
||||||
|
|
||||||
|
maybe_realloc_buffers();
|
||||||
|
|
||||||
#if defined TORRENT_ASIO_DEBUGGING
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
add_outstanding_async("udp_socket::on_read");
|
add_outstanding_async("udp_socket::on_read");
|
||||||
#endif
|
#endif
|
||||||
s->async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf))
|
s->async_receive_from(asio::buffer(m_v6_buf, m_v6_buf_size)
|
||||||
, m_v6_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2));
|
, m_v6_ep, boost::bind(&udp_socket::on_read, this, s, _1, _2));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -421,6 +456,10 @@ void udp_socket::unwrap(error_code const& e, char const* buf, int size)
|
|||||||
m_callback(e, sender, p, size - (p - buf));
|
m_callback(e, sender, p, size - (p - buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef BOOST_ASIO_ENABLE_CANCELIO
|
||||||
|
#error BOOST_ASIO_ENABLE_CANCELIO needs to be defined when building libtorrent to enable cancel() in asio on windows
|
||||||
|
#endif
|
||||||
|
|
||||||
void udp_socket::close()
|
void udp_socket::close()
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(is_single_thread());
|
TORRENT_ASSERT(is_single_thread());
|
||||||
@ -461,6 +500,18 @@ void udp_socket::close()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void udp_socket::set_buf_size(int s)
|
||||||
|
{
|
||||||
|
if (s > m_v4_buf_size)
|
||||||
|
{
|
||||||
|
m_v4_buf_size = s;
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
m_v6_buf_size = s;
|
||||||
|
#endif
|
||||||
|
m_reallocate_buffers = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void udp_socket::bind(udp::endpoint const& ep, error_code& ec)
|
void udp_socket::bind(udp::endpoint const& ep, error_code& ec)
|
||||||
{
|
{
|
||||||
CHECK_MAGIC;
|
CHECK_MAGIC;
|
||||||
@ -474,6 +525,8 @@ void udp_socket::bind(udp::endpoint const& ep, error_code& ec)
|
|||||||
if (m_ipv6_sock.is_open()) m_ipv6_sock.close(ec);
|
if (m_ipv6_sock.is_open()) m_ipv6_sock.close(ec);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
maybe_realloc_buffers();
|
||||||
|
|
||||||
if (ep.address().is_v4())
|
if (ep.address().is_v4())
|
||||||
{
|
{
|
||||||
m_ipv4_sock.open(udp::v4(), ec);
|
m_ipv4_sock.open(udp::v4(), ec);
|
||||||
@ -483,7 +536,7 @@ void udp_socket::bind(udp::endpoint const& ep, error_code& ec)
|
|||||||
#if defined TORRENT_ASIO_DEBUGGING
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
add_outstanding_async("udp_socket::on_read");
|
add_outstanding_async("udp_socket::on_read");
|
||||||
#endif
|
#endif
|
||||||
m_ipv4_sock.async_receive_from(asio::buffer(m_v4_buf, sizeof(m_v4_buf))
|
m_ipv4_sock.async_receive_from(asio::buffer(m_v4_buf, m_v4_buf_size)
|
||||||
, m_v4_ep, boost::bind(&udp_socket::on_read, this, &m_ipv4_sock, _1, _2));
|
, m_v4_ep, boost::bind(&udp_socket::on_read, this, &m_ipv4_sock, _1, _2));
|
||||||
++m_outstanding;
|
++m_outstanding;
|
||||||
}
|
}
|
||||||
@ -497,7 +550,7 @@ void udp_socket::bind(udp::endpoint const& ep, error_code& ec)
|
|||||||
#if defined TORRENT_ASIO_DEBUGGING
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
add_outstanding_async("udp_socket::on_read");
|
add_outstanding_async("udp_socket::on_read");
|
||||||
#endif
|
#endif
|
||||||
m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf))
|
m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, m_v6_buf_size)
|
||||||
, m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2));
|
, m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2));
|
||||||
++m_outstanding;
|
++m_outstanding;
|
||||||
}
|
}
|
||||||
@ -523,6 +576,8 @@ void udp_socket::bind(int port)
|
|||||||
if (m_ipv6_sock.is_open()) m_ipv6_sock.close(ec);
|
if (m_ipv6_sock.is_open()) m_ipv6_sock.close(ec);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
maybe_realloc_buffers();
|
||||||
|
|
||||||
m_ipv4_sock.open(udp::v4(), ec);
|
m_ipv4_sock.open(udp::v4(), ec);
|
||||||
if (!ec)
|
if (!ec)
|
||||||
{
|
{
|
||||||
@ -530,7 +585,7 @@ void udp_socket::bind(int port)
|
|||||||
add_outstanding_async("udp_socket::on_read");
|
add_outstanding_async("udp_socket::on_read");
|
||||||
#endif
|
#endif
|
||||||
m_ipv4_sock.bind(udp::endpoint(address_v4::any(), port), ec);
|
m_ipv4_sock.bind(udp::endpoint(address_v4::any(), port), ec);
|
||||||
m_ipv4_sock.async_receive_from(asio::buffer(m_v4_buf, sizeof(m_v4_buf))
|
m_ipv4_sock.async_receive_from(asio::buffer(m_v4_buf, m_v4_buf_size)
|
||||||
, m_v4_ep, boost::bind(&udp_socket::on_read, this, &m_ipv4_sock, _1, _2));
|
, m_v4_ep, boost::bind(&udp_socket::on_read, this, &m_ipv4_sock, _1, _2));
|
||||||
++m_outstanding;
|
++m_outstanding;
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
@ -546,7 +601,7 @@ void udp_socket::bind(int port)
|
|||||||
#endif
|
#endif
|
||||||
m_ipv6_sock.set_option(v6only(true), ec);
|
m_ipv6_sock.set_option(v6only(true), ec);
|
||||||
m_ipv6_sock.bind(udp::endpoint(address_v6::any(), port), ec);
|
m_ipv6_sock.bind(udp::endpoint(address_v6::any(), port), ec);
|
||||||
m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, sizeof(m_v6_buf))
|
m_ipv6_sock.async_receive_from(asio::buffer(m_v6_buf, m_v6_buf_size)
|
||||||
, m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2));
|
, m_v6_ep, boost::bind(&udp_socket::on_read, this, &m_ipv6_sock, _1, _2));
|
||||||
++m_outstanding;
|
++m_outstanding;
|
||||||
#ifdef TORRENT_DEBUG
|
#ifdef TORRENT_DEBUG
|
||||||
|
@ -210,6 +210,8 @@ namespace libtorrent { namespace
|
|||||||
, m_tp(tp)
|
, m_tp(tp)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
virtual char const* type() const { return "ut_metadata"; }
|
||||||
|
|
||||||
// can add entries to the extension handshake
|
// can add entries to the extension handshake
|
||||||
virtual void add_handshake(entry& h)
|
virtual void add_handshake(entry& h)
|
||||||
{
|
{
|
||||||
|
131
src/ut_pex.cpp
131
src/ut_pex.cpp
@ -145,10 +145,20 @@ namespace libtorrent { namespace
|
|||||||
// no supported flags to set yet
|
// no supported flags to set yet
|
||||||
// 0x01 - peer supports encryption
|
// 0x01 - peer supports encryption
|
||||||
// 0x02 - peer is a seed
|
// 0x02 - peer is a seed
|
||||||
|
// 0x04 - supports uTP. This is only a positive flags
|
||||||
|
// passing 0 doesn't mean the peer doesn't
|
||||||
|
// support uTP
|
||||||
|
// 0x08 - supports holepunching protocol. If this
|
||||||
|
// flag is received from a peer, it can be
|
||||||
|
// used as a rendezvous point in case direct
|
||||||
|
// connections to the peer fail
|
||||||
int flags = p->is_seed() ? 2 : 0;
|
int flags = p->is_seed() ? 2 : 0;
|
||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
flags |= p->supports_encryption() ? 1 : 0;
|
flags |= p->supports_encryption() ? 1 : 0;
|
||||||
#endif
|
#endif
|
||||||
|
flags |= p->get_socket()->get<utp_stream>() ? 4 : 0;
|
||||||
|
flags |= p->supports_holepunch() ? 8 : 0;
|
||||||
|
|
||||||
// i->first was added since the last time
|
// i->first was added since the last time
|
||||||
if (remote.address().is_v4())
|
if (remote.address().is_v4())
|
||||||
{
|
{
|
||||||
@ -205,11 +215,14 @@ namespace libtorrent { namespace
|
|||||||
: m_torrent(t)
|
: m_torrent(t)
|
||||||
, m_pc(pc)
|
, m_pc(pc)
|
||||||
, m_tp(tp)
|
, m_tp(tp)
|
||||||
|
, m_last_pex(min_time())
|
||||||
, m_1_minute(55)
|
, m_1_minute(55)
|
||||||
, m_message_index(0)
|
, m_message_index(0)
|
||||||
, m_first_time(true)
|
, m_first_time(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
virtual char const* type() const { return "ut_pex"; }
|
||||||
|
|
||||||
virtual void add_handshake(entry& h)
|
virtual void add_handshake(entry& h)
|
||||||
{
|
{
|
||||||
entry& messages = h["m"];
|
entry& messages = h["m"];
|
||||||
@ -239,9 +252,20 @@ namespace libtorrent { namespace
|
|||||||
m_pc.disconnect(errors::pex_message_too_large, 2);
|
m_pc.disconnect(errors::pex_message_too_large, 2);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ptime now = time_now();
|
||||||
|
if (now - m_last_pex < seconds(10))
|
||||||
|
{
|
||||||
|
// this client appears to be trying to flood us
|
||||||
|
// with pex messages. Don't allow that.
|
||||||
|
m_pc.disconnect(errors::too_frequent_pex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (body.left() < length) return true;
|
if (body.left() < length) return true;
|
||||||
|
|
||||||
|
m_last_pex = now;
|
||||||
|
|
||||||
lazy_entry pex_msg;
|
lazy_entry pex_msg;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
int ret = lazy_bdecode(body.begin, body.end, pex_msg, ec);
|
int ret = lazy_bdecode(body.begin, body.end, pex_msg, ec);
|
||||||
@ -251,13 +275,34 @@ namespace libtorrent { namespace
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_entry const* p = pex_msg.dict_find("added");
|
lazy_entry const* p = pex_msg.dict_find_string("dropped");
|
||||||
lazy_entry const* pf = pex_msg.dict_find("added.f");
|
|
||||||
|
|
||||||
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
(*m_pc.m_logger) << time_now_string() << " <== PEX ["
|
||||||
|
" dropped:" << (p?p->string_length():0);
|
||||||
|
#endif
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
int num_peers = p->string_length() / 6;
|
||||||
|
char const* in = p->string_ptr();
|
||||||
|
|
||||||
|
for (int i = 0; i < num_peers; ++i)
|
||||||
|
{
|
||||||
|
tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
|
||||||
|
peers4_t::value_type v(adr.address().to_v4().to_bytes(), adr.port());
|
||||||
|
peers4_t::iterator j = std::lower_bound(m_peers.begin(), m_peers.end(), v);
|
||||||
|
if (j != m_peers.end() && *j == v) m_peers.erase(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p = pex_msg.dict_find_string("added");
|
||||||
|
lazy_entry const* pf = pex_msg.dict_find_string("added.f");
|
||||||
|
|
||||||
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
(*m_pc.m_logger) << " added:" << (p?p->string_length():0) << " ]\n";
|
||||||
|
#endif
|
||||||
if (p != 0
|
if (p != 0
|
||||||
&& pf != 0
|
&& pf != 0
|
||||||
&& p->type() == lazy_entry::string_t
|
|
||||||
&& pf->type() == lazy_entry::string_t
|
|
||||||
&& pf->string_length() == p->string_length() / 6)
|
&& pf->string_length() == p->string_length() / 6)
|
||||||
{
|
{
|
||||||
int num_peers = pf->string_length();
|
int num_peers = pf->string_length();
|
||||||
@ -270,14 +315,39 @@ namespace libtorrent { namespace
|
|||||||
{
|
{
|
||||||
tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
|
tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
|
||||||
char flags = *fin++;
|
char flags = *fin++;
|
||||||
|
|
||||||
|
if (m_peers.size() >= m_torrent.settings().max_pex_peers) break;
|
||||||
|
|
||||||
// ignore local addresses unless the peer is local to us
|
// ignore local addresses unless the peer is local to us
|
||||||
if (is_local(adr.address()) && !is_local(m_pc.remote().address())) continue;
|
if (is_local(adr.address()) && !is_local(m_pc.remote().address())) continue;
|
||||||
|
|
||||||
|
peers4_t::value_type v(adr.address().to_v4().to_bytes(), adr.port());
|
||||||
|
peers4_t::iterator j = std::lower_bound(m_peers.begin(), m_peers.end(), v);
|
||||||
|
// do we already know about this peer?
|
||||||
|
if (j != m_peers.end() && *j == v) continue;
|
||||||
|
m_peers.insert(j, v);
|
||||||
p.add_peer(adr, pid, peer_info::pex, flags);
|
p.add_peer(adr, pid, peer_info::pex, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
lazy_entry const* p6 = pex_msg.dict_find("added6");
|
|
||||||
|
lazy_entry const* p6 = pex_msg.dict_find("dropped6");
|
||||||
|
if (p6 != 0 && p6->type() == lazy_entry::string_t)
|
||||||
|
{
|
||||||
|
int num_peers = p6->string_length() / 18;
|
||||||
|
char const* in = p6->string_ptr();
|
||||||
|
|
||||||
|
for (int i = 0; i < num_peers; ++i)
|
||||||
|
{
|
||||||
|
tcp::endpoint adr = detail::read_v6_endpoint<tcp::endpoint>(in);
|
||||||
|
peers6_t::value_type v(adr.address().to_v6().to_bytes(), adr.port());
|
||||||
|
peers6_t::iterator j = std::lower_bound(m_peers6.begin(), m_peers6.end(), v);
|
||||||
|
if (j != m_peers6.end() && *j == v) m_peers6.erase(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p6 = pex_msg.dict_find("added6");
|
||||||
lazy_entry const* p6f = pex_msg.dict_find("added6.f");
|
lazy_entry const* p6f = pex_msg.dict_find("added6.f");
|
||||||
if (p6 != 0
|
if (p6 != 0
|
||||||
&& p6f != 0
|
&& p6f != 0
|
||||||
@ -297,6 +367,13 @@ namespace libtorrent { namespace
|
|||||||
char flags = *fin++;
|
char flags = *fin++;
|
||||||
// ignore local addresses unless the peer is local to us
|
// ignore local addresses unless the peer is local to us
|
||||||
if (is_local(adr.address()) && !is_local(m_pc.remote().address())) continue;
|
if (is_local(adr.address()) && !is_local(m_pc.remote().address())) continue;
|
||||||
|
if (m_peers6.size() >= m_torrent.settings().max_pex_peers) break;
|
||||||
|
|
||||||
|
peers6_t::value_type v(adr.address().to_v6().to_bytes(), adr.port());
|
||||||
|
peers6_t::iterator j = std::lower_bound(m_peers6.begin(), m_peers6.end(), v);
|
||||||
|
// do we already know about this peer?
|
||||||
|
if (j != m_peers6.end() && *j == v) continue;
|
||||||
|
m_peers6.insert(j, v);
|
||||||
p.add_peer(adr, pid, peer_info::pex, flags);
|
p.add_peer(adr, pid, peer_info::pex, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -323,8 +400,6 @@ namespace libtorrent { namespace
|
|||||||
m_1_minute = 0;
|
m_1_minute = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void send_ut_peer_diff()
|
void send_ut_peer_diff()
|
||||||
{
|
{
|
||||||
// if there's no change in out peer set, don't send anything
|
// if there's no change in out peer set, don't send anything
|
||||||
@ -419,6 +494,23 @@ namespace libtorrent { namespace
|
|||||||
torrent& m_torrent;
|
torrent& m_torrent;
|
||||||
peer_connection& m_pc;
|
peer_connection& m_pc;
|
||||||
ut_pex_plugin& m_tp;
|
ut_pex_plugin& m_tp;
|
||||||
|
// stores all peers this this peer is connected to. These lists
|
||||||
|
// are updated with each pex message and are limited in size
|
||||||
|
// to protect against malicious clients. These lists are also
|
||||||
|
// used for looking up which peer a peer that supports holepunch
|
||||||
|
// came from.
|
||||||
|
// these are vectors to save memory and keep the items close
|
||||||
|
// together for performance. Inserting and removing is relatively
|
||||||
|
// cheap since the lists' size is limited
|
||||||
|
typedef std::vector<std::pair<address_v4::bytes_type, boost::uint16_t> > peers4_t;
|
||||||
|
peers4_t m_peers;
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
typedef std::vector<std::pair<address_v6::bytes_type, boost::uint16_t> > peers6_t;
|
||||||
|
peers6_t m_peers6;
|
||||||
|
#endif
|
||||||
|
// the last pex message we received
|
||||||
|
ptime m_last_pex;
|
||||||
|
|
||||||
int m_1_minute;
|
int m_1_minute;
|
||||||
int m_message_index;
|
int m_message_index;
|
||||||
|
|
||||||
@ -438,11 +530,10 @@ namespace libtorrent { namespace
|
|||||||
return boost::shared_ptr<peer_plugin>(new ut_pex_peer_plugin(m_torrent
|
return boost::shared_ptr<peer_plugin>(new ut_pex_peer_plugin(m_torrent
|
||||||
, *pc, *this));
|
, *pc, *this));
|
||||||
}
|
}
|
||||||
}}
|
} }
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t, void*)
|
boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t, void*)
|
||||||
{
|
{
|
||||||
if (t->torrent_file().priv() || (t->torrent_file().is_i2p()
|
if (t->torrent_file().priv() || (t->torrent_file().is_i2p()
|
||||||
@ -453,6 +544,28 @@ namespace libtorrent
|
|||||||
return boost::shared_ptr<torrent_plugin>(new ut_pex_plugin(*t));
|
return boost::shared_ptr<torrent_plugin>(new ut_pex_plugin(*t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool was_introduced_by(peer_plugin const* pp, tcp::endpoint const& ep)
|
||||||
|
{
|
||||||
|
ut_pex_peer_plugin* p = (ut_pex_peer_plugin*)pp;
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
if (ep.address().is_v4())
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
ut_pex_peer_plugin::peers4_t::value_type v(ep.address().to_v4().to_bytes(), ep.port());
|
||||||
|
ut_pex_peer_plugin::peers4_t::const_iterator i
|
||||||
|
= std::lower_bound(p->m_peers.begin(), p->m_peers.end(), v);
|
||||||
|
return i != p->m_peers.end() && *i == v;
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ut_pex_peer_plugin::peers6_t::value_type v(ep.address().to_v6().to_bytes(), ep.port());
|
||||||
|
ut_pex_peer_plugin::peers6_t::iterator i
|
||||||
|
= std::lower_bound(p->m_peers6.begin(), p->m_peers6.end(), v);
|
||||||
|
return i != p->m_peers6.end() && *i == v;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
324
src/utp_socket_manager.cpp
Normal file
324
src/utp_socket_manager.cpp
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2009, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libtorrent/utp_stream.hpp"
|
||||||
|
#include "libtorrent/udp_socket.hpp"
|
||||||
|
#include "libtorrent/utp_socket_manager.hpp"
|
||||||
|
#include "libtorrent/instantiate_connection.hpp"
|
||||||
|
#include "libtorrent/socket_io.hpp"
|
||||||
|
#include "libtorrent/broadcast_socket.hpp" // for is_teredo
|
||||||
|
|
||||||
|
// #define TORRENT_DEBUG_MTU 1135
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
|
||||||
|
utp_socket_manager::utp_socket_manager(session_settings const& sett, udp_socket& s
|
||||||
|
, incoming_utp_callback_t cb)
|
||||||
|
: m_sock(s)
|
||||||
|
, m_cb(cb)
|
||||||
|
, m_last_socket(0)
|
||||||
|
, m_new_connection(-1)
|
||||||
|
, m_sett(sett)
|
||||||
|
, m_sock_buf_size(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
utp_socket_manager::~utp_socket_manager()
|
||||||
|
{
|
||||||
|
for (socket_map_t::iterator i = m_utp_sockets.begin()
|
||||||
|
, end(m_utp_sockets.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
delete_utp_impl(i->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void utp_socket_manager::get_status(utp_status& s) const
|
||||||
|
{
|
||||||
|
s.num_idle = 0;
|
||||||
|
s.num_syn_sent = 0;
|
||||||
|
s.num_connected = 0;
|
||||||
|
s.num_fin_sent = 0;
|
||||||
|
s.num_close_wait = 0;
|
||||||
|
|
||||||
|
for (socket_map_t::const_iterator i = m_utp_sockets.begin()
|
||||||
|
, end(m_utp_sockets.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
int state = utp_socket_state(i->second);
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case 0: ++s.num_idle; break;
|
||||||
|
case 1: ++s.num_syn_sent; break;
|
||||||
|
case 2: ++s.num_connected; break;
|
||||||
|
case 3: ++s.num_fin_sent; break;
|
||||||
|
case 4: ++s.num_close_wait; break;
|
||||||
|
case 5: ++s.num_close_wait; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void utp_socket_manager::tick(ptime now)
|
||||||
|
{
|
||||||
|
for (socket_map_t::iterator i = m_utp_sockets.begin()
|
||||||
|
, end(m_utp_sockets.end()); i != end;)
|
||||||
|
{
|
||||||
|
if (should_delete(i->second))
|
||||||
|
{
|
||||||
|
delete_utp_impl(i->second);
|
||||||
|
if (m_last_socket == i->second) m_last_socket = 0;
|
||||||
|
m_utp_sockets.erase(i++);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tick_utp_impl(i->second, now);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void utp_socket_manager::mtu_for_dest(address const& addr, int& link_mtu, int& utp_mtu)
|
||||||
|
{
|
||||||
|
if (time_now() - m_last_route_update > seconds(60))
|
||||||
|
{
|
||||||
|
m_last_route_update = time_now();
|
||||||
|
error_code ec;
|
||||||
|
m_routes = enum_routes(m_sock.get_io_service(), ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtu = 0;
|
||||||
|
if (!m_routes.empty())
|
||||||
|
{
|
||||||
|
for (std::vector<ip_route>::iterator i = m_routes.begin()
|
||||||
|
, end(m_routes.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
if (!match_addr_mask(addr, i->destination, i->netmask)) continue;
|
||||||
|
|
||||||
|
// assume that we'll actually use the route with the largest
|
||||||
|
// MTU (seems like a reasonable assumption).
|
||||||
|
// this could however be improved by using the route metrics
|
||||||
|
// and the prefix length of the netmask to order the matches
|
||||||
|
if (mtu < i->mtu) mtu = i->mtu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mtu == 0)
|
||||||
|
{
|
||||||
|
if (is_teredo(addr)) mtu = TORRENT_TEREDO_MTU;
|
||||||
|
else mtu = TORRENT_ETHERNET_MTU;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clamp the MTU within reasonable bounds
|
||||||
|
if (mtu < TORRENT_INET_MIN_MTU) mtu = TORRENT_INET_MIN_MTU;
|
||||||
|
else if (mtu > TORRENT_INET_MAX_MTU) mtu = TORRENT_INET_MAX_MTU;
|
||||||
|
|
||||||
|
link_mtu = mtu;
|
||||||
|
|
||||||
|
mtu -= TORRENT_UDP_HEADER;
|
||||||
|
|
||||||
|
if (m_sock.get_proxy_settings().type == proxy_settings::socks5
|
||||||
|
|| m_sock.get_proxy_settings().type == proxy_settings::socks5_pw)
|
||||||
|
{
|
||||||
|
// this is for the IP layer
|
||||||
|
address proxy_addr = m_sock.proxy_addr().address();
|
||||||
|
if (proxy_addr.is_v4()) mtu -= TORRENT_IPV4_HEADER;
|
||||||
|
else mtu -= TORRENT_IPV6_HEADER;
|
||||||
|
|
||||||
|
// this is for the SOCKS layer
|
||||||
|
mtu -= TORRENT_SOCKS5_HEADER;
|
||||||
|
|
||||||
|
// the address field in the SOCKS header
|
||||||
|
if (addr.is_v4()) mtu -= 4;
|
||||||
|
else mtu -= 16;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (addr.is_v4()) mtu -= TORRENT_IPV4_HEADER;
|
||||||
|
else mtu -= TORRENT_IPV6_HEADER;
|
||||||
|
}
|
||||||
|
|
||||||
|
utp_mtu = mtu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void utp_socket_manager::send_packet(udp::endpoint const& ep, char const* p
|
||||||
|
, int len, error_code& ec, int flags)
|
||||||
|
{
|
||||||
|
if (!m_sock.is_open())
|
||||||
|
{
|
||||||
|
ec = asio::error::operation_aborted;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TORRENT_DEBUG_MTU
|
||||||
|
// drop packets that exceed the debug MTU
|
||||||
|
if ((flags & dont_fragment) && len > TORRENT_DEBUG_MTU) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TORRENT_HAS_DONT_FRAGMENT
|
||||||
|
error_code tmp;
|
||||||
|
if (flags & utp_socket_manager::dont_fragment)
|
||||||
|
m_sock.set_option(libtorrent::dont_fragment(true), tmp);
|
||||||
|
#endif
|
||||||
|
m_sock.send(ep, p, len, ec);
|
||||||
|
#ifdef TORRENT_HAS_DONT_FRAGMENT
|
||||||
|
if (flags & utp_socket_manager::dont_fragment)
|
||||||
|
m_sock.set_option(libtorrent::dont_fragment(false), tmp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp::endpoint utp_socket_manager::local_endpoint(error_code& ec) const
|
||||||
|
{
|
||||||
|
return m_sock.local_endpoint(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool utp_socket_manager::incoming_packet(char const* p, int size, udp::endpoint const& ep)
|
||||||
|
{
|
||||||
|
// UTP_LOGV("incoming packet size:%d\n", size);
|
||||||
|
|
||||||
|
if (size < sizeof(utp_header)) return false;
|
||||||
|
|
||||||
|
utp_header const* ph = (utp_header*)p;
|
||||||
|
|
||||||
|
// UTP_LOGV("incoming packet version:%d\n", int(ph->get_version()));
|
||||||
|
|
||||||
|
if (ph->get_version() != 1) return false;
|
||||||
|
|
||||||
|
const ptime receive_time = time_now_hires();
|
||||||
|
|
||||||
|
// parse out connection ID and look for existing
|
||||||
|
// connections. If found, forward to the utp_stream.
|
||||||
|
boost::uint16_t id = ph->connection_id;
|
||||||
|
|
||||||
|
// first test to see if it's the same socket as last time
|
||||||
|
// in most cases it is
|
||||||
|
if (m_last_socket
|
||||||
|
&& utp_match(m_last_socket, ep, id))
|
||||||
|
{
|
||||||
|
return utp_incoming_packet(m_last_socket, p, size, ep, receive_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_map_t::iterator i = m_utp_sockets.find(id);
|
||||||
|
|
||||||
|
std::pair<socket_map_t::iterator, socket_map_t::iterator> r =
|
||||||
|
m_utp_sockets.equal_range(id);
|
||||||
|
|
||||||
|
for (; r.first != r.second; ++r.first)
|
||||||
|
{
|
||||||
|
if (!utp_match(r.first->second, ep, id)) continue;
|
||||||
|
bool ret = utp_incoming_packet(r.first->second, p, size, ep, receive_time);
|
||||||
|
if (ret) m_last_socket = r.first->second;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UTP_LOGV("incoming packet id:%d source:%s\n", id, print_endpoint(ep).c_str());
|
||||||
|
|
||||||
|
if (!m_sett.enable_incoming_utp)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// if not found, see if it's a SYN packet, if it is,
|
||||||
|
// create a new utp_stream
|
||||||
|
if (ph->get_type() == ST_SYN)
|
||||||
|
{
|
||||||
|
// create the new socket with this ID
|
||||||
|
m_new_connection = id;
|
||||||
|
|
||||||
|
// UTP_LOGV("not found, new connection id:%d\n", m_new_connection);
|
||||||
|
|
||||||
|
boost::shared_ptr<socket_type> c(new (std::nothrow) socket_type(m_sock.get_io_service()));
|
||||||
|
if (!c) return false;
|
||||||
|
instantiate_connection(m_sock.get_io_service(), proxy_settings(), *c, 0, this);
|
||||||
|
utp_stream* str = c->get<utp_stream>();
|
||||||
|
TORRENT_ASSERT(str);
|
||||||
|
int link_mtu, utp_mtu;
|
||||||
|
mtu_for_dest(ep.address(), link_mtu, utp_mtu);
|
||||||
|
utp_init_mtu(str->get_impl(), link_mtu, utp_mtu);
|
||||||
|
bool ret = utp_incoming_packet(str->get_impl(), p, size, ep, receive_time);
|
||||||
|
if (!ret) return false;
|
||||||
|
m_cb(c);
|
||||||
|
// the connection most likely changed its connection ID here
|
||||||
|
// we need to move it to the correct ID
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #error send reset
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void utp_socket_manager::remove_socket(boost::uint16_t id)
|
||||||
|
{
|
||||||
|
socket_map_t::iterator i = m_utp_sockets.find(id);
|
||||||
|
if (i == m_utp_sockets.end()) return;
|
||||||
|
delete_utp_impl(i->second);
|
||||||
|
if (m_last_socket == i->second) m_last_socket = 0;
|
||||||
|
m_utp_sockets.erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void utp_socket_manager::set_sock_buf(int size)
|
||||||
|
{
|
||||||
|
if (size < m_sock_buf_size) return;
|
||||||
|
m_sock.set_buf_size(size);
|
||||||
|
error_code ec;
|
||||||
|
// add more socket buffer storage on the lower level socket
|
||||||
|
// to avoid dropping packets because of a full receive buffer
|
||||||
|
// while processing a packet
|
||||||
|
|
||||||
|
// only update the buffer size if it's bigger than
|
||||||
|
// what we already have
|
||||||
|
datagram_socket::receive_buffer_size recv_buf_size_opt;
|
||||||
|
m_sock.get_option(recv_buf_size_opt, ec);
|
||||||
|
if (recv_buf_size_opt.value() < size * 10)
|
||||||
|
{
|
||||||
|
m_sock.set_option(datagram_socket::receive_buffer_size(size * 10), ec);
|
||||||
|
m_sock.set_option(datagram_socket::send_buffer_size(size * 3), ec);
|
||||||
|
}
|
||||||
|
m_sock_buf_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
utp_socket_impl* utp_socket_manager::new_utp_socket(utp_stream* str)
|
||||||
|
{
|
||||||
|
boost::uint16_t send_id = 0;
|
||||||
|
boost::uint16_t recv_id = 0;
|
||||||
|
if (m_new_connection != -1)
|
||||||
|
{
|
||||||
|
send_id = m_new_connection;
|
||||||
|
recv_id = m_new_connection + 1;
|
||||||
|
m_new_connection = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
send_id = rand();
|
||||||
|
recv_id = send_id - 1;
|
||||||
|
}
|
||||||
|
utp_socket_impl* impl = construct_utp_impl(recv_id, send_id, str, this);
|
||||||
|
m_utp_sockets.insert(std::make_pair(recv_id, impl));
|
||||||
|
return impl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
2900
src/utp_stream.cpp
Normal file
2900
src/utp_stream.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -34,6 +34,7 @@ test-suite libtorrent :
|
|||||||
[ run test_bdecode_performance.cpp ]
|
[ run test_bdecode_performance.cpp ]
|
||||||
[ run test_pe_crypto.cpp ]
|
[ run test_pe_crypto.cpp ]
|
||||||
|
|
||||||
|
[ run test_utp.cpp ]
|
||||||
[ run test_auto_unchoke.cpp ]
|
[ run test_auto_unchoke.cpp ]
|
||||||
[ run test_http_connection.cpp ]
|
[ run test_http_connection.cpp ]
|
||||||
[ run test_torrent.cpp ]
|
[ run test_torrent.cpp ]
|
||||||
|
@ -241,9 +241,9 @@ setup_transfer(session* ses1, session* ses2, session* ses3
|
|||||||
ses1->set_settings(sess_set);
|
ses1->set_settings(sess_set);
|
||||||
ses2->set_settings(sess_set);
|
ses2->set_settings(sess_set);
|
||||||
if (ses3) ses3->set_settings(sess_set);
|
if (ses3) ses3->set_settings(sess_set);
|
||||||
ses1->set_alert_mask(~alert::progress_notification);
|
ses1->set_alert_mask(~(alert::progress_notification | alert::stats_notification));
|
||||||
ses2->set_alert_mask(~alert::progress_notification);
|
ses2->set_alert_mask(~(alert::progress_notification | alert::stats_notification));
|
||||||
if (ses3) ses3->set_alert_mask(~alert::progress_notification);
|
if (ses3) ses3->set_alert_mask(~(alert::progress_notification | alert::stats_notification));
|
||||||
|
|
||||||
std::srand(time(0));
|
std::srand(time(0));
|
||||||
peer_id pid;
|
peer_id pid;
|
||||||
@ -289,9 +289,11 @@ setup_transfer(session* ses1, session* ses2, session* ses3
|
|||||||
if (p) param = *p;
|
if (p) param = *p;
|
||||||
param.ti = clone_ptr(t);
|
param.ti = clone_ptr(t);
|
||||||
param.save_path = "./tmp1" + suffix;
|
param.save_path = "./tmp1" + suffix;
|
||||||
|
param.seed_mode = true;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
torrent_handle tor1 = ses1->add_torrent(param, ec);
|
torrent_handle tor1 = ses1->add_torrent(param, ec);
|
||||||
tor1.super_seeding(super_seeding);
|
tor1.super_seeding(super_seeding);
|
||||||
|
param.seed_mode = false;
|
||||||
TEST_CHECK(!ses1->get_torrents().empty());
|
TEST_CHECK(!ses1->get_torrents().empty());
|
||||||
torrent_handle tor2;
|
torrent_handle tor2;
|
||||||
torrent_handle tor3;
|
torrent_handle tor3;
|
||||||
@ -753,7 +755,7 @@ void web_server_thread(int* port, bool ssl, bool chunked)
|
|||||||
|
|
||||||
while (!p.finished())
|
while (!p.finished())
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(len < sizeof(buf));
|
TORRENT_ASSERT(len < int(sizeof(buf)));
|
||||||
size_t received = s.read_some(boost::asio::buffer(&buf[len]
|
size_t received = s.read_some(boost::asio::buffer(&buf[len]
|
||||||
, sizeof(buf) - len), ec);
|
, sizeof(buf) - len), ec);
|
||||||
// fprintf(stderr, "read: %d\n", int(received));
|
// fprintf(stderr, "read: %d\n", int(received));
|
||||||
|
@ -43,8 +43,11 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "libtorrent/broadcast_socket.hpp"
|
#include "libtorrent/broadcast_socket.hpp"
|
||||||
#include "libtorrent/identify_client.hpp"
|
#include "libtorrent/identify_client.hpp"
|
||||||
#include "libtorrent/file.hpp"
|
#include "libtorrent/file.hpp"
|
||||||
|
#include "libtorrent/packet_buffer.hpp"
|
||||||
#include "libtorrent/session.hpp"
|
#include "libtorrent/session.hpp"
|
||||||
#include "libtorrent/bencode.hpp"
|
#include "libtorrent/bencode.hpp"
|
||||||
|
#include "libtorrent/timestamp_history.hpp"
|
||||||
|
#include "libtorrent/enum_net.hpp"
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
#include "libtorrent/kademlia/node_id.hpp"
|
#include "libtorrent/kademlia/node_id.hpp"
|
||||||
#include "libtorrent/kademlia/routing_table.hpp"
|
#include "libtorrent/kademlia/routing_table.hpp"
|
||||||
@ -382,6 +385,98 @@ int test_main()
|
|||||||
error_code ec;
|
error_code ec;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
// test timestamp_history
|
||||||
|
{
|
||||||
|
timestamp_history h;
|
||||||
|
TEST_EQUAL(h.add_sample(0x32, false), 0);
|
||||||
|
TEST_EQUAL(h.base(), 0x32);
|
||||||
|
TEST_EQUAL(h.add_sample(0x33, false), 0x1);
|
||||||
|
TEST_EQUAL(h.base(), 0x32);
|
||||||
|
TEST_EQUAL(h.add_sample(0x3433, false), 0x3401);
|
||||||
|
TEST_EQUAL(h.base(), 0x32);
|
||||||
|
TEST_EQUAL(h.add_sample(0x30, false), 0);
|
||||||
|
TEST_EQUAL(h.base(), 0x30);
|
||||||
|
|
||||||
|
// test that wrapping of the timestamp is properly handled
|
||||||
|
h.add_sample(0xfffffff3, false);
|
||||||
|
TEST_EQUAL(h.base(), 0xfffffff3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// test packet_buffer
|
||||||
|
{
|
||||||
|
packet_buffer pb;
|
||||||
|
|
||||||
|
TEST_EQUAL(pb.capacity(), 0);
|
||||||
|
TEST_EQUAL(pb.size(), 0);
|
||||||
|
TEST_EQUAL(pb.span(), 0);
|
||||||
|
|
||||||
|
pb.insert(123, (void*)123);
|
||||||
|
TEST_EQUAL(pb.at(123 + 16), 0);
|
||||||
|
|
||||||
|
TEST_CHECK(pb.at(123) == (void*)123);
|
||||||
|
TEST_CHECK(pb.capacity() > 0);
|
||||||
|
TEST_EQUAL(pb.size(), 1);
|
||||||
|
TEST_EQUAL(pb.span(), 1);
|
||||||
|
TEST_EQUAL(pb.cursor(), 123);
|
||||||
|
|
||||||
|
pb.insert(125, (void*)125);
|
||||||
|
|
||||||
|
TEST_CHECK(pb.at(125) == (void*)125);
|
||||||
|
TEST_EQUAL(pb.size(), 2);
|
||||||
|
TEST_EQUAL(pb.span(), 3);
|
||||||
|
TEST_EQUAL(pb.cursor(), 123);
|
||||||
|
|
||||||
|
pb.insert(500, (void*)500);
|
||||||
|
TEST_EQUAL(pb.size(), 3);
|
||||||
|
TEST_EQUAL(pb.span(), 501 - 123);
|
||||||
|
TEST_EQUAL(pb.capacity(), 512);
|
||||||
|
|
||||||
|
TEST_CHECK(pb.remove(123) == (void*)123);
|
||||||
|
TEST_EQUAL(pb.size(), 2);
|
||||||
|
TEST_EQUAL(pb.span(), 501 - 125);
|
||||||
|
TEST_EQUAL(pb.cursor(), 125);
|
||||||
|
TEST_CHECK(pb.remove(125) == (void*)125);
|
||||||
|
TEST_EQUAL(pb.size(), 1);
|
||||||
|
TEST_EQUAL(pb.span(), 1);
|
||||||
|
TEST_EQUAL(pb.cursor(), 500);
|
||||||
|
|
||||||
|
TEST_CHECK(pb.remove(500) == (void*)500);
|
||||||
|
TEST_EQUAL(pb.size(), 0);
|
||||||
|
TEST_EQUAL(pb.span(), 0);
|
||||||
|
|
||||||
|
for (int i = 0; i < 0xff; ++i)
|
||||||
|
{
|
||||||
|
int index = (i + 0xfff0) & 0xffff;
|
||||||
|
pb.insert(index, (void*)(index + 1));
|
||||||
|
fprintf(stderr, "insert: %u (mask: %x)\n", index, int(pb.capacity() - 1));
|
||||||
|
TEST_EQUAL(pb.capacity(), 512);
|
||||||
|
if (i >= 14)
|
||||||
|
{
|
||||||
|
index = (index - 14) & 0xffff;
|
||||||
|
fprintf(stderr, "remove: %u\n", index);
|
||||||
|
TEST_CHECK(pb.remove(index) == (void*)(index + 1));
|
||||||
|
TEST_EQUAL(pb.size(), 14);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// test wrapping the indices
|
||||||
|
packet_buffer pb;
|
||||||
|
|
||||||
|
TEST_EQUAL(pb.size(), 0);
|
||||||
|
|
||||||
|
pb.insert(0xfffe, (void*)1);
|
||||||
|
TEST_CHECK(pb.at(0xfffe) == (void*)1);
|
||||||
|
|
||||||
|
pb.insert(2, (void*)2);
|
||||||
|
TEST_CHECK(pb.at(2) == (void*)2);
|
||||||
|
|
||||||
|
pb.remove(0xfffe);
|
||||||
|
TEST_CHECK(pb.at(0xfffe) == (void*)0);
|
||||||
|
TEST_CHECK(pb.at(2) == (void*)2);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CHECK(error_code(errors::http_error).message() == "HTTP error");
|
TEST_CHECK(error_code(errors::http_error).message() == "HTTP error");
|
||||||
TEST_CHECK(error_code(errors::missing_file_sizes).message() == "missing or invalid 'file sizes' entry");
|
TEST_CHECK(error_code(errors::missing_file_sizes).message() == "missing or invalid 'file sizes' entry");
|
||||||
TEST_CHECK(error_code(errors::unsupported_protocol_version).message() == "unsupported protocol version");
|
TEST_CHECK(error_code(errors::unsupported_protocol_version).message() == "unsupported protocol version");
|
||||||
@ -391,7 +486,7 @@ int test_main()
|
|||||||
|
|
||||||
TEST_CHECK(errors::reserved129 == 129);
|
TEST_CHECK(errors::reserved129 == 129);
|
||||||
TEST_CHECK(errors::reserved159 == 159);
|
TEST_CHECK(errors::reserved159 == 159);
|
||||||
TEST_CHECK(errors::reserved108 == 108);
|
TEST_CHECK(errors::reserved109 == 109);
|
||||||
|
|
||||||
{
|
{
|
||||||
// test session state load/restore
|
// test session state load/restore
|
||||||
@ -1062,6 +1157,16 @@ int test_main()
|
|||||||
#endif
|
#endif
|
||||||
TEST_CHECK(is_any(address_v4::any()));
|
TEST_CHECK(is_any(address_v4::any()));
|
||||||
TEST_CHECK(!is_any(address::from_string("31.53.21.64", ec)));
|
TEST_CHECK(!is_any(address::from_string("31.53.21.64", ec)));
|
||||||
|
|
||||||
|
TEST_CHECK(match_addr_mask(
|
||||||
|
address::from_string("10.0.1.3", ec),
|
||||||
|
address::from_string("10.0.3.3", ec),
|
||||||
|
address::from_string("255.255.0.0", ec)));
|
||||||
|
|
||||||
|
TEST_CHECK(!match_addr_mask(
|
||||||
|
address::from_string("10.0.1.3", ec),
|
||||||
|
address::from_string("10.1.3.3", ec),
|
||||||
|
address::from_string("255.255.0.0", ec)));
|
||||||
|
|
||||||
// test torrent parsing
|
// test torrent parsing
|
||||||
|
|
||||||
|
151
test/test_utp.cpp
Normal file
151
test/test_utp.cpp
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2008, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libtorrent/session.hpp"
|
||||||
|
#include "libtorrent/session_settings.hpp"
|
||||||
|
#include "libtorrent/hasher.hpp"
|
||||||
|
#include "libtorrent/alert_types.hpp"
|
||||||
|
#include "libtorrent/bencode.hpp"
|
||||||
|
#include "libtorrent/thread.hpp"
|
||||||
|
#include "libtorrent/time.hpp"
|
||||||
|
#include "libtorrent/file.hpp"
|
||||||
|
#include <boost/tuple/tuple.hpp>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
|
#include "test.hpp"
|
||||||
|
#include "setup_transfer.hpp"
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace libtorrent;
|
||||||
|
using boost::tuples::ignore;
|
||||||
|
|
||||||
|
void test_transfer()
|
||||||
|
{
|
||||||
|
// in case the previous run was terminated
|
||||||
|
error_code ec;
|
||||||
|
remove_all("./tmp1_utp", ec);
|
||||||
|
remove_all("./tmp2_utp", ec);
|
||||||
|
|
||||||
|
session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48885, 49930), "0.0.0.0", 0);
|
||||||
|
session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49885, 50930), "0.0.0.0", 0);
|
||||||
|
|
||||||
|
session_settings sett;
|
||||||
|
|
||||||
|
sett.enable_outgoing_tcp = false;
|
||||||
|
sett.min_reconnect_time = 1;
|
||||||
|
sett.announce_to_all_trackers = true;
|
||||||
|
sett.announce_to_all_tiers = true;
|
||||||
|
// make sure we announce to both http and udp trackers
|
||||||
|
sett.prefer_udp_trackers = false;
|
||||||
|
|
||||||
|
// for performance testing
|
||||||
|
// sett.disable_hash_checks = true;
|
||||||
|
// sett.utp_delayed_ack = 0;
|
||||||
|
|
||||||
|
// disable this to use regular size packets over loopback
|
||||||
|
// sett.utp_dynamic_sock_buf = false;
|
||||||
|
|
||||||
|
ses1.set_settings(sett);
|
||||||
|
ses2.set_settings(sett);
|
||||||
|
|
||||||
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
|
pe_settings pes;
|
||||||
|
pes.out_enc_policy = pe_settings::disabled;
|
||||||
|
pes.in_enc_policy = pe_settings::disabled;
|
||||||
|
ses1.set_pe_settings(pes);
|
||||||
|
ses2.set_pe_settings(pes);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
torrent_handle tor1;
|
||||||
|
torrent_handle tor2;
|
||||||
|
|
||||||
|
create_directory("./tmp1_utp", ec);
|
||||||
|
std::ofstream file("./tmp1_utp/temporary");
|
||||||
|
boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 1000, false);
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
// for performance testing
|
||||||
|
add_torrent_params atp;
|
||||||
|
// atp.storage = &disabled_storage_constructor;
|
||||||
|
|
||||||
|
// test using piece sizes smaller than 16kB
|
||||||
|
boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
|
||||||
|
, true, false, true, "_utp", 8 * 1024, &t, false, &atp);
|
||||||
|
|
||||||
|
for (int i = 0; i < 300; ++i)
|
||||||
|
{
|
||||||
|
print_alerts(ses1, "ses1", true, true, true);
|
||||||
|
print_alerts(ses2, "ses2", true, true, true);
|
||||||
|
|
||||||
|
torrent_status st1 = tor1.status();
|
||||||
|
torrent_status st2 = tor2.status();
|
||||||
|
|
||||||
|
std::cerr
|
||||||
|
<< "\033[32m" << int(st1.download_payload_rate / 1000.f) << "kB/s "
|
||||||
|
<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
|
||||||
|
<< "\033[0m" << int(st1.progress * 100) << "% "
|
||||||
|
<< st1.num_peers
|
||||||
|
<< ": "
|
||||||
|
<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
|
||||||
|
<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
|
||||||
|
<< "\033[0m" << int(st2.progress * 100) << "% "
|
||||||
|
<< st2.num_peers
|
||||||
|
<< " cc: " << st2.connect_candidates
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
if (st2.is_finished) break;
|
||||||
|
|
||||||
|
TEST_CHECK(st1.state == torrent_status::seeding
|
||||||
|
|| st1.state == torrent_status::checking_files);
|
||||||
|
TEST_CHECK(st2.state == torrent_status::downloading);
|
||||||
|
|
||||||
|
test_sleep(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CHECK(tor1.status().is_finished);
|
||||||
|
TEST_CHECK(tor2.status().is_finished);
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_main()
|
||||||
|
{
|
||||||
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
test_transfer();
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
remove_all("./tmp1_utp", ec);
|
||||||
|
remove_all("./tmp2_utp", ec);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user