merge RC_1_1 into master
|
@ -47,6 +47,8 @@ before_install:
|
|||
echo ''import site; site.addsitedir("/usr/local/lib/python2.7/site-packages")'' >> /Users/travis/Library/Python/2.7/lib/python/site-packages/homebrew.pth;
|
||||
sudo easy_install Pygments;
|
||||
sudo easy_install -U aafigure;
|
||||
brew install --quiet graphviz;
|
||||
brew install --quiet Homebrew/python/pillow;
|
||||
fi'
|
||||
|
||||
# disable simulations on OSX for now. It hangs on travis
|
||||
|
|
|
@ -10,10 +10,6 @@ DOCS_IMAGES = \
|
|||
docs/cwnd_thumb.png \
|
||||
docs/delays.png \
|
||||
docs/delays_thumb.png \
|
||||
docs/disk_access.png \
|
||||
docs/disk_buffer_before_optimization.png \
|
||||
docs/disk_buffer.png \
|
||||
docs/disk_buffer_sample.png \
|
||||
docs/disk_io.png \
|
||||
docs/hacking.html \
|
||||
docs/im_thumb.jpg \
|
||||
|
@ -28,8 +24,6 @@ DOCS_IMAGES = \
|
|||
docs/write_disk_buffers.png \
|
||||
docs/write_disk_buffers.diagram \
|
||||
docs/ziptorrent_thumb.gif \
|
||||
docs/disk_access_elevator.png \
|
||||
docs/disk_access_no_elevator.png\
|
||||
docs/ip_id_v4.png \
|
||||
docs/ip_id_v6.png \
|
||||
docs/hash_distribution.png \
|
||||
|
|
|
@ -198,7 +198,7 @@ void bind_create_torrent()
|
|||
.def(init<file_storage&>())
|
||||
.def(init<torrent_info const&>(arg("ti")))
|
||||
.def(init<file_storage&, int, int, int>((arg("storage"), arg("piece_size") = 0
|
||||
, arg("pad_file_limit") = -1, arg("flags") = int(libtorrent::create_torrent::optimize))))
|
||||
, arg("pad_file_limit") = -1, arg("flags") = int(libtorrent::create_torrent::optimize_alignment))))
|
||||
|
||||
.def("generate", &create_torrent::generate)
|
||||
|
||||
|
@ -220,7 +220,10 @@ void bind_create_torrent()
|
|||
;
|
||||
|
||||
enum_<create_torrent::flags_t>("create_torrent_flags_t")
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
.value("optimize", create_torrent::optimize)
|
||||
#endif
|
||||
.value("optimize_alignment", create_torrent::optimize_alignment)
|
||||
.value("merkle", create_torrent::merkle)
|
||||
.value("modification_time", create_torrent::modification_time)
|
||||
.value("symlinks", create_torrent::symlinks)
|
||||
|
|
|
@ -366,7 +366,7 @@ namespace
|
|||
allow_threading_guard guard;
|
||||
s.start_upnp();
|
||||
}
|
||||
#endif
|
||||
#endif // TORRENT_NO_DEPRECATE
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
boost::shared_ptr<alert>
|
||||
|
@ -789,7 +789,7 @@ void bind_session()
|
|||
.def("settings", &session_get_settings)
|
||||
.def("get_settings", &session_get_settings)
|
||||
#endif
|
||||
.def("set_settings", &session_set_settings)
|
||||
.def("apply_settings", &session_set_settings)
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||
.def("set_pe_settings", allow_threads(<::session::set_pe_settings))
|
||||
|
|
|
@ -1,765 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>libtorrent manual</title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<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@libtorrent.org">arvid@libtorrent.org</a></td></tr>
|
||||
<tr><th class="docinfo-name">Version:</th>
|
||||
<td>1.1.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="#downloading-and-building" id="id8">downloading and building</a><ul>
|
||||
<li><a class="reference internal" href="#building-from-svn" id="id9">building from svn</a></li>
|
||||
<li><a class="reference internal" href="#building-with-bbv2" id="id10">building with BBv2</a></li>
|
||||
<li><a class="reference internal" href="#building-with-autotools" id="id11">building with autotools</a></li>
|
||||
<li><a class="reference internal" href="#building-with-other-build-systems" id="id12">building with other build systems</a></li>
|
||||
<li><a class="reference internal" href="#build-configurations" id="id13">build configurations</a></li>
|
||||
<li><a class="reference internal" href="#building-openssl-for-windows" id="id14">building openssl for windows</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="downloading-and-building">
|
||||
<h1>downloading and building</h1>
|
||||
<p>To acquire the latest version of libtorrent, you'll have to grab it from SVN.
|
||||
You'll find instructions on how to do this <a class="reference external" href="http://sourceforge.net/svn/?group_id=79942">here</a> (see subversion access).</p>
|
||||
<p>The build systems supported "out of the box" in libtorrent are boost-build v2
|
||||
(BBv2) and autotools (for unix-like systems). If you still can't build after
|
||||
following these instructions, you can usually get help in the <tt class="docutils literal">#libtorrent</tt>
|
||||
IRC channel on <tt class="docutils literal">irc.freenode.net</tt>.</p>
|
||||
<div class="warning">
|
||||
<p class="first admonition-title">Warning</p>
|
||||
<p>A common mistake when building and linking against libtorrent is
|
||||
to build with one set of configuration options (#defines) and
|
||||
link against it using a different set of configuration options. Since
|
||||
libtorrent has some code in header files, that code will not be
|
||||
compatible with the built library if they see different configurations.</p>
|
||||
<p>Always make sure that the same TORRENT_* macros are defined when you
|
||||
link against libtorrent as when you build it.</p>
|
||||
<p class="last">Boost-build supports propagating configuration options to dependencies.
|
||||
When building using the makefiles, this is handled by setting the
|
||||
configuration options in the pkg-config file. Always use pkg-config
|
||||
when linking against libtorrent.</p>
|
||||
</div>
|
||||
<div class="section" id="building-from-svn">
|
||||
<h2>building from svn</h2>
|
||||
<p>To build libtorrent from svn you need to check out the libtorrent sources from
|
||||
sourceforge. If you downloaded a release tarball, you can skip this section.</p>
|
||||
<p>To check out libtorrent follow these <a class="reference external" href="http://sourceforge.net/svn/?group_id=79942">instructions</a>.</p>
|
||||
</div>
|
||||
<div class="section" id="building-with-bbv2">
|
||||
<h2>building with BBv2</h2>
|
||||
<p>The primary reason to use boost-build is that it will automatically build the
|
||||
dependent boost libraries with the correct compiler settings, in order to
|
||||
ensure that the build targets are link compatible (see <a class="reference external" href="http://boost.org/more/separate_compilation.html">boost guidelines</a>
|
||||
for some details on this issue).</p>
|
||||
<p>Since BBv2 will build the boost libraries for you, you need the full boost
|
||||
source package. Having boost installed via some package system is usually not
|
||||
enough (and even if it is enough, the necessary environment variables are
|
||||
usually not set by the package installer).</p>
|
||||
<p>If you want to build against an installed copy of boost, you can skip directly
|
||||
to step 3 (assuming you also have boost build installed).</p>
|
||||
<div class="section" id="step-1-download-boost">
|
||||
<h3>Step 1: Download boost</h3>
|
||||
<p>You'll find boost <a class="reference external" href="http://sourceforge.net/project/showfiles.php?group_id=7586&package_id=8041&release_id=619445">here</a>.</p>
|
||||
<p>Extract the archive to some directory where you want it. For the sake of this
|
||||
guide, let's assume you extract the package to <tt class="docutils literal"><span class="pre">c:\boost_1_55_0</span></tt> (I'm using
|
||||
a windows path in this example since if you're on linux/unix you're more likely
|
||||
to use the autotools). You'll need at least version 1.49 of the boost library
|
||||
in order to build libtorrent.</p>
|
||||
</div>
|
||||
<div class="section" id="step-2-setup-bbv2">
|
||||
<h3>Step 2: Setup BBv2</h3>
|
||||
<p>First you need to build <tt class="docutils literal">bjam</tt>. You do this by opening a terminal (In
|
||||
windows, run <tt class="docutils literal">cmd</tt>). Change directory to
|
||||
<tt class="docutils literal"><span class="pre">c:\boost_1_55_0\tools\jam\src</span></tt>. Then run the script called
|
||||
<tt class="docutils literal">build.bat</tt> or <tt class="docutils literal">build.sh</tt> on a unix system. This will build <tt class="docutils literal">bjam</tt> and
|
||||
place it in a directory starting with <tt class="docutils literal">bin.</tt> and then have the name of your
|
||||
platform. Copy the <tt class="docutils literal">bjam.exe</tt> (or <tt class="docutils literal">bjam</tt> on a unix system) to a place
|
||||
that's in you shell's <tt class="docutils literal">PATH</tt>. On linux systems a place commonly used may be
|
||||
<tt class="docutils literal">/usr/local/bin</tt> or on windows <tt class="docutils literal"><span class="pre">c:\windows</span></tt> (you can also add directories
|
||||
to the search paths by modifying the environment variable called <tt class="docutils literal">PATH</tt>).</p>
|
||||
<p>Now you have <tt class="docutils literal">bjam</tt> installed. <tt class="docutils literal">bjam</tt> can be considered an interpreter
|
||||
that the boost-build system is implemented on. So boost-build uses <tt class="docutils literal">bjam</tt>.
|
||||
So, to complete the installation you need to make two more things. You need to
|
||||
set the environment variable <tt class="docutils literal">BOOST_BUILD_PATH</tt>. This is the path that tells
|
||||
<tt class="docutils literal">bjam</tt> where it can find boost-build, your configuration file and all the
|
||||
toolsets (descriptions used by boost-build to know how to use different
|
||||
compilers on different platforms). Assuming the boost install path above, set
|
||||
it to <tt class="docutils literal"><span class="pre">c:\boost_1_55_0\tools\build\v2</span></tt>.</p>
|
||||
<p>To set an environment variable in windows, type for example:</p>
|
||||
<pre class="literal-block">
|
||||
set BOOST_BUILD_PATH=c:\boost_1_55_0\tools\build\v2
|
||||
</pre>
|
||||
<p>In a terminal window.</p>
|
||||
<p>The last thing to do to complete the setup of BBv2 is to modify your
|
||||
<tt class="docutils literal"><span class="pre">user-config.jam</span></tt> file. It is located in <tt class="docutils literal"><span class="pre">c:\boost_1_55_0\tools\build\v2</span></tt>.
|
||||
Depending on your platform and which compiler you're using, you should add a
|
||||
line for each compiler and compiler version you have installed on your system
|
||||
that you want to be able to use with BBv2. For example, if you're using
|
||||
Microsoft Visual Studio 12 (2013), just add a line:</p>
|
||||
<pre class="literal-block">
|
||||
using msvc : 12.0 ;
|
||||
</pre>
|
||||
<p>If you use GCC, add the line:</p>
|
||||
<pre class="literal-block">
|
||||
using gcc ;
|
||||
</pre>
|
||||
<p>If you have more than one version of GCC installed, you can add the
|
||||
commandline used to invoke g++ after the version number, like this:</p>
|
||||
<pre class="literal-block">
|
||||
using gcc : 3.3 : g++-3.3 ;
|
||||
using gcc : 4.0 : g++-4.0 ;
|
||||
</pre>
|
||||
<p>Another toolset worth mentioning is the <tt class="docutils literal">darwin</tt> toolset (For MacOS X).
|
||||
From Tiger (10.4) MacOS X comes with both GCC 3.3 and GCC 4.0. Then you can
|
||||
use the following toolsets:</p>
|
||||
<pre class="literal-block">
|
||||
using darwin : 3.3 : g++-3.3 ;
|
||||
using darwin : 4.0 : g++-4.0 ;
|
||||
</pre>
|
||||
<p>Note that the spaces around the semi-colons and colons are important!</p>
|
||||
<p>Also see the <a class="reference external" href="http://www.boost.org/doc/html/bbv2/installation.html">official installation instructions</a>.</p>
|
||||
</div>
|
||||
<div class="section" id="step-3-building-libtorrent">
|
||||
<h3>Step 3: Building libtorrent</h3>
|
||||
<p>When building libtorrent, the <tt class="docutils literal">Jamfile</tt> expects the environment variable
|
||||
<tt class="docutils literal">BOOST_ROOT</tt> to be set to the boost installation directory. It uses this to
|
||||
find the boost libraries it depends on, so they can be built and their headers
|
||||
files found. So, set this to <tt class="docutils literal"><span class="pre">c:\boost_1_55_0</span></tt>. You only need this if you're
|
||||
building against a source distribution of boost.</p>
|
||||
<p>Then the only thing left is simply to invoke <tt class="docutils literal">bjam</tt>. If you want to specify
|
||||
a specific toolset to use (compiler) you can just add that to the commandline.
|
||||
For example:</p>
|
||||
<pre class="literal-block">
|
||||
bjam msvc-7.1
|
||||
bjam gcc-3.3
|
||||
bjam darwin-4.0
|
||||
</pre>
|
||||
<div class="note">
|
||||
<p class="first admonition-title">Note</p>
|
||||
<p class="last">If the environment variable <tt class="docutils literal">BOOST_ROOT</tt> is not set, the jamfile will
|
||||
attempt to link against "installed" boost libraries. i.e. assume the headers
|
||||
and libraries are available in default search paths.</p>
|
||||
</div>
|
||||
<p>To build different versions you can also just add the name of the build
|
||||
variant. Some default build variants in BBv2 are <tt class="docutils literal">release</tt>, <tt class="docutils literal">debug</tt>,
|
||||
<tt class="docutils literal">profile</tt>.</p>
|
||||
<p>You can build libtorrent as a dll too, by typing <tt class="docutils literal">link=shared</tt>, or
|
||||
<tt class="docutils literal">link=static</tt> to build a static library.</p>
|
||||
<p>If you want to explicitly say how to link against the runtime library, you
|
||||
can set the <tt class="docutils literal"><span class="pre">runtime-link</span></tt> feature on the commandline, either to <tt class="docutils literal">shared</tt>
|
||||
or <tt class="docutils literal">static</tt>. Most operating systems will only allow linking shared against
|
||||
the runtime, but on windows you can do both. Example:</p>
|
||||
<pre class="literal-block">
|
||||
bjam msvc-7.1 link=static runtime-link=static
|
||||
</pre>
|
||||
<div class="note">
|
||||
<p class="first admonition-title">Note</p>
|
||||
<p class="last">When building on windows, the path boost-build puts targets in may be too
|
||||
long. If you get an error message like: "The input line is long", try to
|
||||
pass --abbreviate-paths on the bjam command line.</p>
|
||||
</div>
|
||||
<div class="warning">
|
||||
<p class="first admonition-title">Warning</p>
|
||||
<p class="last">If you link statically to the runtime library, you cannot build libtorrent
|
||||
as a shared library (DLL), since you will get separate heaps in the library
|
||||
and in the client application. It will result in crashes and possibly link
|
||||
errors.</p>
|
||||
</div>
|
||||
<div class="note">
|
||||
<p class="first admonition-title">Note</p>
|
||||
<p class="last">With boost-build V2 (Milestone 11), the darwin toolset uses the <tt class="docutils literal"><span class="pre">-s</span></tt> linker
|
||||
option to strip debug symbols. This option is buggy in Apple's GCC, and
|
||||
will make the executable crash on startup. On Mac OS X, instead build
|
||||
your release executables with the <tt class="docutils literal"><span class="pre">debug-symbols=on</span></tt> option, and
|
||||
later strip your executable with <tt class="docutils literal">strip</tt>.</p>
|
||||
</div>
|
||||
<div class="note">
|
||||
<p class="first admonition-title">Note</p>
|
||||
<p class="last">Some linux systems requires linking against <tt class="docutils literal">librt</tt> in order to access
|
||||
the POSIX clock functions. If you get an error complaining about a missing
|
||||
symbol <tt class="docutils literal">clock_gettime</tt>, you have to give <tt class="docutils literal"><span class="pre">need-librt=yes</span></tt> on the
|
||||
bjam command line. This will make libtorrent link against <tt class="docutils literal">librt</tt>.</p>
|
||||
</div>
|
||||
<div class="note">
|
||||
<p class="first admonition-title">Note</p>
|
||||
<p class="last">When building on Solaris, you might have to specify <tt class="docutils literal"><span class="pre">stdlib=sun-stlport</span></tt>
|
||||
on the bjam command line.</p>
|
||||
</div>
|
||||
<p>The build targets are put in a directory called bin, and under it they are
|
||||
sorted in directories depending on the toolset and build variant used.</p>
|
||||
<p>To build the examples, just change directory to the examples directory and
|
||||
invoke <tt class="docutils literal">bjam</tt> from there. To build and run the tests, go to the test
|
||||
directory and run <tt class="docutils literal">bjam</tt>.</p>
|
||||
<p>Note that if you're building on windows using the <tt class="docutils literal">msvc</tt> toolset, you cannot run it
|
||||
from a cygwin terminal, you'll have to run it from a <tt class="docutils literal">cmd</tt> terminal. The same goes for
|
||||
cygwin, if you're building with gcc in cygwin you'll have to run it from a cygwin terminal.
|
||||
Also, make sure the paths are correct in the different environments. In cygwin, the paths
|
||||
(<tt class="docutils literal">BOOST_BUILD_PATH</tt> and <tt class="docutils literal">BOOST_ROOT</tt>) should be in the typical unix-format (e.g.
|
||||
<tt class="docutils literal">/cygdrive/c/boost_1_55_0</tt>). In the windows environment, they should have the typical
|
||||
windows format (<tt class="docutils literal"><span class="pre">c:/boost_1_55_0</span></tt>).</p>
|
||||
<div class="note">
|
||||
<p class="first admonition-title">Note</p>
|
||||
<p class="last">In Jamfiles, spaces are separators. It's typically easiest to avoid spaces
|
||||
in path names. If you want spaces in your paths, make sure to quote them
|
||||
with double quotes (").</p>
|
||||
</div>
|
||||
<p>The <tt class="docutils literal">Jamfile</tt> will define <tt class="docutils literal">NDEBUG</tt> when it's building a release build.
|
||||
For more build configuration flags see <a class="reference internal" href="#build-configurations">Build configurations</a>.</p>
|
||||
<p>Build features:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="33%" />
|
||||
<col width="67%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">boost build feature</th>
|
||||
<th class="head">values</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td><tt class="docutils literal"><span class="pre">boost-link</span></tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">static</tt> - links statically against the boost
|
||||
libraries.</li>
|
||||
<li><tt class="docutils literal">shared</tt> - links dynamically against the boost
|
||||
libraries.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">logging</tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">off</tt> - logging alerts disabled.</li>
|
||||
<li><tt class="docutils literal">on</tt> - default. logging alerts available,
|
||||
still need to be enabled by the alert mask. The
|
||||
reason to disable logging is to keep the binary
|
||||
size down.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">dht</tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">on</tt> - build with support for tracker less
|
||||
torrents and DHT support.</li>
|
||||
<li><tt class="docutils literal">logging</tt> - build with DHT support and verbose
|
||||
logging of the DHT protocol traffic.</li>
|
||||
<li><tt class="docutils literal">off</tt> - build without DHT support.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">asserts</tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">auto</tt> - asserts are on if in debug mode</li>
|
||||
<li><tt class="docutils literal">on</tt> - asserts are on, even in release mode</li>
|
||||
<li><tt class="docutils literal">off</tt> - asserts are disabled</li>
|
||||
<li><tt class="docutils literal">production</tt> - assertion failures are logged
|
||||
to <tt class="docutils literal">asserts.log</tt> in the current working
|
||||
directory, but won't abort the process.
|
||||
The file they are logged to can be customized
|
||||
by setting the global pointer <tt class="docutils literal">extern char
|
||||
const* libtorrent_assert_log</tt> to a different
|
||||
filename.</li>
|
||||
<li><tt class="docutils literal">system</tt> use the libc assert macro</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">encryption</tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">on</tt> - encrypted bittorrent connections
|
||||
enabled. (Message Stream encryption).</li>
|
||||
<li><tt class="docutils literal">off</tt> - turns off support for encrypted
|
||||
connections. The shipped public domain SHA-1
|
||||
implementation is used.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal"><span class="pre">mutable-torrents</span></tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">on</tt> - mutable torrents are supported
|
||||
(<a class="reference external" href="http://www.bittorrent.org/beps/bep_0038.html">BEP 38</a>) (default).</li>
|
||||
<li><tt class="docutils literal">off</tt> - mutable torrents are not supported.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">crypto</tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal"><span class="pre">built-in</span></tt> - (default) uses built-in SHA-1
|
||||
implementation.</li>
|
||||
<li><tt class="docutils literal">openssl</tt> - links against openssl and
|
||||
libcrypto to use for SHA-1 hashing.</li>
|
||||
<li><tt class="docutils literal">gcrypt</tt> - links against libgcrypt to use for
|
||||
SHA-1 hashing.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">allocator</tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">pool</tt> - default, uses pool allocators for
|
||||
send buffers.</li>
|
||||
<li><tt class="docutils literal">system</tt> - uses <tt class="docutils literal">malloc()</tt> and <tt class="docutils literal">free()</tt>
|
||||
instead. Might be useful to debug buffer issues
|
||||
with tools like electric fence or libgmalloc.</li>
|
||||
<li><tt class="docutils literal">debug</tt> - instruments buffer usage to catch
|
||||
bugs in libtorrent.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">link</tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">static</tt> - builds libtorrent as a static
|
||||
library (.a / .lib)</li>
|
||||
<li><tt class="docutils literal">shared</tt> - builds libtorrent as a shared
|
||||
library (.so / .dll).</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal"><span class="pre">runtime-link</span></tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">static</tt> - links statically against the
|
||||
run-time library (if available on your
|
||||
platform).</li>
|
||||
<li><tt class="docutils literal">shared</tt> - link dynamically against the
|
||||
run-time library (default).</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">variant</tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">debug</tt> - builds libtorrent with debug
|
||||
information and invariant checks.</li>
|
||||
<li><tt class="docutils literal">release</tt> - builds libtorrent in release mode
|
||||
without invariant checks and with optimization.</li>
|
||||
<li><tt class="docutils literal">profile</tt> - builds libtorrent with profile
|
||||
information.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal"><span class="pre">character-set</span></tt></td>
|
||||
<td><p class="first">This setting will only have an affect on windows.
|
||||
Other platforms are expected to support UTF-8.</p>
|
||||
<ul class="last simple">
|
||||
<li><tt class="docutils literal">unicode</tt> - The unicode version of the win32
|
||||
API is used. This is default.</li>
|
||||
<li><tt class="docutils literal">ansi</tt> - The ansi version of the win32 API is
|
||||
used.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal"><span class="pre">invariant-checks</span></tt></td>
|
||||
<td><p class="first">This setting only affects debug builds (where
|
||||
<tt class="docutils literal">NDEBUG</tt> is not defined). It defaults to <tt class="docutils literal">on</tt>.</p>
|
||||
<ul class="last simple">
|
||||
<li><tt class="docutils literal">on</tt> - internal invariant checks are enabled.</li>
|
||||
<li><tt class="docutils literal">off</tt> - internal invariant checks are
|
||||
disabled. The resulting executable will run
|
||||
faster than a regular debug build.</li>
|
||||
<li><tt class="docutils literal">full</tt> - turns on extra expensive invariant
|
||||
checks.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal"><span class="pre">debug-symbols</span></tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">on</tt> - default for debug builds. This setting
|
||||
is useful for building release builds with
|
||||
symbols.</li>
|
||||
<li><tt class="docutils literal">off</tt> - default for release builds.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal"><span class="pre">deprecated-functions</span></tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">on</tt> - default. Includes deprecated functions
|
||||
of the API (might produce warnings during build
|
||||
when deprecated functions are used).</li>
|
||||
<li><tt class="docutils literal">off</tt> - excludes deprecated functions from the
|
||||
API. Generates build errors when deprecated
|
||||
functions are used.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">iconv</tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">auto</tt> - use iconv for string conversions for
|
||||
linux and mingw and other posix platforms.</li>
|
||||
<li><tt class="docutils literal">on</tt> - force use of iconv</li>
|
||||
<li><tt class="docutils literal">off</tt> - force not using iconv (disables locale
|
||||
awareness except on windows).</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">i2p</tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">on</tt> - build with I2P support</li>
|
||||
<li><tt class="docutils literal">off</tt> - build without I2P support</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal"><span class="pre">profile-calls</span></tt></td>
|
||||
<td><ul class="first last simple">
|
||||
<li><tt class="docutils literal">off</tt> - default. No additional call profiling.</li>
|
||||
<li><tt class="docutils literal">on</tt> - Enable logging of stack traces of
|
||||
calls into libtorrent that are blocking. On
|
||||
session shutdown, a file <tt class="docutils literal">blocking_calls.txt</tt>
|
||||
is written with stack traces of blocking calls
|
||||
ordered by the number of them.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The <tt class="docutils literal">variant</tt> feature is <em>implicit</em>, which means you don't need to specify
|
||||
the name of the feature, just the value.</p>
|
||||
<p>The logs created when building vlog or log mode are put in a directory called
|
||||
<tt class="docutils literal">libtorrent_logs</tt> in the current working directory.</p>
|
||||
<p>When building the example client on windows, you need to build with
|
||||
<tt class="docutils literal">link=static</tt> otherwise you may get unresolved external symbols for some
|
||||
boost.program-options symbols.</p>
|
||||
<p>For more information, see the <a class="reference external" href="http://www.boost.org/tools/build/v2/index.html">Boost build v2 documentation</a>, or more
|
||||
specifically <a class="reference external" href="http://www.boost.org/doc/html/bbv2/reference.html#bbv2.advanced.builtins.features">the section on builtin features</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="building-with-autotools">
|
||||
<h2>building with autotools</h2>
|
||||
<p>First of all, you need to install <tt class="docutils literal">automake</tt> and <tt class="docutils literal">autoconf</tt>. Many
|
||||
unix/linux systems comes with these preinstalled.</p>
|
||||
<p>The prerequisites for building libtorrent are boost.thread, boost.date_time
|
||||
and boost.filesystem. Those are the <em>compiled</em> boost libraries needed. The
|
||||
headers-only libraries needed include (but is not necessarily limited to)
|
||||
boost.bind, boost.ref, boost.multi_index, boost.optional, boost.lexical_cast,
|
||||
boost.integer, boost.iterator, boost.tuple, boost.array, boost.function,
|
||||
boost.smart_ptr, boost.preprocessor, boost.static_assert.</p>
|
||||
<p>If you want to build the <tt class="docutils literal">client_test</tt> example, you'll also need boost.regex
|
||||
and boost.program_options.</p>
|
||||
<div class="section" id="step-1-generating-the-build-system">
|
||||
<h3>Step 1: Generating the build system</h3>
|
||||
<p>No build system is present if libtorrent is checked out from CVS - it
|
||||
needs to be generated first. If you're building from a released tarball,
|
||||
you may skip directly to <a class="reference internal" href="#step-2-running-configure">Step 2: Running configure</a>.</p>
|
||||
<p>Execute the following command to generate the build system:</p>
|
||||
<pre class="literal-block">
|
||||
./autotool.sh
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="step-2-running-configure">
|
||||
<h3>Step 2: Running configure</h3>
|
||||
<p>In your shell, change directory to the libtorrent directory and run
|
||||
<tt class="docutils literal">./configure</tt>. This will look for libraries and C++ features that libtorrent
|
||||
is dependent on. If something is missing or can't be found it will print an
|
||||
error telling you what failed.</p>
|
||||
<p>The most likely problem you may encounter is that the configure script won't
|
||||
find the boost libraries. Make sure you have boost installed on your system.
|
||||
The easiest way to install boost is usually to use the preferred package
|
||||
system on your platform. Usually libraries and headers are installed in
|
||||
standard directories where the compiler will find them, but sometimes that
|
||||
may not be the case. For example when installing boost on darwin using
|
||||
darwinports (the package system based on BSD ports) all libraries are
|
||||
installed to <tt class="docutils literal">/opt/local/lib</tt> and headers are installed to
|
||||
<tt class="docutils literal">/opt/local/include</tt>. By default the compiler will not look in these
|
||||
directories. You have to set the enviornment variables <tt class="docutils literal">LDFLAGS</tt> and
|
||||
<tt class="docutils literal">CXXFLAGS</tt> in order to make the compiler find those libs. In this example
|
||||
you'd set them like this:</p>
|
||||
<pre class="literal-block">
|
||||
export LDFLAGS=-L/opt/local/lib
|
||||
export CXXFLAGS=-I/opt/local/include
|
||||
</pre>
|
||||
<p>It was observed on FreeBSD (release 6.0) that one needs to add '-lpthread' to
|
||||
LDFLAGS, as Boost::Thread detection will fail without it, even if
|
||||
Boost::Thread is installed.</p>
|
||||
<p>If you need to set these variables, it may be a good idea to add those lines
|
||||
to your <tt class="docutils literal"><span class="pre">~/.profile</span></tt> or <tt class="docutils literal"><span class="pre">~/.tcshrc</span></tt> depending on your shell.</p>
|
||||
<p>If the boost libraries are named with a suffix on your platform, you may use
|
||||
the <tt class="docutils literal"><span class="pre">--with-boost-thread=</span></tt> option to specify the suffix used for the thread
|
||||
library in this case. For more information about these options, run:</p>
|
||||
<pre class="literal-block">
|
||||
./configure --help
|
||||
</pre>
|
||||
<p>On gentoo the boost libraries that are built with multi-threading support have
|
||||
the suffix <tt class="docutils literal">mt</tt>.</p>
|
||||
<p>You know that the boost libraries were found if you see the following output
|
||||
from the configure script:</p>
|
||||
<pre class="literal-block">
|
||||
checking whether the Boost::DateTime library is available... yes
|
||||
checking for main in -lboost_date_time... yes
|
||||
checking whether the Boost::Filesystem library is available... yes
|
||||
checking for main in -lboost_filesystem... yes
|
||||
checking whether the Boost::Thread library is available... yes
|
||||
checking for main in -lboost_thread... yes
|
||||
</pre>
|
||||
<p>Another possible source of problems may be if the path to your libtorrent
|
||||
directory contains spaces. Make sure you either rename the directories with
|
||||
spaces in their names to remove the spaces or move the libtorrent directory.</p>
|
||||
</div>
|
||||
<div class="section" id="creating-a-debug-build">
|
||||
<h3>Creating a debug build</h3>
|
||||
<p>To tell configure to build a debug version (with debug info, asserts
|
||||
and invariant checks enabled), you have to run the configure script
|
||||
with the following option:</p>
|
||||
<pre class="literal-block">
|
||||
./configure --enable-debug=yes
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="creating-a-release-build">
|
||||
<h3>Creating a release build</h3>
|
||||
<p>To tell the configure to build a release version (without debug info,
|
||||
asserts and invariant checks), you have to run the configure script
|
||||
with the following option:</p>
|
||||
<pre class="literal-block">
|
||||
./configure --enable-debug=no
|
||||
</pre>
|
||||
<p>The above option make use of -DNDEBUG, which is used throughout libtorrent.</p>
|
||||
</div>
|
||||
<div class="section" id="id7">
|
||||
<h3>Step 3: Building libtorrent</h3>
|
||||
<p>Once the configure script is run successfully, you just type <tt class="docutils literal">make</tt> and
|
||||
libtorrent, the examples and the tests will be built.</p>
|
||||
<p>When libtorrent is built it may be a good idea to run the tests, you do this
|
||||
by running <tt class="docutils literal">make check</tt>.</p>
|
||||
<p>If you want to build a release version (without debug info, asserts and
|
||||
invariant checks), you have to rerun the configure script and rebuild, like this:</p>
|
||||
<pre class="literal-block">
|
||||
./configure --disable-debug
|
||||
make clean
|
||||
make
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="building-with-other-build-systems">
|
||||
<h2>building with other build systems</h2>
|
||||
<p>If you're building in MS Visual Studio, you may have to set the compiler
|
||||
options "force conformance in for loop scope", "treat wchar_t as built-in
|
||||
type" and "Enable Run-Time Type Info" to Yes.</p>
|
||||
</div>
|
||||
<div class="section" id="build-configurations">
|
||||
<h2>build configurations</h2>
|
||||
<p>By default libtorrent is built In debug mode, and will have pretty expensive
|
||||
invariant checks and asserts built into it. If you want to disable such checks
|
||||
(you want to do that in a release build) you can see the table below for which
|
||||
defines you can use to control the build.</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="45%" />
|
||||
<col width="55%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">macro</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td><tt class="docutils literal">NDEBUG</tt></td>
|
||||
<td>If you define this macro, all asserts,
|
||||
invariant checks and general debug code will be
|
||||
removed. Since there is quite a lot of code in
|
||||
in header files in libtorrent, it may be
|
||||
important to define the symbol consistently
|
||||
across compilation units, including the clients
|
||||
files. Potential problems is different
|
||||
compilation units having different views of
|
||||
structs and class layouts and sizes.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_DISABLE_LOGGING</tt></td>
|
||||
<td>This macro will disable support for logging
|
||||
alerts, like log_alert, torrent_log_alert and
|
||||
peer_log_alert. With this build flag, you
|
||||
cannot enable those alerts.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_STORAGE_DEBUG</tt></td>
|
||||
<td>This will enable extra expensive invariant
|
||||
checks in the storage, including logging of
|
||||
piece sorting.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_DISK_STATS</tt></td>
|
||||
<td>This will create a log of all disk activity
|
||||
which later can parsed and graphed using
|
||||
<tt class="docutils literal">parse_disk_log.py</tt>.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">UNICODE</tt></td>
|
||||
<td>If building on windows this will make sure the
|
||||
UTF-8 strings in pathnames are converted into
|
||||
UTF-16 before they are passed to the file
|
||||
operations.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_DISABLE_POOL_ALLOCATOR</tt></td>
|
||||
<td>Disables use of <tt class="docutils literal"><span class="pre">boost::pool<></span></tt>.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_DISABLE_MUTABLE_TORRENTS</tt></td>
|
||||
<td>Disables mutable torrent support (<a class="reference external" href="http://www.bittorrent.org/beps/bep_0038.html">BEP 38</a>)</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_LINKING_SHARED</tt></td>
|
||||
<td>If this is defined when including the
|
||||
libtorrent headers, the classes and functions
|
||||
will be tagged with <tt class="docutils literal">__declspec(dllimport)</tt>
|
||||
on msvc and default visibility on GCC 4 and
|
||||
later. Set this in your project if you're
|
||||
linking against libtorrent as a shared library.
|
||||
(This is set by the Jamfile when
|
||||
<tt class="docutils literal">link=shared</tt> is set).</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_BUILDING_SHARED</tt></td>
|
||||
<td>If this is defined, the functions and classes
|
||||
in libtorrent are marked with
|
||||
<tt class="docutils literal">__declspec(dllexport)</tt> on msvc, or with
|
||||
default visibility on GCC 4 and later. This
|
||||
should be defined when building libtorrent as
|
||||
a shared library. (This is set by the Jamfile
|
||||
when <tt class="docutils literal">link=shared</tt> is set).</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_DISABLE_DHT</tt></td>
|
||||
<td>If this is defined, the support for trackerless
|
||||
torrents will be disabled.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_DISABLE_ENCRYPTION</tt></td>
|
||||
<td>This will disable any encryption support and
|
||||
the dependencies of a crypto library.
|
||||
Encryption support is the peer connection
|
||||
encrypted supported by clients such as
|
||||
uTorrent, Azureus and KTorrent.
|
||||
If this is not defined, either
|
||||
<tt class="docutils literal">TORRENT_USE_OPENSSL</tt> or
|
||||
<tt class="docutils literal">TORRENT_USE_GCRYPT</tt> must be defined.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_DISABLE_EXTENSIONS</tt></td>
|
||||
<td>When defined, libtorrent plugin support is
|
||||
disabled along with support for the extension
|
||||
handskake (BEP 10).</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">_UNICODE</tt></td>
|
||||
<td>On windows, this will cause the file IO
|
||||
use wide character API, to properly support
|
||||
non-ansi characters.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_DISABLE_RESOLVE_COUNTRIES</tt></td>
|
||||
<td>Defining this will disable the ability to
|
||||
resolve countries of origin for peer IPs.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_DISABLE_INVARIANT_CHECKS</tt></td>
|
||||
<td>This will disable internal invariant checks in
|
||||
libtorrent. The invariant checks can sometime
|
||||
be quite expensive, they typically don't scale
|
||||
very well. This option can be used to still
|
||||
build in debug mode, with asserts enabled, but
|
||||
make the resulting executable faster.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_EXPENSIVE_INVARIANT_CHECKS</tt></td>
|
||||
<td>This will enable extra expensive invariant
|
||||
checks. Useful for finding particular bugs
|
||||
or for running before releases.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_NO_DEPRECATE</tt></td>
|
||||
<td>This will exclude all deprecated functions from
|
||||
the header files and cpp files.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_PRODUCTION_ASSERTS</tt></td>
|
||||
<td>Define to either 0 or 1. Enables assert logging
|
||||
in release builds.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_USE_ASSERTS</tt></td>
|
||||
<td>Define as 0 to disable asserts unconditionally.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">TORRENT_USE_SYSTEM_ASSERTS</tt></td>
|
||||
<td>Uses the libc assert macro rather then the
|
||||
custom one.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>If you experience that libtorrent uses unreasonable amounts of cpu, it will
|
||||
definitely help to define <tt class="docutils literal">NDEBUG</tt>, since it will remove the invariant checks
|
||||
within the library.</p>
|
||||
</div>
|
||||
<div class="section" id="building-openssl-for-windows">
|
||||
<h2>building openssl for windows</h2>
|
||||
<p>To build openssl for windows with Visual Studio 7.1 (2003) execute the following commands
|
||||
in a command shell:</p>
|
||||
<pre class="literal-block">
|
||||
perl Configure VC-WIN32 --prefix="c:/openssl
|
||||
call ms\do_nasm
|
||||
call "C:\Program Files\Microsoft Visual Studio .NET 2003\vc7\bin\vcvars32.bat"
|
||||
nmake -f ms\nt.mak
|
||||
copy inc32\openssl "C:\Program Files\Microsoft Visual Studio .NET 2003\vc7\include\"
|
||||
copy out32\libeay32.lib "C:\Program Files\Microsoft Visual Studio .NET 2003\vc7\lib"
|
||||
copy out32\ssleay32.lib "C:\Program Files\Microsoft Visual Studio .NET 2003\vc7\lib"
|
||||
</pre>
|
||||
<p>This will also install the headers and library files in the visual studio directories to
|
||||
be picked up by libtorrent.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,112 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>client_test example program</title>
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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="client-test-example-program">
|
||||
<div id="container">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<div id="main">
|
||||
<h1 class="title">client_test example program</h1>
|
||||
|
||||
<p>Client test is a, more or less, complete bittorrent client. It lacks most
|
||||
settings and you can't start or stop torrents once you've started it. All
|
||||
the settings are hardcoded. The commandline arguments are:</p>
|
||||
<pre class="literal-block">
|
||||
client_test <filename1.torrent> <filename2.torrent> ...
|
||||
</pre>
|
||||
<p>You can start any number of torrent downloads/seeds via the commandline.
|
||||
If one argument starts with <tt class="docutils literal"><span class="pre">http://</span></tt> it is interpreted as a tracker
|
||||
announce url, and it expects an info-hash as the next argument. The info-hash
|
||||
has to be hex-encoded. For example: <tt class="docutils literal">2410d4554d5ed856d69f426c38791673c59f4418</tt>.
|
||||
If you pass an announce url and info-hash, a torrent-less download is started.
|
||||
It relies on that at least one peer on the tracker is running a libtorrent based
|
||||
client and has the metadata (.torrent file). The metadata extension in
|
||||
libtorrent will then download it from that peer (or from those peers if more
|
||||
than one).</p>
|
||||
<p>While running, the <tt class="docutils literal">client_test</tt> sample will look something like this:</p>
|
||||
<img alt="client_test.png" src="client_test.png" />
|
||||
<p>The commands available in the client are:</p>
|
||||
<ul class="simple">
|
||||
<li><tt class="docutils literal">q</tt> quits the client (there will be a delay while the client waits
|
||||
for tracker responses)</li>
|
||||
<li><tt class="docutils literal">l</tt> toggle log. Will display the log at the bottom, informing about
|
||||
tracker and peer events.</li>
|
||||
<li><tt class="docutils literal">i</tt> toggles torrent info. Will show the peer list for each torrent.</li>
|
||||
<li><tt class="docutils literal">d</tt> toggle download info. Will show the block list for each torrent,
|
||||
showing downloaded and requested blocks.</li>
|
||||
<li><tt class="docutils literal">p</tt> pause all torrents.</li>
|
||||
<li><tt class="docutils literal">u</tt> unpause all torrents.</li>
|
||||
<li><tt class="docutils literal">r</tt> force tracker reannounce for all torrents.</li>
|
||||
<li><tt class="docutils literal">f</tt> toggle show file progress. Displays a list of all files and the
|
||||
download progress for each file.</li>
|
||||
</ul>
|
||||
<p>The list at the bottom (shown if you press <tt class="docutils literal">d</tt>) shows which blocks has
|
||||
been requested from which peer. The green background means that it has been
|
||||
downloaded. It shows that fast peers will prefer to request whole pieces
|
||||
instead of dowloading parts of pieces. It may make it easier to determine
|
||||
which peer that sent the corrupt data if a piece fails the hash test.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,136 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>libtorrent manual</title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<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@libtorrent.org">arvid@libtorrent.org</a></td></tr>
|
||||
<tr><th class="docinfo-name">Version:</th>
|
||||
<td>1.1.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="#contributing-to-libtorrent" id="id1">contributing to libtorrent</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="contributing-to-libtorrent">
|
||||
<h1>contributing to libtorrent</h1>
|
||||
<p>There are several ways to contribute to libtorrent at various levels. Any help is
|
||||
much appreciated. If you're interested in something libtorrent related that's not
|
||||
enumerated on this page, please contact <a class="reference external" href="mailto:arvid@libtorrent.org">arvid@libtorrent.org</a> or the <a class="reference external" href="http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss">mailing list</a>.</p>
|
||||
<ol class="arabic">
|
||||
<li><dl class="first docutils">
|
||||
<dt>Testing</dt>
|
||||
<dd><p class="first">This is not just limited to finding bugs and ways to reproduce crashes, but also
|
||||
sub-optimal behavior is certain scenarios and finding ways to reproduce those. Please
|
||||
report any issue to the bug tracker at <a class="reference external" href="https://github.com/arvidn/libtorrent/issues">github</a>.</p>
|
||||
<p class="last">New features that need testing are streaming (<tt class="docutils literal">set_piece_deadline()</tt>), the different
|
||||
choking algorithms (especially the new BitTyrant choker), the disk cache options (such
|
||||
as <tt class="docutils literal">explicit_cache</tt>).</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
</ol>
|
||||
<ol class="arabic" start="2">
|
||||
<li><dl class="first docutils">
|
||||
<dt>Documentation</dt>
|
||||
<dd><p class="first last">Finding typos or outdated sections in the documentation. Contributing documentation
|
||||
based on your own experience and experimentation with the library or with BitTorrent
|
||||
in general. Non-reference documentation is very much welcome as well, higher level
|
||||
descriptions on how to configure libtorrent for various situations for instance.
|
||||
The reference documentation for libtorrent is generated from the header files.
|
||||
For updates, please submit a <a class="reference external" href="https://github.com/arvidn/libtorrent">pull request</a>.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li><dl class="first docutils">
|
||||
<dt>Code</dt>
|
||||
<dd><p class="first">Contributing code for new features or bug-fixes is highly welcome. If you're interested
|
||||
in adding a feature but not sure where to start, please contact the <a class="reference external" href="http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss">mailing list</a> or
|
||||
<tt class="docutils literal">#libtorrent</tt> @ <tt class="docutils literal">irc.freenode.net</tt>. For proposed fixes or udpates, please
|
||||
submit a <a class="reference external" href="https://github.com/arvidn/libtorrent">pull request</a>.</p>
|
||||
<p class="last">New features might be better support for integrating with other services, new choking
|
||||
algorithms, seeding policies, ports to new platforms etc.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
</ol>
|
||||
<p>For an overview of the internals of libtorrent, see the <a class="reference external" href="hacking.html">hacking</a> page.</p>
|
||||
<p>For outstanding things to do, see the <a class="reference external" href="todo.html">todo list</a>.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,148 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title></title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.css" />
|
||||
<style type="text/css">
|
||||
/* Hides from IE-mac \*/
|
||||
* html pre { height: 1%; }
|
||||
/* End hide from IE-mac */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document">
|
||||
<div id="container">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<div id="main">
|
||||
|
||||
<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@libtorrent.org">arvid@libtorrent.org</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="section" id="mainline-dht-extensions">
|
||||
<h1>Mainline DHT extensions</h1>
|
||||
<p>libtorrent implements a few extensions to the Mainline DHT protocol.</p>
|
||||
<div class="section" id="get-peers-response">
|
||||
<h2>get_peers response</h2>
|
||||
<p>libtorrent always responds with <tt class="docutils literal">nodes</tt> to a get_peers request. If it has
|
||||
peers for the specified info-hash, it will return <tt class="docutils literal">values</tt> as well. This is
|
||||
because just because some peer announced to us, doesn't mean that we are
|
||||
among the 8 closest nodes of the info hash. libtorrent also keeps traversing
|
||||
nodes using get_peers until it has found the 8 closest ones, and then announces
|
||||
to those nodes.</p>
|
||||
</div>
|
||||
<div class="section" id="forward-compatibility">
|
||||
<h2>forward compatibility</h2>
|
||||
<p>In order to support future DHT messages, any message which is not recognized
|
||||
but has either an <tt class="docutils literal">info_hash</tt> or <tt class="docutils literal">target</tt> argument is interpreted as
|
||||
find node for that target. i.e. it returns nodes. This allows future messages
|
||||
to be properly forwarded by clients that don't understand them instead of
|
||||
being blocked.</p>
|
||||
</div>
|
||||
<div class="section" id="client-identification">
|
||||
<h2>client identification</h2>
|
||||
<p>In each DHT packet, an extra key is inserted named "v". This is a string
|
||||
describing the client and version used. This can help alot when debugging
|
||||
and finding errors in client implementations. The string is encoded as four
|
||||
characters, two characters describing the client and two characters interpreted
|
||||
as a binary number describing the client version.</p>
|
||||
<p>Currently known clients:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="65%" />
|
||||
<col width="35%" />
|
||||
</colgroup>
|
||||
<tbody valign="top">
|
||||
<tr><td>uTorrent</td>
|
||||
<td><tt class="docutils literal">UT</tt></td>
|
||||
</tr>
|
||||
<tr><td>libtorrent</td>
|
||||
<td><tt class="docutils literal">LT</tt></td>
|
||||
</tr>
|
||||
<tr><td>MooPolice</td>
|
||||
<td><tt class="docutils literal">MP</tt></td>
|
||||
</tr>
|
||||
<tr><td>GetRight</td>
|
||||
<td><tt class="docutils literal">GR</tt></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section" id="ipv6-support">
|
||||
<h2>IPv6 support</h2>
|
||||
<p><strong>This extension is superseeded by</strong> <a class="reference external" href="http://bittorrent.org/beps/bep_0032.html">BEP 32</a>.</p>
|
||||
<p>The DHT messages that don't support IPv6 are the <tt class="docutils literal">nodes</tt> replies.
|
||||
They encode all the contacts as 6 bytes packed together in sequence in a
|
||||
string. The problem is that IPv6 endpoints cannot be encoded as 6 bytes, but
|
||||
needs 18 bytes. The extension libtorrent applies is to add another key, called
|
||||
<tt class="docutils literal">nodes2</tt>.</p>
|
||||
<p><tt class="docutils literal">nodes2</tt> may be present in replies that contains a <tt class="docutils literal">nodes</tt> key. It is encoded
|
||||
as a list of strings. Each string represents one contact and is encoded as 20
|
||||
bytes node-id and then a variable length encoded IP address (6 bytes in IPv4 case
|
||||
and 18 bytes in IPv6 case).</p>
|
||||
<p>As an optimization, libtorrent does not include the extra key in case there are
|
||||
only IPv4 nodes present.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,435 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>BitTorrent extension for DHT RSS feeds</title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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="bittorrent-extension-for-dht-rss-feeds">
|
||||
<div id="container">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<div id="main">
|
||||
<h1 class="title">BitTorrent extension for DHT RSS feeds</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@libtorrent.org">arvid@libtorrent.org</a></td></tr>
|
||||
<tr><th class="docinfo-name">Version:</th>
|
||||
<td>1.1.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="#terminology" id="id1">terminology</a></li>
|
||||
<li><a class="reference internal" href="#linked-lists" id="id2">linked lists</a></li>
|
||||
<li><a class="reference internal" href="#skip-lists" id="id3">skip lists</a></li>
|
||||
<li><a class="reference internal" href="#list-head" id="id4">list-head</a></li>
|
||||
<li><a class="reference internal" href="#messages" id="id5">messages</a><ul>
|
||||
<li><a class="reference internal" href="#requesting-items" id="id6">requesting items</a></li>
|
||||
<li><a class="reference internal" href="#request-item-response" id="id7">request item response</a></li>
|
||||
<li><a class="reference internal" href="#announcing-items" id="id8">announcing items</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#re-announcing" id="id9">re-announcing</a></li>
|
||||
<li><a class="reference internal" href="#timeouts" id="id10">timeouts</a></li>
|
||||
<li><a class="reference internal" href="#rss-feeds" id="id11">RSS feeds</a><ul>
|
||||
<li><a class="reference internal" href="#example" id="id12">example</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#rss-feed-uri-scheme" id="id13">RSS feed URI scheme</a></li>
|
||||
<li><a class="reference internal" href="#rationale" id="id14">rationale</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>This proposal has been superseded by the <a class="reference external" href="dht_store.html">dht_put</a> feature. This may
|
||||
still be implemented on top of that.</p>
|
||||
<p>This is a proposal for an extension to the BitTorrent DHT to allow
|
||||
for decentralized RSS feed like functionality.</p>
|
||||
<p>The intention is to allow the creation of repositories of torrents
|
||||
where only a single identity has the authority to add new content. For
|
||||
this repository to be robust against network failures and resilient
|
||||
to attacks at the source.</p>
|
||||
<p>The target ID under which the repository is stored in the DHT, is the
|
||||
SHA-1 hash of a feed name and the 512 bit public key. This private key
|
||||
in this pair MUST be used to sign every item stored in the repository.
|
||||
Every message that contain signed items MUST also include this key, to
|
||||
allow the receiver to verify the key itself against the target ID as well
|
||||
as the validity of the signatures of the items. Every recipient of a
|
||||
message with feed items in it MUST verify both the validity of the public
|
||||
key against the target ID it is stored under, as well as the validity of
|
||||
the signatures of each individual item.</p>
|
||||
<p>As with normal DHT announces, the write-token mechanism is used to
|
||||
prevent IP spoof attacks.</p>
|
||||
<div class="section" id="terminology">
|
||||
<h1>terminology</h1>
|
||||
<p>In this document, a <em>storage node</em> refers to the node in the DHT to which
|
||||
an item is being announce. A <em>subscribing node</em> refers to a node which
|
||||
makes look ups in the DHT to find the storage nodes, to request items
|
||||
from them.</p>
|
||||
</div>
|
||||
<div class="section" id="linked-lists">
|
||||
<h1>linked lists</h1>
|
||||
<p>Items are chained together in a geneal singly linked list. A linked
|
||||
list does not necessarily contain RSS items, and no RSS related items
|
||||
are mandatory. However, RSS items will be used as examples in this BEP:</p>
|
||||
<pre class="literal-block">
|
||||
key = SHA1(name + key)
|
||||
+---------+
|
||||
| head | key = SHA1(bencode(item))
|
||||
| +---------+ +---------+
|
||||
| | next |-------->| item | key = SHA1(bencode(item))
|
||||
| | key | | +---------+ +---------+
|
||||
| | name | | | next |------->| item |
|
||||
| | seq | | | key | | +---------+
|
||||
| | ... | | | ... | | | next |--->0
|
||||
| +---------+ | +---------+ | | key |
|
||||
| sig | | sig | | | ... |
|
||||
+---------+ +---------+ | +---------+
|
||||
| sig |
|
||||
+---------+
|
||||
</pre>
|
||||
<p>The <tt class="docutils literal">next</tt> pointer is at least 20 byte ID in the DHT key space pointing to where the next
|
||||
item in the list is announced. The list is terminated with an ID of all zeroes.</p>
|
||||
<p>The ID an items is announced to is determined by the SHA1 hash of the bencoded representation
|
||||
of the item iteself. This contains all fields in the item, except the signature.
|
||||
The only mandatory fields in an item are <tt class="docutils literal">next</tt>, <tt class="docutils literal">key</tt> and <tt class="docutils literal">sig</tt>.</p>
|
||||
<p>The <tt class="docutils literal">key</tt> field MUST match the public key of the list head node. The <tt class="docutils literal">sig</tt> field
|
||||
MUST be the signature of the bencoded representation of <tt class="docutils literal">item</tt> or <tt class="docutils literal">head</tt> (whichever
|
||||
is included in the message).</p>
|
||||
<p>All subscribers MUST verify that the item is announced under the correct DHT key
|
||||
and MUST verify the signature is valid and MUST verify the public key is the same
|
||||
as the list-head. If a node fails any of these checks, it must be ignored and the
|
||||
chain of items considered terminated.</p>
|
||||
<p>Each item holds a bencoded dictionary with arbitrary keys, except two mandatory keys:
|
||||
<tt class="docutils literal">next</tt> and <tt class="docutils literal">key</tt>. The signature <tt class="docutils literal">sig</tt> is transferred outside of this dictionary
|
||||
and is the signature of all of it. An implementation should stora any arbitrary keys that
|
||||
are announced to an item, within reasonable restriction such as nesting, size and numeric
|
||||
range of integers.</p>
|
||||
</div>
|
||||
<div class="section" id="skip-lists">
|
||||
<h1>skip lists</h1>
|
||||
<p>The <tt class="docutils literal">next</tt> key stored in the list head and the items is a string of at least length
|
||||
20 bytes, it may be any length divisible by 20. Each 20 bytes are the ID of the next
|
||||
item in the list, the item 2 hops away, 4 hops away, 8 hops away, and so on. For
|
||||
simplicity, only the first ID (1 hop) in the <tt class="docutils literal">next</tt> field is illustrated above.</p>
|
||||
<p>A publisher of an item SHOULD include as many IDs in the <tt class="docutils literal">next</tt> field as the remaining
|
||||
size of the list warrants, within reason.</p>
|
||||
<p>These skip lists allow for parallelized lookups of items and also makes it more efficient
|
||||
to search for specific items. It also mitigates breaking lists missing some items.</p>
|
||||
<p>Figure of the skip list in the first list item:</p>
|
||||
<pre class="literal-block">
|
||||
n Item0 Item1 Item2 Item3 Item4 Item5 Item6 Item7 Item8 Item9 Item10
|
||||
0 O----->
|
||||
20 O------------>
|
||||
40 O-------------------------->
|
||||
60 O------------------------------------------------------>
|
||||
</pre>
|
||||
<p><em>n</em> refers to the byte offset into the <tt class="docutils literal">next</tt> field.</p>
|
||||
</div>
|
||||
<div class="section" id="list-head">
|
||||
<h1>list-head</h1>
|
||||
<p>The list head item is special in that it can be updated, without changing its
|
||||
DHT key. This is required to prepend new items to the linked list. To authenticate
|
||||
that only the original publisher can update the head, the whole linked list head
|
||||
is signed. In order to avoid a malicious node to overwrite the list head with an old
|
||||
version, the sequence number <tt class="docutils literal">seq</tt> must be monotonically increasing for each update,
|
||||
and a node hosting the list node MUST not downgrade a list head from a higher sequence
|
||||
number to a lower one, only upgrade.</p>
|
||||
<p>The list head's DHT key (which it is announced to) MUST be the SHA1 hash of the name
|
||||
(<tt class="docutils literal">n</tt>) and <tt class="docutils literal">key</tt> fields concatenated.</p>
|
||||
<p>Any node MUST reject any list head which is announced under any other ID.</p>
|
||||
</div>
|
||||
<div class="section" id="messages">
|
||||
<h1>messages</h1>
|
||||
<p>These are the messages to deal with linked lists.</p>
|
||||
<p>The <tt class="docutils literal">id</tt> field in these messages has the same semantics as the standard DHT messages,
|
||||
i.e. the node ID of the node sending the message, to maintain the structure of the DHT
|
||||
network.</p>
|
||||
<p>The <tt class="docutils literal">token</tt> field also has the same semantics as the standard DHT message <tt class="docutils literal">get_peers</tt>
|
||||
and <tt class="docutils literal">announce_peer</tt>, when requesting an item and to write an item respectively.</p>
|
||||
<p><tt class="docutils literal">nodes</tt> and <tt class="docutils literal">nodes6</tt> has the same semantics as in its <tt class="docutils literal">get_peers</tt> response.</p>
|
||||
<div class="section" id="requesting-items">
|
||||
<h2>requesting items</h2>
|
||||
<p>This message can be used to request both a list head and a list item. When requesting
|
||||
a list head, the <tt class="docutils literal">n</tt> (name) field MUST be specified. When requesting a list item the
|
||||
<tt class="docutils literal">n</tt> field is not required.</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"a":
|
||||
{
|
||||
"id": <em><20 byte ID of sending node></em>,
|
||||
"key": <em><64 byte public curve25519 key for this list></em>,
|
||||
"n": <em><list name></em>
|
||||
"target": <em><target-id for 'head' or 'item'></em>
|
||||
},
|
||||
"q": "get_item",
|
||||
"t": <em><transaction-id></em>,
|
||||
"y": "q",
|
||||
}
|
||||
</pre>
|
||||
<p>When requesting a list-head the <tt class="docutils literal">target</tt> MUST always be SHA-1(<em>feed_name</em> + <em>public_key</em>).
|
||||
<tt class="docutils literal">target</tt> is the target node ID the item was written to.</p>
|
||||
<p>The <tt class="docutils literal">n</tt> field is the name of the list. If specified, It MUST be UTF-8 encoded string
|
||||
and it MUST match the name of the feed in the receiving node.</p>
|
||||
</div>
|
||||
<div class="section" id="request-item-response">
|
||||
<h2>request item response</h2>
|
||||
<p>This is the format of a response of a list head:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"r":
|
||||
{
|
||||
"head":
|
||||
{
|
||||
"key": <em><64 byte public curve25519 key for this list></em>,
|
||||
"next": <em><20 bytes item ID></em>,
|
||||
"n": <em><name of the linked list></em>,
|
||||
"seq": <em><monotonically increasing sequence number></em>
|
||||
},
|
||||
"sig": <em><curve25519 signature of 'head' entry (in bencoded form)></em>,
|
||||
"id": <em><20 byte id of sending node></em>,
|
||||
"token": <em><write-token></em>,
|
||||
"nodes": <em><n * compact IPv4-port pair></em>,
|
||||
"nodes6": <em><n * compact IPv6-port pair></em>
|
||||
},
|
||||
"t": <em><transaction-id></em>,
|
||||
"y": "r",
|
||||
}
|
||||
</pre>
|
||||
<p>This is the format of a response of a list item:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"r":
|
||||
{
|
||||
"item":
|
||||
{
|
||||
"key": <em><64 byte public curve25519 key for this list></em>,
|
||||
"next": <em><20 bytes item ID></em>,
|
||||
...
|
||||
},
|
||||
"sig": <em><curve25519 signature of 'item' entry (in bencoded form)></em>,
|
||||
"id": <em><20 byte id of sending node></em>,
|
||||
"token": <em><write-token></em>,
|
||||
"nodes": <em><n * compact IPv4-port pair></em>,
|
||||
"nodes6": <em><n * compact IPv6-port pair></em>
|
||||
},
|
||||
"t": <em><transaction-id></em>,
|
||||
"y": "r",
|
||||
}
|
||||
</pre>
|
||||
<p>A client receiving a <tt class="docutils literal">get_item</tt> response MUST verify the signature in the <tt class="docutils literal">sig</tt>
|
||||
field against the bencoded representation of the <tt class="docutils literal">item</tt> field, using the <tt class="docutils literal">key</tt> as
|
||||
the public key. The <tt class="docutils literal">key</tt> MUST match the public key of the feed.</p>
|
||||
<p>The <tt class="docutils literal">item</tt> dictionary MAY contain arbitrary keys, and all keys MUST be stored for
|
||||
items.</p>
|
||||
</div>
|
||||
<div class="section" id="announcing-items">
|
||||
<h2>announcing items</h2>
|
||||
<p>The message format for announcing a list head:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"a":
|
||||
{
|
||||
"head":
|
||||
{
|
||||
"key": <em><64 byte public curve25519 key for this list></em>,
|
||||
"next": <em><20 bytes item ID></em>,
|
||||
"n": <em><name of the linked list></em>,
|
||||
"seq": <em><monotonically increasing sequence number></em>
|
||||
},
|
||||
"sig": <em><curve25519 signature of 'head' entry (in bencoded form)></em>,
|
||||
"id": <em><20 byte node-id of origin node></em>,
|
||||
"target": <em><target-id as derived from public key and name></em>,
|
||||
"token": <em><write-token as obtained by previous request></em>
|
||||
},
|
||||
"y": "q",
|
||||
"q": "announce_item",
|
||||
"t": <em><transaction-id></em>
|
||||
}
|
||||
</pre>
|
||||
<p>The message format for announcing a list item:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"a":
|
||||
{
|
||||
"item":
|
||||
{
|
||||
"key": <em><64 byte public curve25519 key for this list></em>,
|
||||
"next": <em><20 bytes item ID></em>,
|
||||
...
|
||||
},
|
||||
"sig": <em><curve25519 signature of 'item' entry (in bencoded form)></em>,
|
||||
"id": <em><20 byte node-id of origin node></em>,
|
||||
"target": <em><target-id as derived from item dict></em>,
|
||||
"token": <em><write-token as obtained by previous request></em>
|
||||
},
|
||||
"y": "q",
|
||||
"q": "announce_item",
|
||||
"t": <em><transaction-id></em>
|
||||
}
|
||||
</pre>
|
||||
<p>A storage node MAY reject items and heads whose bencoded representation is
|
||||
greater than 1024 bytes.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="re-announcing">
|
||||
<h1>re-announcing</h1>
|
||||
<p>In order to keep feeds alive, subscriber nodes SHOULD help out in announcing
|
||||
items they have downloaded to the DHT.</p>
|
||||
<p>Every subscriber node SHOULD store items in long term storage, across sessions,
|
||||
in order to keep items alive for as long as possible, with as few sources as possible.</p>
|
||||
<p>Subscribers to a feed SHOULD also announce items that they know of, to the feed.
|
||||
Since a feed may have many subscribers and many items, subscribers should re-announce
|
||||
items according to the following algorithm.</p>
|
||||
<pre class="literal-block">
|
||||
1. pick one random item (<em>i</em>) from the local repository (except
|
||||
items already announced this round)
|
||||
2. If all items in the local repository have been announced
|
||||
2.1 terminate
|
||||
3. look up item <em>i</em> in the DHT
|
||||
4. If fewer than 8 nodes returned the item
|
||||
4.1 announce <em>i</em> to the DHT
|
||||
4.2 goto 1
|
||||
</pre>
|
||||
<p>This ensures a balanced load on the DHT while still keeping items alive</p>
|
||||
</div>
|
||||
<div class="section" id="timeouts">
|
||||
<h1>timeouts</h1>
|
||||
<p>Items SHOULD be announced to the DHT every 30 minutes. A storage node MAY time
|
||||
out an item after 60 minutes of no one announcing it.</p>
|
||||
<p>A storing node MAY extend the timeout when it receives a request for it. Since
|
||||
items are immutable, the data doesn't go stale. Therefore it doesn't matter if
|
||||
the storing node no longer is in the set of the 8 closest nodes.</p>
|
||||
</div>
|
||||
<div class="section" id="rss-feeds">
|
||||
<h1>RSS feeds</h1>
|
||||
<p>For RSS feeds, following keys are mandatory in the list item's <tt class="docutils literal">item</tt> dictionary.</p>
|
||||
<dl class="docutils">
|
||||
<dt>ih</dt>
|
||||
<dd>The torrent's info hash</dd>
|
||||
<dt>size</dt>
|
||||
<dd>The size (in bytes) of all files the torrent</dd>
|
||||
<dt>n</dt>
|
||||
<dd>name of the torrent</dd>
|
||||
</dl>
|
||||
<div class="section" id="example">
|
||||
<h2>example</h2>
|
||||
<p>This is an example of an <tt class="docutils literal">announce_item</tt> message:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"a":
|
||||
{
|
||||
"item":
|
||||
{
|
||||
"key": "6bc1de5443d1a7c536cdf69433ac4a7163d3c63e2f9c92d
|
||||
78f6011cf63dbcd5b638bbc2119cdad0c57e4c61bc69ba5e2c08
|
||||
b918c2db8d1848cf514bd9958d307",
|
||||
"info-hash": "7ea94c240691311dc0916a2a91eb7c3db2c6f3e4",
|
||||
"size": 24315329,
|
||||
"n": "my stuff",
|
||||
"next": "c68f29156404e8e0aas8761ef5236bcagf7f8f2e"
|
||||
}
|
||||
"sig": <em><signature></em>
|
||||
"id": "b46989156404e8e0acdb751ef553b210ef77822e",
|
||||
"target": "b4692ef0005639e86d7165bf378474107bf3a762"
|
||||
"token": "23ba"
|
||||
},
|
||||
"y": "q",
|
||||
"q": "announce_item",
|
||||
"t": "a421"
|
||||
}
|
||||
</pre>
|
||||
<p>Strings are printed in hex for printability, but actual encoding is binary.</p>
|
||||
<p>Note that <tt class="docutils literal">target</tt> is in fact SHA1 hash of the same data the signature <tt class="docutils literal">sig</tt>
|
||||
is the signature of, i.e.:</p>
|
||||
<pre class="literal-block">
|
||||
d9:info-hash20:7ea94c240691311dc0916a2a91eb7c3db2c6f3e43:key64:6bc1de5443d1
|
||||
a7c536cdf69433ac4a7163d3c63e2f9c92d78f6011cf63dbcd5b638bbc2119cdad0c57e4c61
|
||||
bc69ba5e2c08b918c2db8d1848cf514bd9958d3071:n8:my stuff4:next20:c68f29156404
|
||||
e8e0aas8761ef5236bcagf7f8f2e4:sizei24315329ee
|
||||
</pre>
|
||||
<p>(note that binary data is printed as hex)</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="rss-feed-uri-scheme">
|
||||
<h1>RSS feed URI scheme</h1>
|
||||
<p>The proposed URI scheme for DHT feeds is:</p>
|
||||
<pre class="literal-block">
|
||||
magnet:?xt=btfd:<em><base16-curve25519-public-key></em> &dn= <em><feed name></em>
|
||||
</pre>
|
||||
<p>Note that a difference from regular torrent magnet links is the <strong>btfd</strong>
|
||||
versus <strong>btih</strong> used in regular magnet links to torrents.</p>
|
||||
<p>The <em>feed name</em> is mandatory since it is used in the request and when
|
||||
calculating the target ID.</p>
|
||||
</div>
|
||||
<div class="section" id="rationale">
|
||||
<h1>rationale</h1>
|
||||
<p>The reason to use <a class="reference external" href="http://cr.yp.to/ecdh.html">curve25519</a> instead of, for instance, RSA is compactness. According to
|
||||
<a class="reference external" href="http://cr.yp.to/">http://cr.yp.to/</a>, curve25519 is free from patent claims and there are open implementations
|
||||
in both C and Java.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,305 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>BitTorrent DHT security extension</title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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="bittorrent-dht-security-extension">
|
||||
<div id="container">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<div id="main">
|
||||
<h1 class="title">BitTorrent DHT security extension</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@libtorrent.org">arvid@libtorrent.org</a></td></tr>
|
||||
<tr><th class="docinfo-name">Version:</th>
|
||||
<td>1.1.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="#id1" id="id2">BitTorrent DHT security extension</a></li>
|
||||
<li><a class="reference internal" href="#considerations" id="id3">considerations</a></li>
|
||||
<li><a class="reference internal" href="#node-id-restriction" id="id4">Node ID restriction</a></li>
|
||||
<li><a class="reference internal" href="#bootstrapping" id="id5">bootstrapping</a></li>
|
||||
<li><a class="reference internal" href="#rationale" id="id6">rationale</a></li>
|
||||
<li><a class="reference internal" href="#enforcement" id="id7">enforcement</a></li>
|
||||
<li><a class="reference internal" href="#backwards-compatibility-and-transition" id="id8">backwards compatibility and transition</a></li>
|
||||
<li><a class="reference internal" href="#forward-compatibility" id="id9">forward compatibility</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="id1">
|
||||
<h1>BitTorrent DHT security extension</h1>
|
||||
<p>The purpose of this extension is to make it harder to launch a few
|
||||
specific attacks against the BitTorrent DHT and also to make it harder
|
||||
to snoop the network.</p>
|
||||
<p>Specifically the attack this extension intends to make harder is launching
|
||||
8 or more DHT nodes which node-IDs selected close to a specific target
|
||||
info-hash, in order to become the main nodes hosting peers for it. Currently
|
||||
this is very easy to do and lets the attacker not only see all the traffic
|
||||
related to this specific info-hash but also block access to it by other
|
||||
peers.</p>
|
||||
<p>The proposed guard against this is to enforce restrictions on which node-ID
|
||||
a node can choose, based on its external IP address.</p>
|
||||
</div>
|
||||
<div class="section" id="considerations">
|
||||
<h1>considerations</h1>
|
||||
<p>One straight forward scheme to tie the node ID to an IP would be to hash
|
||||
the IP and force the node ID to share the prefix of that hash. One main
|
||||
draw back of this approach is that an entities control over the DHT key
|
||||
space grows linearly with its control over the IP address space.</p>
|
||||
<p>In order to successfully launch an attack, you just need to find 8 IPs
|
||||
whose hash will be <em>closest</em> to the target info-hash. Given the current
|
||||
size of the DHT, that is quite likely to be possible by anyone in control
|
||||
of a /8 IP block.</p>
|
||||
<p>The size of the DHT is approximately 8.4 million nodes. This is estmiated
|
||||
by observing that a typical routing table typically has about 20 of its
|
||||
top routing table buckets full. That means the key space is dense enough
|
||||
to contain 8 nodes for every combination of the 20 top bits of node IDs.</p>
|
||||
<blockquote>
|
||||
<tt class="docutils literal">2^20 * 8 = 8388608</tt></blockquote>
|
||||
<p>By controlling that many IP addresses, an attacker could snoop any info-hash.
|
||||
By controlling 8 times that many IP addresses, an attacker could actually
|
||||
take over any info-hash.</p>
|
||||
<p>With IPv4, snooping would require a /8 IP block, giving access to 16.7 million
|
||||
Ips.</p>
|
||||
<p>Another problem with hashing the IP is that multiple users behind a NAT are
|
||||
forced to run their DHT nodes on the same node ID.</p>
|
||||
</div>
|
||||
<div class="section" id="node-id-restriction">
|
||||
<h1>Node ID restriction</h1>
|
||||
<p>In order to avoid the number node IDs controlled to grow linearly by the number
|
||||
of IPs, as well as allowing more than one node ID per external IP, the node
|
||||
ID can be restricted at each class level of the IP.</p>
|
||||
<p>Another important property of the restriction put on node IDs is that the
|
||||
distribution of the IDs remoain uniform. This is why CRC32C (Castagnoli) was
|
||||
chosen as the hash function.</p>
|
||||
<p>The expression to calculate a valid ID prefix (from an IPv4 address) is:</p>
|
||||
<pre class="literal-block">
|
||||
crc32c((ip & 0x030f3fff) | (r << 29))
|
||||
</pre>
|
||||
<p>And for an IPv6 address (<tt class="docutils literal">ip</tt> is the high 64 bits of the address):</p>
|
||||
<pre class="literal-block">
|
||||
crc32c((ip & 0x0103070f1f3f7fff) | (r << 61))
|
||||
</pre>
|
||||
<p><tt class="docutils literal">r</tt> is a random number in the range [0, 7]. The resulting integer,
|
||||
representing the masked IP address is supposed to be big-endian before
|
||||
hashed. The "|" operator means bit-wise OR.</p>
|
||||
<p>The details of implementing this is to evaluate the expression, store the
|
||||
result in a big endian 64 bit integer and hash those 8 bytes with CRC32C.</p>
|
||||
<p>The first (most significant) 21 bits of the node ID used in the DHT MUST
|
||||
match the first 21 bits of the resulting hash. The last byte of the hash MUST
|
||||
match the random number (<tt class="docutils literal">r</tt>) used to generate the hash.</p>
|
||||
<img alt="ip_id_v4.png" src="ip_id_v4.png" />
|
||||
<img alt="ip_id_v6.png" src="ip_id_v6.png" />
|
||||
<p>Example code code for calculating a valid node ID:</p>
|
||||
<pre class="literal-block">
|
||||
uint8_t* ip; // our external IPv4 or IPv6 address (network byte order)
|
||||
int num_octets; // the number of octets to consider in ip (4 or 8)
|
||||
uint8_t node_id[20]; // resulting node ID
|
||||
|
||||
uint8_t v4_mask[] = { 0x03, 0x0f, 0x3f, 0xff };
|
||||
uint8_t v6_mask[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
|
||||
uint8_t* mask = num_octets == 4 ? v4_mask : v6_mask;
|
||||
|
||||
for (int i = 0; i < num_octets; ++i)
|
||||
ip[i] &= mask[i];
|
||||
|
||||
uint32_t rand = std::rand() & 0xff;
|
||||
uint8_t r = rand & 0x7;
|
||||
ip[0] |= r << 5;
|
||||
|
||||
uint32_t crc = 0;
|
||||
crc = crc32c(crc, ip, num_octets);
|
||||
|
||||
// only take the top 21 bits from crc
|
||||
node_id[0] = (crc >> 24) & 0xff;
|
||||
node_id[1] = (crc >> 16) & 0xff;
|
||||
node_id[2] = ((crc >> 8) & 0xf8) | (std::rand() & 0x7);
|
||||
for (int i = 3; i < 19; ++i) node_id[i] = std::rand();
|
||||
node_id[19] = rand;
|
||||
</pre>
|
||||
<p>test vectors:</p>
|
||||
<pre class="literal-block">
|
||||
IP rand example node ID
|
||||
============ ===== ==========================================
|
||||
124.31.75.21 1 <strong>5fbfbf</strong> f10c5d6a4ec8a88e4c6ab4c28b95eee4 <strong>01</strong>
|
||||
21.75.31.124 86 <strong>5a3ce9</strong> c14e7a08645677bbd1cfe7d8f956d532 <strong>56</strong>
|
||||
65.23.51.170 22 <strong>a5d432</strong> 20bc8f112a3d426c84764f8c2a1150e6 <strong>16</strong>
|
||||
84.124.73.14 65 <strong>1b0321</strong> dd1bb1fe518101ceef99462b947a01ff <strong>41</strong>
|
||||
43.213.53.83 90 <strong>e56f6c</strong> bf5b7c4be0237986d5243b87aa6d5130 <strong>5a</strong>
|
||||
</pre>
|
||||
<p>The bold parts of the node ID are the important parts. The rest are
|
||||
random numbers. The last bold number of each row has only its most significant
|
||||
bit pulled from the CRC32C function. The lower 3 bits are random.</p>
|
||||
</div>
|
||||
<div class="section" id="bootstrapping">
|
||||
<h1>bootstrapping</h1>
|
||||
<p>In order to set ones initial node ID, the external IP needs to be known. This
|
||||
is not a trivial problem. With this extension, <em>all</em> DHT responses SHOULD include
|
||||
a <em>top-level</em> field called <tt class="docutils literal">ip</tt>, containing a compact binary representation of
|
||||
the requestor's IP and port. That is big endian IP followed by 2 bytes of big endian
|
||||
port.</p>
|
||||
<p>The IP portion is the same byte sequence used to verify the node ID.</p>
|
||||
<p>It is important that the <tt class="docutils literal">ip</tt> field is in the top level dictionary. Nodes that
|
||||
enforce the node-ID will respond with an error message ("y": "e", "e": { ... }),
|
||||
whereas a node that supports this extension but without enforcing it will respond
|
||||
with a normal reply ("y": "r", "r": { ... }).</p>
|
||||
<p>A DHT node which receives an <tt class="docutils literal">ip</tt> result in a request SHOULD consider restarting
|
||||
its DHT node with a new node ID, taking this IP into account. Since a single node
|
||||
can not be trusted, there should be some mechanism to determine whether or
|
||||
not the node has a correct understanding of its external IP or not. This could
|
||||
be done by voting, or only restart the DHT once at least a certain number of
|
||||
nodes, from separate searches, tells you your node ID is incorrect.</p>
|
||||
</div>
|
||||
<div class="section" id="rationale">
|
||||
<h1>rationale</h1>
|
||||
<p>The choice of using CRC32C instead of a more traditional cryptographic hash
|
||||
function is justified primarily of these reasons:</p>
|
||||
<ol class="arabic simple">
|
||||
<li>it is a fast function</li>
|
||||
<li>produces well distributed results</li>
|
||||
<li>there is no need for the hash function to be one-way (the input set is
|
||||
so small that any hash function could be reversed).</li>
|
||||
<li>CRC32C (Castagnoli) is supported in hardware by SSE 4.2, which can
|
||||
significantly speed up computation</li>
|
||||
</ol>
|
||||
<p>There are primarily two tests run on SHA-1 and CRC32C to establish the
|
||||
distribution of results. The first one is the number of bits in the output
|
||||
set that contain every possible combination of bits. The CRC32C function
|
||||
has a longer such prefix in its output than SHA-1. This means nodes will still
|
||||
have well uniformly distributed IDs, even when IP addresses in use are not
|
||||
uniformly distributed.</p>
|
||||
<p>The following graph illustrate a few different hash functions with regard
|
||||
to this property.</p>
|
||||
<img alt="complete_bit_prefixes.png" src="complete_bit_prefixes.png" />
|
||||
<p>This test takes into account IP addresses that are not globally routable, i.e.
|
||||
reserved for local networks, multicast and other things. It also takes into
|
||||
account that some /8 blocks are not in use by end-users and exremely unlikely
|
||||
to ever run a DHT node. This makes the results likely to be very similar to
|
||||
what we would see in the wild.</p>
|
||||
<p>These results indicate that CRC32C provides the best uniformity in the results
|
||||
in terms of bit prefixes where all possibilities are represented, and that
|
||||
no more than 21 bits should be used from the result. If more than 21 bits
|
||||
were to be used, there would be certain node IDs that would be impossible to
|
||||
have, which would make routing sub-optimal.</p>
|
||||
<p>The second test is more of a sanity test for the uniform distribution property.
|
||||
The target space (32 bit interger) is divided up into 1000 buckets. Every valid
|
||||
IP and <tt class="docutils literal">r</tt> input is run through the algorithm and the result is put in the
|
||||
bucket it falls in. The expectation is that each bucket has roughly an equal
|
||||
number of results falling into it. The following graph shows the resulting
|
||||
histogram, comparing SHA-1 and CRC32C.</p>
|
||||
<img alt="hash_distribution.png" src="hash_distribution.png" />
|
||||
<p>The source code for these tests can be found <a class="reference external" href="https://github.com/arvidn/hash_complete_prefix">here</a>.</p>
|
||||
<p>The reason to use CRC32C instead of the CRC32 implemented by zlib is that
|
||||
Intel CPUs have hardware support for the CRC32C calculations. The input
|
||||
being exactly 4 bytes is also deliberate, to make it fit in a single
|
||||
instruction.</p>
|
||||
</div>
|
||||
<div class="section" id="enforcement">
|
||||
<h1>enforcement</h1>
|
||||
<p>Once enforced, write tokens from peers whose node ID does not match its external
|
||||
IP should be considered dropped. In other words, a peer that uses a non-matching
|
||||
ID MUST never be used to store information on, regardless of which request. In the
|
||||
original DHT specification only <tt class="docutils literal">announce_peer</tt> stores data in the network,
|
||||
but any future extension which stores data in the network SHOULD use the same
|
||||
restriction.</p>
|
||||
<p>Any peer on a local network address is exempt from this node ID verification.
|
||||
This includes the following IP blocks:</p>
|
||||
<dl class="docutils">
|
||||
<dt>10.0.0.0/8</dt>
|
||||
<dd>reserved for local networks</dd>
|
||||
<dt>172.16.0.0/12</dt>
|
||||
<dd>reserved for local networks</dd>
|
||||
<dt>192.168.0.0/16</dt>
|
||||
<dd>reserved for local networks</dd>
|
||||
<dt>169.254.0.0/16</dt>
|
||||
<dd>reserved for self-assigned IPs</dd>
|
||||
<dt>127.0.0.0/8</dt>
|
||||
<dd>reserved for loopback</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="section" id="backwards-compatibility-and-transition">
|
||||
<h1>backwards compatibility and transition</h1>
|
||||
<p>During some transition period, this restriction should not be enforced, and
|
||||
peers whose node ID does not match this formula relative to their external IP
|
||||
should not be blocked.</p>
|
||||
<p>Requests from peers whose node ID does not match their external IP should
|
||||
always be serviced, even after the transition period. The attack this protects
|
||||
from is storing data on an attacker's node, not servicing an attackers request.</p>
|
||||
</div>
|
||||
<div class="section" id="forward-compatibility">
|
||||
<h1>forward compatibility</h1>
|
||||
<p>If the total size of the DHT grows to the point where the inherent size limit
|
||||
in this proposal is too small, the modulus constants can be updated in a new
|
||||
proposal, and another transition period where both sets of modulus constants
|
||||
are accepted.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,538 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>BitTorrent extension for arbitrary DHT store</title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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="bittorrent-extension-for-arbitrary-dht-store">
|
||||
<div id="container">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<div id="main">
|
||||
<h1 class="title">BitTorrent extension for arbitrary DHT store</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@libtorrent.org">arvid@libtorrent.org</a></td></tr>
|
||||
<tr><th class="docinfo-name">Version:</th>
|
||||
<td>1.1.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="#terminology" id="id3">terminology</a></li>
|
||||
<li><a class="reference internal" href="#messages" id="id4">messages</a></li>
|
||||
<li><a class="reference internal" href="#immutable-items" id="id5">immutable items</a><ul>
|
||||
<li><a class="reference internal" href="#put-message" id="id6">put message</a></li>
|
||||
<li><a class="reference internal" href="#get-message" id="id7">get message</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#mutable-items" id="id8">mutable items</a><ul>
|
||||
<li><a class="reference internal" href="#id1" id="id9">put message</a></li>
|
||||
<li><a class="reference internal" href="#cas" id="id10">CAS</a></li>
|
||||
<li><a class="reference internal" href="#response" id="id11">response</a></li>
|
||||
<li><a class="reference internal" href="#errors" id="id12">errors</a></li>
|
||||
<li><a class="reference internal" href="#id2" id="id13">get message</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#signature-verification" id="id14">signature verification</a></li>
|
||||
<li><a class="reference internal" href="#expiration" id="id15">expiration</a></li>
|
||||
<li><a class="reference internal" href="#test-vectors" id="id16">test vectors</a><ul>
|
||||
<li><a class="reference internal" href="#test-1-mutable" id="id17">test 1 (mutable)</a></li>
|
||||
<li><a class="reference internal" href="#test-2-mutable-with-salt" id="id18">test 2 (mutable with salt)</a></li>
|
||||
<li><a class="reference internal" href="#test-3-immutable" id="id19">test 3 (immutable)</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#resources" id="id20">resources</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>This is a proposal for an extension to the BitTorrent DHT to allow
|
||||
storing and retrieving of arbitrary data.</p>
|
||||
<p>It supports both storing <em>immutable</em> items, where the key is
|
||||
the SHA-1 hash of the data itself, and <em>mutable</em> items, where
|
||||
the key is the public key of the key pair used to sign the data.</p>
|
||||
<p>There are two new proposed messages, <tt class="docutils literal">put</tt> and <tt class="docutils literal">get</tt>.</p>
|
||||
<div class="section" id="terminology">
|
||||
<h1>terminology</h1>
|
||||
<p>In this document, a <em>storage node</em> refers to the node in the DHT to which
|
||||
an item is being announced and stored on. A <em>requesting node</em> refers to
|
||||
a node which makes look-ups in the DHT to find the storage nodes, to
|
||||
request items from them, and possibly re-announce those items to keep them
|
||||
alive.</p>
|
||||
</div>
|
||||
<div class="section" id="messages">
|
||||
<h1>messages</h1>
|
||||
<p>The proposed new messages <tt class="docutils literal">get</tt> and <tt class="docutils literal">put</tt> are similar to the existing
|
||||
<tt class="docutils literal">get_peers</tt> and <tt class="docutils literal">announce_peer</tt>.</p>
|
||||
<p>Responses to <tt class="docutils literal">get</tt> should always include <tt class="docutils literal">nodes</tt> and <tt class="docutils literal">nodes6</tt>. Those
|
||||
fields have the same semantics as in its <tt class="docutils literal">get_peers</tt> response. It should also
|
||||
include a write token, <tt class="docutils literal">token</tt>, with the same semantics as int <tt class="docutils literal">get_peers</tt>.
|
||||
The write token MAY be tied specifically to the key which <tt class="docutils literal">get</tt> requested.
|
||||
i.e. the <tt class="docutils literal">token</tt> can only be used to store values under that one key. It may
|
||||
also be tied to the node ID and IP address of the requesting node.</p>
|
||||
<p>The <tt class="docutils literal">id</tt> field in these messages has the same semantics as the standard DHT
|
||||
messages, i.e. the node ID of the node sending the message, to maintain the
|
||||
structure of the DHT network.</p>
|
||||
<p>The <tt class="docutils literal">token</tt> field also has the same semantics as the standard DHT message
|
||||
<tt class="docutils literal">get_peers</tt> and <tt class="docutils literal">announce_peer</tt>, when requesting an item and to write an
|
||||
item respectively.</p>
|
||||
<p>The <tt class="docutils literal">k</tt> field is the 32 byte ed25519 public key, which the signature can be
|
||||
authenticated with. When looking up a mutable item, the <tt class="docutils literal">target</tt> field MUST be
|
||||
the SHA-1 hash of this key concatenated with the <tt class="docutils literal">salt</tt>, if present.</p>
|
||||
<p>The distinction between storing mutable and immutable items is the inclusion of
|
||||
a public key, a sequence number, signature and an optional salt (<tt class="docutils literal">k</tt>, <tt class="docutils literal">seq</tt>,
|
||||
<tt class="docutils literal">sig</tt> and <tt class="docutils literal">salt</tt>).</p>
|
||||
<p><tt class="docutils literal">get</tt> requests for mutable items and immutable items cannot be distinguished
|
||||
from eachother. An implementation can either store mutable and immutable items
|
||||
in the same hash table internally, or in separate ones and potentially do two
|
||||
lookups for <tt class="docutils literal">get</tt> requests.</p>
|
||||
<p>The <tt class="docutils literal">v</tt> field is the <em>value</em> to be stored. It is allowed to be any bencoded
|
||||
type (list, dict, string or integer). When it's being hashed (for verifying its
|
||||
signature or to calculate its key), its flattened, bencoded, form is used. It is
|
||||
important to use the verbatim bencoded representation as it appeared in the
|
||||
message. decoding and then re-encoding bencoded structures is not necessarily an
|
||||
identity operation.</p>
|
||||
<p>Storing nodes MAY reject <tt class="docutils literal">put</tt> requests where the bencoded form of <tt class="docutils literal">v</tt> is
|
||||
longer than 1000 bytes. In other words, it's not safe to assume storing more
|
||||
than 1000 bytes will succeed.</p>
|
||||
</div>
|
||||
<div class="section" id="immutable-items">
|
||||
<h1>immutable items</h1>
|
||||
<p>Immutable items are stored under their SHA-1 hash, and since they cannot be
|
||||
modified, there is no need to authenticate the origin of them. This makes
|
||||
immutable items simple.</p>
|
||||
<p>A node making a lookup SHOULD verify the data it receives from the network, to
|
||||
verify that its hash matches the target that was looked up.</p>
|
||||
<div class="section" id="put-message">
|
||||
<h2>put message</h2>
|
||||
<p>Request:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"a":
|
||||
{
|
||||
"id": <em><20 byte id of sending node (string)></em>,
|
||||
"v": <em><any bencoded type, whose encoded size <= 1000></em>
|
||||
},
|
||||
"t": <em><transaction-id (string)></em>,
|
||||
"y": "q",
|
||||
"q": "put"
|
||||
}
|
||||
</pre>
|
||||
<p>Response:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"r": { "id": <em><20 byte id of sending node (string)></em> },
|
||||
"t": <em><transaction-id (string)></em>,
|
||||
"y": "r",
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="get-message">
|
||||
<h2>get message</h2>
|
||||
<p>Request:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"a":
|
||||
{
|
||||
"id": <em><20 byte id of sending node (string)></em>,
|
||||
"target": <em><SHA-1 hash of item (string)></em>,
|
||||
},
|
||||
"t": <em><transaction-id (string)></em>,
|
||||
"y": "q",
|
||||
"q": "get"
|
||||
}
|
||||
</pre>
|
||||
<p>Response:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"r":
|
||||
{
|
||||
"id": <em><20 byte id of sending node (string)></em>,
|
||||
"token": <em><write token (string)></em>,
|
||||
"v": <em><any bencoded type whose SHA-1 hash matches 'target'></em>,
|
||||
"nodes": <em><IPv4 nodes close to 'target'></em>,
|
||||
"nodes6": <em><IPv6 nodes close to 'target'></em>
|
||||
},
|
||||
"t": <em><transaction-id></em>,
|
||||
"y": "r",
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="mutable-items">
|
||||
<h1>mutable items</h1>
|
||||
<p>Mutable items can be updated, without changing their DHT keys. To authenticate
|
||||
that only the original publisher can update an item, it is signed by a private
|
||||
key generated by the original publisher. The target ID mutable items are stored
|
||||
under is the SHA-1 hash of the public key (as it appears in the <tt class="docutils literal">put</tt>
|
||||
message).</p>
|
||||
<p>In order to avoid a malicious node to overwrite the list head with an old
|
||||
version, the sequence number <tt class="docutils literal">seq</tt> must be monotonically increasing for each
|
||||
update, and a node hosting the list node MUST not downgrade a list head from a
|
||||
higher sequence number to a lower one, only upgrade. The sequence number SHOULD
|
||||
not exceed <tt class="docutils literal">MAX_INT64</tt>, (i.e. <tt class="docutils literal">0x7fffffffffffffff</tt>. A client MAY reject any
|
||||
message with a sequence number exceeding this. A client MAY also reject any
|
||||
message with a negative sequence number.</p>
|
||||
<p>The signature is a 64 byte ed25519 signature of the bencoded sequence number
|
||||
concatenated with the <tt class="docutils literal">v</tt> key. e.g. something like this:</p>
|
||||
<pre class="literal-block">
|
||||
3:seqi4e1:v12:Hello world!
|
||||
</pre>
|
||||
<p>If the <tt class="docutils literal">salt</tt> key is present and non-empty, the salt string must be included
|
||||
in what's signed. Note that if <tt class="docutils literal">salt</tt> is specified and an empty string, it is
|
||||
as if it was not specified and nothing in addition to the sequence number and
|
||||
the data is signed. The salt string may not be longer than 64 bytes.</p>
|
||||
<p>When a salt is included in what is signed, the key <tt class="docutils literal">salt</tt> with the value of
|
||||
the key is prepended in its bencoded form. For example, if <tt class="docutils literal">salt</tt> is "foobar",
|
||||
the buffer to be signed is:</p>
|
||||
<pre class="literal-block">
|
||||
4:salt6:foobar3:seqi4e1:v12:Hello world!
|
||||
</pre>
|
||||
<div class="section" id="id1">
|
||||
<h2>put message</h2>
|
||||
<p>Request:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"a":
|
||||
{
|
||||
"cas": <em><optional expected seq-nr (int)></em>,
|
||||
"id": <em><20 byte id of sending node (string)></em>,
|
||||
"k": <em><ed25519 public key (32 bytes string)></em>,
|
||||
"salt": <em><optional salt to be appended to "k" when hashing (string)></em>
|
||||
"seq": <em><monotonically increasing sequence number (integer)></em>,
|
||||
"sig": <em><ed25519 signature (64 bytes string)></em>,
|
||||
"token": <em><write-token (string)></em>,
|
||||
"v": <em><any bencoded type, whose encoded size < 1000></em>
|
||||
},
|
||||
"t": <em><transaction-id (string)></em>,
|
||||
"y": "q",
|
||||
"q": "put"
|
||||
}
|
||||
</pre>
|
||||
<p>Storing nodes receiving a <tt class="docutils literal">put</tt> request where <tt class="docutils literal">seq</tt> is lower than or equal
|
||||
to what's already stored on the node, MUST reject the request. If the sequence
|
||||
number is equal, and the value is also the same, the node SHOULD reset its
|
||||
timeout counter.</p>
|
||||
<p>If the sequence number in the <tt class="docutils literal">put</tt> message is lower than the sequence number
|
||||
associated with the currently stored value, the storing node MAY return an error
|
||||
message with code 302 (see error codes below).</p>
|
||||
<p>Note that this request does not contain a target hash. The target hash under
|
||||
which this blob is stored is implied by the <tt class="docutils literal">k</tt> argument. The key is the SHA-1
|
||||
hash of the key (<tt class="docutils literal">k</tt>).</p>
|
||||
<p>In order to support a single key being used to store separate items in the DHT,
|
||||
an optional <tt class="docutils literal">salt</tt> can be specified in the <tt class="docutils literal">put</tt> request of mutable items.
|
||||
If the salt entry is not present, it can be assumed to be an empty string, and
|
||||
its semantics should be identical as specifying a salt key with an empty string.
|
||||
The salt can be any binary string (but probably most conveniently a hash of
|
||||
something). This string is appended to the key, as specified in the <tt class="docutils literal">k</tt> field,
|
||||
when calculating the key to store the blob under (i.e. the key <tt class="docutils literal">get</tt> requests
|
||||
specify to retrieve this data).</p>
|
||||
<p>This lets a single entity, with a single key, publish any number of unrelated
|
||||
items, with a single key that readers can verify. This is useful if the
|
||||
publisher doesn't know ahead of time how many different items are to be
|
||||
published. It can distribute a single public key for users to authenticate the
|
||||
published blobs.</p>
|
||||
<p>Note that the salt is not returned in the response to a <tt class="docutils literal">get</tt> request. This
|
||||
is intentional. When issuing a <tt class="docutils literal">get</tt> request for an item is expected to
|
||||
know what the salt is (because it is part of what the target ID that is being
|
||||
looked up is derived from). There is no need to repeat it back for bystanders
|
||||
to see.</p>
|
||||
</div>
|
||||
<div class="section" id="cas">
|
||||
<h2>CAS</h2>
|
||||
<p>CAS is short for <em>compare and swap</em>, it has similar semantics as CAS CPU
|
||||
instructions. It is used to avoid race conditions when multiple nodes are
|
||||
writing to the same slot in the DHT.</p>
|
||||
<p>The <tt class="docutils literal">cas</tt> field is optional. If present it specifies the sequence number of
|
||||
the data blob being overwritten by the put. When present, the storing node
|
||||
MUST compare this number to the current sequence number it has stored under
|
||||
this key. Only if the <tt class="docutils literal">cas</tt> matches the stored sequence number is the put
|
||||
performed. If it mismatches, the store fails and an error is returned.
|
||||
See <a class="reference internal" href="#errors">errors</a> below.</p>
|
||||
<p>The <tt class="docutils literal">cas</tt> field only applies to mutable puts. If there is no current
|
||||
value, the <tt class="docutils literal">cas</tt> field SHOULD be ignored.</p>
|
||||
<p>When sending a <tt class="docutils literal">put</tt> request to a node that did not return any data for the
|
||||
<tt class="docutils literal">get</tt>, the <tt class="docutils literal">cas</tt> field SHOULD NOT be included.</p>
|
||||
</div>
|
||||
<div class="section" id="response">
|
||||
<h2>response</h2>
|
||||
<p>Response:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"r": { "id": <em><20 byte id of sending node (string)></em> },
|
||||
"t": <em><transaction-id (string)></em>,
|
||||
"y": "r",
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="errors">
|
||||
<h2>errors</h2>
|
||||
<p>If the store fails for any reason an error message is returned instead of the
|
||||
message template above, i.e. one where "y" is "e" and "e" is a tuple of
|
||||
[error-code, message]). Failures include <tt class="docutils literal">cas</tt> mismatches and the sequence
|
||||
number is outdated.</p>
|
||||
<p>The error message (as specified by <a class="reference external" href="http://www.bittorrent.org/beps/bep_0005.html">BEP5</a>) looks like this:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"e": [ <em><error-code (integer)></em>, <em><error-string (string)></em> ],
|
||||
"t": <em><transaction-id (string)></em>,
|
||||
"y": "e",
|
||||
}
|
||||
</pre>
|
||||
<p>In addition to the error codes defined in <a class="reference external" href="http://www.bittorrent.org/beps/bep_0005.html">BEP5</a>, this specification defines
|
||||
some additional error codes.</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="29%" />
|
||||
<col width="71%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">error-code</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>205</td>
|
||||
<td>message (<tt class="docutils literal">v</tt> field)
|
||||
too big.</td>
|
||||
</tr>
|
||||
<tr><td>206</td>
|
||||
<td>invalid signature</td>
|
||||
</tr>
|
||||
<tr><td>207</td>
|
||||
<td>salt (<tt class="docutils literal">salt</tt> field)
|
||||
too big.</td>
|
||||
</tr>
|
||||
<tr><td>301</td>
|
||||
<td>the CAS hash mismatched,
|
||||
re-read value and try
|
||||
again.</td>
|
||||
</tr>
|
||||
<tr><td>302</td>
|
||||
<td>sequence number less than
|
||||
current.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>An implementation MUST emit 301 errors if the cas mismatches. This is a
|
||||
critical feature in synchronization of multiple agents sharing an immutable
|
||||
item.</p>
|
||||
</div>
|
||||
<div class="section" id="id2">
|
||||
<h2>get message</h2>
|
||||
<p>Request:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"a":
|
||||
{
|
||||
"id": <em><20 byte id of sending node (string)></em>,
|
||||
"target:" <em><20 byte SHA-1 hash of public key and salt (string)></em>
|
||||
},
|
||||
"t": <em><transaction-id (string)></em>,
|
||||
"y": "q",
|
||||
"q": "get"
|
||||
}
|
||||
</pre>
|
||||
<p>Response:</p>
|
||||
<pre class="literal-block">
|
||||
{
|
||||
"r":
|
||||
{
|
||||
"id": <em><20 byte id of sending node (string)></em>,
|
||||
"k": <em><ed25519 public key (32 bytes string)></em>,
|
||||
"nodes": <em><IPv4 nodes close to 'target'></em>,
|
||||
"nodes6": <em><IPv6 nodes close to 'target'></em>,
|
||||
"seq": <em><monotonically increasing sequence number (integer)></em>,
|
||||
"sig": <em><ed25519 signature (64 bytes string)></em>,
|
||||
"token": <em><write-token (string)></em>,
|
||||
"v": <em><any bencoded type, whose encoded size <= 1000></em>
|
||||
},
|
||||
"t": <em><transaction-id (string)></em>,
|
||||
"y": "r",
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="signature-verification">
|
||||
<h1>signature verification</h1>
|
||||
<p>In order to make it maximally difficult to attack the bencoding parser, signing
|
||||
and verification of the value and sequence number should be done as follows:</p>
|
||||
<ol class="arabic simple">
|
||||
<li>encode value and sequence number separately</li>
|
||||
<li>concatenate ("4:salt" <em>length-of-salt</em> ":" <em>salt</em>) "3:seqi" <em>seq</em>
|
||||
"e1:v" <em>len</em> ":" and the encoded value.
|
||||
sequence number 1 of value "Hello World!" would be converted to:
|
||||
"3:seqi1e1:v12:Hello World!". In this way it is not possible to convince a
|
||||
node that part of the length is actually part of the sequence number even if
|
||||
the parser contains certain bugs. Furthermore it is not possible to have a
|
||||
verification failure if a bencoding serializer alters the order of entries in
|
||||
the dictionary. The salt is in parenthesis because it is optional. It is only
|
||||
prepended if a non-empty salt is specified in the <tt class="docutils literal">put</tt> request.</li>
|
||||
<li>sign or verify the concatenated string</li>
|
||||
</ol>
|
||||
<p>On the storage node, the signature MUST be verified before accepting the store
|
||||
command. The data MUST be stored under the SHA-1 hash of the public key (as it
|
||||
appears in the bencoded dict) and the salt (if present).</p>
|
||||
<p>On the requesting nodes, the key they get back from a <tt class="docutils literal">get</tt> request MUST be
|
||||
verified to hash to the target ID the lookup was made for, as well as verifying
|
||||
the signature. If any of these fail, the response SHOULD be considered invalid.</p>
|
||||
</div>
|
||||
<div class="section" id="expiration">
|
||||
<h1>expiration</h1>
|
||||
<p>Without re-announcement, these items MAY expire in 2 hours. In order
|
||||
to keep items alive, they SHOULD be re-announced once an hour.</p>
|
||||
<p>Any node that's interested in keeping a blob in the DHT alive may announce it.
|
||||
It would simply repeat the signature for a mutable put without having the
|
||||
private key.</p>
|
||||
</div>
|
||||
<div class="section" id="test-vectors">
|
||||
<h1>test vectors</h1>
|
||||
<div class="section" id="test-1-mutable">
|
||||
<h2>test 1 (mutable)</h2>
|
||||
<p>value:</p>
|
||||
<pre class="literal-block">
|
||||
12:Hello World!
|
||||
</pre>
|
||||
<p>buffer being signed:</p>
|
||||
<pre class="literal-block">
|
||||
3:seqi1e1:v12:Hello World!
|
||||
</pre>
|
||||
<p>public key:</p>
|
||||
<pre class="literal-block">
|
||||
77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548
|
||||
</pre>
|
||||
<p>private key:</p>
|
||||
<pre class="literal-block">
|
||||
e06d3183d14159228433ed599221b80bd0a5ce8352e4bdf0262f76786ef1c74d
|
||||
b7e7a9fea2c0eb269d61e3b38e450a22e754941ac78479d6c54e1faf6037881d
|
||||
</pre>
|
||||
<p><strong>target ID</strong>:</p>
|
||||
<pre class="literal-block">
|
||||
4a533d47ec9c7d95b1ad75f576cffc641853b750
|
||||
</pre>
|
||||
<p><strong>signature</strong>:</p>
|
||||
<pre class="literal-block">
|
||||
305ac8aeb6c9c151fa120f120ea2cfb923564e11552d06a5d856091e5e853cff
|
||||
1260d3f39e4999684aa92eb73ffd136e6f4f3ecbfda0ce53a1608ecd7ae21f01
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="test-2-mutable-with-salt">
|
||||
<h2>test 2 (mutable with salt)</h2>
|
||||
<p>value:</p>
|
||||
<pre class="literal-block">
|
||||
12:Hello World!
|
||||
</pre>
|
||||
<p>salt:</p>
|
||||
<pre class="literal-block">
|
||||
foobar
|
||||
</pre>
|
||||
<p>buffer being signed:</p>
|
||||
<pre class="literal-block">
|
||||
4:salt6:foobar3:seqi1e1:v12:Hello World!
|
||||
</pre>
|
||||
<p>public key:</p>
|
||||
<pre class="literal-block">
|
||||
77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548
|
||||
</pre>
|
||||
<p>private key:</p>
|
||||
<pre class="literal-block">
|
||||
e06d3183d14159228433ed599221b80bd0a5ce8352e4bdf0262f76786ef1c74d
|
||||
b7e7a9fea2c0eb269d61e3b38e450a22e754941ac78479d6c54e1faf6037881d
|
||||
</pre>
|
||||
<p><strong>target ID</strong>:</p>
|
||||
<pre class="literal-block">
|
||||
411eba73b6f087ca51a3795d9c8c938d365e32c1
|
||||
</pre>
|
||||
<p><strong>signature</strong>:</p>
|
||||
<pre class="literal-block">
|
||||
6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17d
|
||||
df9a8a7104b1258f30bed3787e6cb896fca78c58f8e03b5f18f14951a87d9a08
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="test-3-immutable">
|
||||
<h2>test 3 (immutable)</h2>
|
||||
<p>value:</p>
|
||||
<pre class="literal-block">
|
||||
12:Hello World!
|
||||
</pre>
|
||||
<p><strong>target ID</strong>:</p>
|
||||
<pre class="literal-block">
|
||||
e5f96f6f38320f0f33959cb4d3d656452117aadb
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="resources">
|
||||
<h1>resources</h1>
|
||||
<p>Libraries that implement ed25519 DSA:</p>
|
||||
<ul class="simple">
|
||||
<li><a class="reference external" href="http://nacl.cr.yp.to/">NaCl</a></li>
|
||||
<li><a class="reference external" href="https://github.com/jedisct1/libsodium">libsodium</a></li>
|
||||
<li><a class="reference external" href="https://github.com/nightcracker/ed25519">nightcracker's ed25519</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 5.2 KiB |
|
@ -1,763 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>libtorrent Examples</title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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-examples">
|
||||
<div id="container">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<div id="main">
|
||||
<h1 class="title">libtorrent Examples</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@libtorrent.org">arvid@libtorrent.org</a></td></tr>
|
||||
<tr><th class="docinfo-name">Version:</th>
|
||||
<td>1.1.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="#examples" id="id2">examples</a><ul>
|
||||
<li><a class="reference internal" href="#simple-client" id="id3">simple client</a></li>
|
||||
<li><a class="reference internal" href="#make-torrent" id="id4">make_torrent</a></li>
|
||||
<li><a class="reference internal" href="#dump-torrent" id="id5">dump_torrent</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="examples">
|
||||
<h1>examples</h1>
|
||||
<p>Except for the example programs in this manual, there's also a bigger example
|
||||
of a (little bit) more complete client, <tt class="docutils literal">client_test</tt>. There are separate
|
||||
instructions for how to use it <a class="reference external" href="client_test.html">here</a> if you'd like to try it. Note that building
|
||||
<tt class="docutils literal">client_test</tt> also requires boost.regex and boost.program_options library.</p>
|
||||
<div class="section" id="simple-client">
|
||||
<h2>simple client</h2>
|
||||
<p>This is a simple client. It doesn't have much output to keep it simple:</p>
|
||||
<pre class="code c++ literal-block">
|
||||
<span class="comment preproc">#include <stdlib.h>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include "libtorrent/entry.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
</span>
|
||||
<span class="keyword type">int</span> <span class="name function">main</span><span class="punctuation">(</span><span class="keyword type">int</span> <span class="name">argc</span><span class="punctuation">,</span> <span class="keyword type">char</span><span class="operator">*</span> <span class="name">argv</span><span class="punctuation">[])</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="name">libtorrent</span><span class="punctuation">;</span>
|
||||
<span class="keyword">namespace</span> <span class="name">lt</span> <span class="operator">=</span> <span class="name">libtorrent</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">argc</span> <span class="operator">!=</span> <span class="literal number integer">2</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fputs</span><span class="punctuation">(</span><span class="literal string">"usage: ./simple_client torrent-file</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"to stop the client, press return.</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">stderr</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">settings_pack</span> <span class="name">sett</span><span class="punctuation">;</span>
|
||||
<span class="name">sett</span><span class="punctuation">.</span><span class="name">set_str</span><span class="punctuation">(</span><span class="name">settings_pack</span><span class="operator">::</span><span class="name">listen_interfaces</span><span class="punctuation">,</span> <span class="literal string">"0.0.0.0:6881"</span><span class="punctuation">);</span>
|
||||
<span class="name">lt</span><span class="operator">::</span><span class="name">session</span> <span class="name">s</span><span class="punctuation">(</span><span class="name">sett</span><span class="punctuation">);</span>
|
||||
<span class="name">error_code</span> <span class="name">ec</span><span class="punctuation">;</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">ec</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"failed to open listen socket: %s</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">ec</span><span class="punctuation">.</span><span class="name">message</span><span class="punctuation">().</span><span class="name">c_str</span><span class="punctuation">());</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="name">add_torrent_params</span> <span class="name">p</span><span class="punctuation">;</span>
|
||||
<span class="name">p</span><span class="punctuation">.</span><span class="name">save_path</span> <span class="operator">=</span> <span class="literal string">"./"</span><span class="punctuation">;</span>
|
||||
<span class="name">p</span><span class="punctuation">.</span><span class="name">ti</span> <span class="operator">=</span> <span class="name">boost</span><span class="operator">::</span><span class="name">make_shared</span><span class="operator"><</span><span class="name">torrent_info</span><span class="operator">></span><span class="punctuation">(</span><span class="name">std</span><span class="operator">::</span><span class="name">string</span><span class="punctuation">(</span><span class="name">argv</span><span class="punctuation">[</span><span class="literal number integer">1</span><span class="punctuation">]),</span> <span class="name">boost</span><span class="operator">::</span><span class="name">ref</span><span class="punctuation">(</span><span class="name">ec</span><span class="punctuation">),</span> <span class="literal number integer">0</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">ec</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"%s</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">ec</span><span class="punctuation">.</span><span class="name">message</span><span class="punctuation">().</span><span class="name">c_str</span><span class="punctuation">());</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="name">s</span><span class="punctuation">.</span><span class="name">add_torrent</span><span class="punctuation">(</span><span class="name">p</span><span class="punctuation">,</span> <span class="name">ec</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">ec</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"%s</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">ec</span><span class="punctuation">.</span><span class="name">message</span><span class="punctuation">().</span><span class="name">c_str</span><span class="punctuation">());</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="comment single">// wait for the user to end
|
||||
</span> <span class="keyword type">char</span> <span class="name">a</span><span class="punctuation">;</span>
|
||||
<span class="name">scanf</span><span class="punctuation">(</span><span class="literal string">"%c</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="operator">&</span><span class="name">a</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">0</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="make-torrent">
|
||||
<h2>make_torrent</h2>
|
||||
<p>Shows how to create a torrent from a directory tree:</p>
|
||||
<pre class="code c++ literal-block">
|
||||
<span class="comment preproc">#include "libtorrent/entry.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/storage.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/file_pool.hpp"
|
||||
#include "libtorrent/hex.hpp" </span><span class="comment single">// for from_hex
|
||||
</span>
|
||||
<span class="comment preproc">#include <boost/bind.hpp>
|
||||
</span>
|
||||
<span class="comment preproc">#ifdef TORRENT_WINDOWS
|
||||
#include <direct.h> </span><span class="comment single">// for _getcwd
|
||||
</span><span class="comment preproc">#endif
|
||||
</span>
|
||||
<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="name">libtorrent</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="keyword type">int</span> <span class="name function">load_file</span><span class="punctuation">(</span><span class="name">std</span><span class="operator">::</span><span class="name">string</span> <span class="keyword">const</span><span class="operator">&</span> <span class="name">filename</span><span class="punctuation">,</span> <span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="keyword type">char</span><span class="operator">>&</span> <span class="name">v</span><span class="punctuation">,</span> <span class="name">libtorrent</span><span class="operator">::</span><span class="name">error_code</span><span class="operator">&</span> <span class="name">ec</span><span class="punctuation">,</span> <span class="keyword type">int</span> <span class="name">limit</span> <span class="operator">=</span> <span class="literal number integer">8000000</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">ec</span><span class="punctuation">.</span><span class="name">clear</span><span class="punctuation">();</span>
|
||||
<span class="keyword type">FILE</span><span class="operator">*</span> <span class="name">f</span> <span class="operator">=</span> <span class="name">fopen</span><span class="punctuation">(</span><span class="name">filename</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">(),</span> <span class="literal string">"rb"</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">f</span> <span class="operator">==</span> <span class="name builtin">NULL</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">ec</span><span class="punctuation">.</span><span class="name">assign</span><span class="punctuation">(</span><span class="name">errno</span><span class="punctuation">,</span> <span class="name">boost</span><span class="operator">::</span><span class="name">system</span><span class="operator">::</span><span class="name">system_category</span><span class="punctuation">());</span>
|
||||
<span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword type">int</span> <span class="name">r</span> <span class="operator">=</span> <span class="name">fseek</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">,</span> <span class="literal number integer">0</span><span class="punctuation">,</span> <span class="name">SEEK_END</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">r</span> <span class="operator">!=</span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">ec</span><span class="punctuation">.</span><span class="name">assign</span><span class="punctuation">(</span><span class="name">errno</span><span class="punctuation">,</span> <span class="name">boost</span><span class="operator">::</span><span class="name">system</span><span class="operator">::</span><span class="name">system_category</span><span class="punctuation">());</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="keyword type">long</span> <span class="name">s</span> <span class="operator">=</span> <span class="name">ftell</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">s</span> <span class="operator"><</span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">ec</span><span class="punctuation">.</span><span class="name">assign</span><span class="punctuation">(</span><span class="name">errno</span><span class="punctuation">,</span> <span class="name">boost</span><span class="operator">::</span><span class="name">system</span><span class="operator">::</span><span class="name">system_category</span><span class="punctuation">());</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">s</span> <span class="operator">></span> <span class="name">limit</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">2</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">r</span> <span class="operator">=</span> <span class="name">fseek</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">,</span> <span class="literal number integer">0</span><span class="punctuation">,</span> <span class="name">SEEK_SET</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">r</span> <span class="operator">!=</span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">ec</span><span class="punctuation">.</span><span class="name">assign</span><span class="punctuation">(</span><span class="name">errno</span><span class="punctuation">,</span> <span class="name">boost</span><span class="operator">::</span><span class="name">system</span><span class="operator">::</span><span class="name">system_category</span><span class="punctuation">());</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">v</span><span class="punctuation">.</span><span class="name">resize</span><span class="punctuation">(</span><span class="name">s</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">s</span> <span class="operator">==</span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">0</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">r</span> <span class="operator">=</span> <span class="name">fread</span><span class="punctuation">(</span><span class="operator">&</span><span class="name">v</span><span class="punctuation">[</span><span class="literal number integer">0</span><span class="punctuation">],</span> <span class="literal number integer">1</span><span class="punctuation">,</span> <span class="name">v</span><span class="punctuation">.</span><span class="name">size</span><span class="punctuation">(),</span> <span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">r</span> <span class="operator"><</span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">ec</span><span class="punctuation">.</span><span class="name">assign</span><span class="punctuation">(</span><span class="name">errno</span><span class="punctuation">,</span> <span class="name">boost</span><span class="operator">::</span><span class="name">system</span><span class="operator">::</span><span class="name">system_category</span><span class="punctuation">());</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">r</span> <span class="operator">!=</span> <span class="name">s</span><span class="punctuation">)</span> <span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">3</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="keyword">return</span> <span class="literal number integer">0</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">std</span><span class="operator">::</span><span class="name">string</span> <span class="name">branch_path</span><span class="punctuation">(</span><span class="name">std</span><span class="operator">::</span><span class="name">string</span> <span class="keyword">const</span><span class="operator">&</span> <span class="name">f</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">f</span><span class="punctuation">.</span><span class="name">empty</span><span class="punctuation">())</span> <span class="keyword">return</span> <span class="name">f</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="comment preproc">#ifdef TORRENT_WINDOWS
|
||||
</span> <span class="keyword">if</span> <span class="punctuation">(</span><span class="name">f</span> <span class="operator">==</span> <span class="literal string">"</span><span class="literal string escape">\\\\</span><span class="literal string">"</span><span class="punctuation">)</span> <span class="keyword">return</span> <span class="literal string">""</span><span class="punctuation">;</span>
|
||||
<span class="comment preproc">#endif
|
||||
</span> <span class="keyword">if</span> <span class="punctuation">(</span><span class="name">f</span> <span class="operator">==</span> <span class="literal string">"/"</span><span class="punctuation">)</span> <span class="keyword">return</span> <span class="literal string">""</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="keyword type">int</span> <span class="name">len</span> <span class="operator">=</span> <span class="name">f</span><span class="punctuation">.</span><span class="name">size</span><span class="punctuation">();</span>
|
||||
<span class="comment single">// if the last character is / or \ ignore it
|
||||
</span> <span class="keyword">if</span> <span class="punctuation">(</span><span class="name">f</span><span class="punctuation">[</span><span class="name">len</span><span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">]</span> <span class="operator">==</span> <span class="literal string char">'/'</span> <span class="operator">||</span> <span class="name">f</span><span class="punctuation">[</span><span class="name">len</span><span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">]</span> <span class="operator">==</span> <span class="literal string char">'\\'</span><span class="punctuation">)</span> <span class="operator">--</span><span class="name">len</span><span class="punctuation">;</span>
|
||||
<span class="keyword">while</span> <span class="punctuation">(</span><span class="name">len</span> <span class="operator">></span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="operator">--</span><span class="name">len</span><span class="punctuation">;</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">f</span><span class="punctuation">[</span><span class="name">len</span><span class="punctuation">]</span> <span class="operator">==</span> <span class="literal string char">'/'</span> <span class="operator">||</span> <span class="name">f</span><span class="punctuation">[</span><span class="name">len</span><span class="punctuation">]</span> <span class="operator">==</span> <span class="literal string char">'\\'</span><span class="punctuation">)</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">f</span><span class="punctuation">[</span><span class="name">len</span><span class="punctuation">]</span> <span class="operator">==</span> <span class="literal string char">'/'</span> <span class="operator">||</span> <span class="name">f</span><span class="punctuation">[</span><span class="name">len</span><span class="punctuation">]</span> <span class="operator">==</span> <span class="literal string char">'\\'</span><span class="punctuation">)</span> <span class="operator">++</span><span class="name">len</span><span class="punctuation">;</span>
|
||||
<span class="keyword">return</span> <span class="name">std</span><span class="operator">::</span><span class="name">string</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">(),</span> <span class="name">len</span><span class="punctuation">);</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="comment single">// do not include files and folders whose
|
||||
// name starts with a .
|
||||
</span><span class="keyword type">bool</span> <span class="name">file_filter</span><span class="punctuation">(</span><span class="name">std</span><span class="operator">::</span><span class="name">string</span> <span class="keyword">const</span><span class="operator">&</span> <span class="name">f</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">f</span><span class="punctuation">.</span><span class="name">empty</span><span class="punctuation">())</span> <span class="keyword">return</span> <span class="name builtin">false</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="keyword type">char</span> <span class="keyword">const</span><span class="operator">*</span> <span class="name">first</span> <span class="operator">=</span> <span class="name">f</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">();</span>
|
||||
<span class="keyword type">char</span> <span class="keyword">const</span><span class="operator">*</span> <span class="name">sep</span> <span class="operator">=</span> <span class="name">strrchr</span><span class="punctuation">(</span><span class="name">first</span><span class="punctuation">,</span> <span class="literal string char">'/'</span><span class="punctuation">);</span>
|
||||
<span class="comment preproc">#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
|
||||
</span> <span class="keyword type">char</span> <span class="keyword">const</span><span class="operator">*</span> <span class="name">altsep</span> <span class="operator">=</span> <span class="name">strrchr</span><span class="punctuation">(</span><span class="name">first</span><span class="punctuation">,</span> <span class="literal string char">'\\'</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">sep</span> <span class="operator">==</span> <span class="name builtin">NULL</span> <span class="operator">||</span> <span class="name">altsep</span> <span class="operator">></span> <span class="name">sep</span><span class="punctuation">)</span> <span class="name">sep</span> <span class="operator">=</span> <span class="name">altsep</span><span class="punctuation">;</span>
|
||||
<span class="comment preproc">#endif
|
||||
</span> <span class="comment single">// if there is no parent path, just set 'sep'
|
||||
</span> <span class="comment single">// to point to the filename.
|
||||
</span> <span class="comment single">// if there is a parent path, skip the '/' character
|
||||
</span> <span class="keyword">if</span> <span class="punctuation">(</span><span class="name">sep</span> <span class="operator">==</span> <span class="name builtin">NULL</span><span class="punctuation">)</span> <span class="name">sep</span> <span class="operator">=</span> <span class="name">first</span><span class="punctuation">;</span>
|
||||
<span class="keyword">else</span> <span class="operator">++</span><span class="name">sep</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="comment single">// return false if the first character of the filename is a .
|
||||
</span> <span class="keyword">if</span> <span class="punctuation">(</span><span class="name">sep</span><span class="punctuation">[</span><span class="literal number integer">0</span><span class="punctuation">]</span> <span class="operator">==</span> <span class="literal string char">'.'</span><span class="punctuation">)</span> <span class="keyword">return</span> <span class="name builtin">false</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"%s</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">f</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">());</span>
|
||||
<span class="keyword">return</span> <span class="name builtin">true</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword type">void</span> <span class="name">print_progress</span><span class="punctuation">(</span><span class="keyword type">int</span> <span class="name">i</span><span class="punctuation">,</span> <span class="keyword type">int</span> <span class="name">num</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"</span><span class="literal string escape">\r</span><span class="literal string">%d/%d"</span><span class="punctuation">,</span> <span class="name">i</span><span class="operator">+</span><span class="literal number integer">1</span><span class="punctuation">,</span> <span class="name">num</span><span class="punctuation">);</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword type">void</span> <span class="name">print_usage</span><span class="punctuation">()</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fputs</span><span class="punctuation">(</span><span class="literal string">"usage: make_torrent FILE [OPTIONS]</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"Generates a torrent file from the specified file</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"or directory and writes it to standard out</span><span class="literal string escape">\n\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"OPTIONS:</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"-m file generate a merkle hash tree torrent.</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" merkle torrents require client support</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" the resulting full merkle tree is written to</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" the specified file</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"-w url adds a web seed to the torrent with</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" the specified url</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"-t url adds the specified tracker to the</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" torrent. For multiple trackers, specify more</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" -t options</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"-c comment sets the comment to the specified string</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"-C creator sets the created-by field to the specified string</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"-p bytes enables padding files. Files larger</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" than bytes will be piece-aligned</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"-s bytes specifies a piece size for the torrent</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" This has to be a multiple of 16 kiB</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"-l Don't follow symlinks, instead encode them as</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" links in the torrent file</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"-o file specifies the output filename of the torrent file</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" If this is not specified, the torrent file is</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" printed to the standard out, except on windows</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" where the filename defaults to a.torrent</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"-r file add root certificate to the torrent, to verify</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" the HTTPS tracker</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"-S info-hash add a similar torrent by info-hash. The similar</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" torrent is expected to share some files with this one</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"-L collection add a collection name to this torrent. Other torrents</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" in the same collection is expected to share files</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" with this one.</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"-M make the torrent compatible with mutable torrents</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" this means aligning large files and pad them in order</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" for piece hashes to uniquely indentify a file without</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">" overlap</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="punctuation">,</span> <span class="name">stderr</span><span class="punctuation">);</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword type">int</span> <span class="name">main</span><span class="punctuation">(</span><span class="keyword type">int</span> <span class="name">argc</span><span class="punctuation">,</span> <span class="keyword type">char</span><span class="operator">*</span> <span class="name">argv</span><span class="punctuation">[])</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="name">libtorrent</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="name">std</span><span class="operator">::</span><span class="name">string</span> <span class="name">creator_str</span> <span class="operator">=</span> <span class="literal string">"libtorrent"</span><span class="punctuation">;</span>
|
||||
<span class="name">std</span><span class="operator">::</span><span class="name">string</span> <span class="name">comment_str</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">argc</span> <span class="operator"><</span> <span class="literal number integer">2</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">print_usage</span><span class="punctuation">();</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="comment preproc">#ifndef BOOST_NO_EXCEPTIONS
|
||||
</span> <span class="name">try</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="comment preproc">#endif
|
||||
</span> <span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="name">std</span><span class="operator">::</span><span class="name">string</span><span class="operator">></span> <span class="name">web_seeds</span><span class="punctuation">;</span>
|
||||
<span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="name">std</span><span class="operator">::</span><span class="name">string</span><span class="operator">></span> <span class="name">trackers</span><span class="punctuation">;</span>
|
||||
<span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="name">std</span><span class="operator">::</span><span class="name">string</span><span class="operator">></span> <span class="name">collections</span><span class="punctuation">;</span>
|
||||
<span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="name">sha1_hash</span><span class="operator">></span> <span class="name">similar</span><span class="punctuation">;</span>
|
||||
<span class="keyword type">int</span> <span class="name">pad_file_limit</span> <span class="operator">=</span> <span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="keyword type">int</span> <span class="name">piece_size</span> <span class="operator">=</span> <span class="literal number integer">0</span><span class="punctuation">;</span>
|
||||
<span class="keyword type">int</span> <span class="name">flags</span> <span class="operator">=</span> <span class="literal number integer">0</span><span class="punctuation">;</span>
|
||||
<span class="name">std</span><span class="operator">::</span><span class="name">string</span> <span class="name">root_cert</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="name">std</span><span class="operator">::</span><span class="name">string</span> <span class="name">outfile</span><span class="punctuation">;</span>
|
||||
<span class="name">std</span><span class="operator">::</span><span class="name">string</span> <span class="name">merklefile</span><span class="punctuation">;</span>
|
||||
<span class="comment preproc">#ifdef TORRENT_WINDOWS
|
||||
</span> <span class="comment single">// don't ever write binary data to the console on windows
|
||||
</span> <span class="comment single">// it will just be interpreted as text and corrupted
|
||||
</span> <span class="name">outfile</span> <span class="operator">=</span> <span class="literal string">"a.torrent"</span><span class="punctuation">;</span>
|
||||
<span class="comment preproc">#endif
|
||||
</span>
|
||||
<span class="keyword">for</span> <span class="punctuation">(</span><span class="keyword type">int</span> <span class="name">i</span> <span class="operator">=</span> <span class="literal number integer">2</span><span class="punctuation">;</span> <span class="name">i</span> <span class="operator"><</span> <span class="name">argc</span><span class="punctuation">;</span> <span class="operator">++</span><span class="name">i</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">][</span><span class="literal number integer">0</span><span class="punctuation">]</span> <span class="operator">!=</span> <span class="literal string char">'-'</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">print_usage</span><span class="punctuation">();</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword">switch</span> <span class="punctuation">(</span><span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">][</span><span class="literal number integer">1</span><span class="punctuation">])</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="keyword">case</span> <span class="literal string char">'w'</span><span class="operator">:</span>
|
||||
<span class="operator">++</span><span class="name">i</span><span class="punctuation">;</span>
|
||||
<span class="name">web_seeds</span><span class="punctuation">.</span><span class="name">push_back</span><span class="punctuation">(</span><span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">]);</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="keyword">case</span> <span class="literal string char">'t'</span><span class="operator">:</span>
|
||||
<span class="operator">++</span><span class="name">i</span><span class="punctuation">;</span>
|
||||
<span class="name">trackers</span><span class="punctuation">.</span><span class="name">push_back</span><span class="punctuation">(</span><span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">]);</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="keyword">case</span> <span class="literal string char">'M'</span><span class="operator">:</span>
|
||||
<span class="name">flags</span> <span class="operator">|=</span> <span class="name">create_torrent</span><span class="operator">::</span><span class="name">mutable_torrent_support</span><span class="punctuation">;</span>
|
||||
<span class="name">pad_file_limit</span> <span class="operator">=</span> <span class="literal number hex">0x4000</span><span class="punctuation">;</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="keyword">case</span> <span class="literal string char">'p'</span><span class="operator">:</span>
|
||||
<span class="operator">++</span><span class="name">i</span><span class="punctuation">;</span>
|
||||
<span class="name">pad_file_limit</span> <span class="operator">=</span> <span class="name">atoi</span><span class="punctuation">(</span><span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">]);</span>
|
||||
<span class="name">flags</span> <span class="operator">|=</span> <span class="name">create_torrent</span><span class="operator">::</span><span class="name">optimize</span><span class="punctuation">;</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="keyword">case</span> <span class="literal string char">'s'</span><span class="operator">:</span>
|
||||
<span class="operator">++</span><span class="name">i</span><span class="punctuation">;</span>
|
||||
<span class="name">piece_size</span> <span class="operator">=</span> <span class="name">atoi</span><span class="punctuation">(</span><span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">]);</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="keyword">case</span> <span class="literal string char">'m'</span><span class="operator">:</span>
|
||||
<span class="operator">++</span><span class="name">i</span><span class="punctuation">;</span>
|
||||
<span class="name">merklefile</span> <span class="operator">=</span> <span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">];</span>
|
||||
<span class="name">flags</span> <span class="operator">|=</span> <span class="name">create_torrent</span><span class="operator">::</span><span class="name">merkle</span><span class="punctuation">;</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="keyword">case</span> <span class="literal string char">'o'</span><span class="operator">:</span>
|
||||
<span class="operator">++</span><span class="name">i</span><span class="punctuation">;</span>
|
||||
<span class="name">outfile</span> <span class="operator">=</span> <span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">];</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="keyword">case</span> <span class="literal string char">'l'</span><span class="operator">:</span>
|
||||
<span class="name">flags</span> <span class="operator">|=</span> <span class="name">create_torrent</span><span class="operator">::</span><span class="name">symlinks</span><span class="punctuation">;</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="keyword">case</span> <span class="literal string char">'C'</span><span class="operator">:</span>
|
||||
<span class="operator">++</span><span class="name">i</span><span class="punctuation">;</span>
|
||||
<span class="name">creator_str</span> <span class="operator">=</span> <span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">];</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="keyword">case</span> <span class="literal string char">'c'</span><span class="operator">:</span>
|
||||
<span class="operator">++</span><span class="name">i</span><span class="punctuation">;</span>
|
||||
<span class="name">comment_str</span> <span class="operator">=</span> <span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">];</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="keyword">case</span> <span class="literal string char">'r'</span><span class="operator">:</span>
|
||||
<span class="operator">++</span><span class="name">i</span><span class="punctuation">;</span>
|
||||
<span class="name">root_cert</span> <span class="operator">=</span> <span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">];</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="keyword">case</span> <span class="literal string char">'S'</span><span class="operator">:</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="operator">++</span><span class="name">i</span><span class="punctuation">;</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">strlen</span><span class="punctuation">(</span><span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">])</span> <span class="operator">!=</span> <span class="literal number integer">40</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"invalid info-hash for -S. "</span>
|
||||
<span class="literal string">"Expected 40 hex characters</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">);</span>
|
||||
<span class="name">print_usage</span><span class="punctuation">();</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="name">sha1_hash</span> <span class="name">ih</span><span class="punctuation">;</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="operator">!</span><span class="name">from_hex</span><span class="punctuation">(</span><span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">],</span> <span class="literal number integer">40</span><span class="punctuation">,</span> <span class="punctuation">(</span><span class="keyword type">char</span><span class="operator">*</span><span class="punctuation">)</span><span class="operator">&</span><span class="name">ih</span><span class="punctuation">[</span><span class="literal number integer">0</span><span class="punctuation">]))</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"invalid info-hash for -S</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">);</span>
|
||||
<span class="name">print_usage</span><span class="punctuation">();</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="name">similar</span><span class="punctuation">.</span><span class="name">push_back</span><span class="punctuation">(</span><span class="name">ih</span><span class="punctuation">);</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="keyword">case</span> <span class="literal string char">'L'</span><span class="operator">:</span>
|
||||
<span class="operator">++</span><span class="name">i</span><span class="punctuation">;</span>
|
||||
<span class="name">collections</span><span class="punctuation">.</span><span class="name">push_back</span><span class="punctuation">(</span><span class="name">argv</span><span class="punctuation">[</span><span class="name">i</span><span class="punctuation">]);</span>
|
||||
<span class="keyword">break</span><span class="punctuation">;</span>
|
||||
<span class="keyword">default</span><span class="operator">:</span>
|
||||
<span class="name">print_usage</span><span class="punctuation">();</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">file_storage</span> <span class="name">fs</span><span class="punctuation">;</span>
|
||||
<span class="name">std</span><span class="operator">::</span><span class="name">string</span> <span class="name">full_path</span> <span class="operator">=</span> <span class="name">argv</span><span class="punctuation">[</span><span class="literal number integer">1</span><span class="punctuation">];</span>
|
||||
<span class="comment preproc">#ifdef TORRENT_WINDOWS
|
||||
</span> <span class="keyword">if</span> <span class="punctuation">(</span><span class="name">full_path</span><span class="punctuation">[</span><span class="literal number integer">1</span><span class="punctuation">]</span> <span class="operator">!=</span> <span class="literal string char">':'</span><span class="punctuation">)</span>
|
||||
<span class="comment preproc">#else
|
||||
</span> <span class="keyword">if</span> <span class="punctuation">(</span><span class="name">full_path</span><span class="punctuation">[</span><span class="literal number integer">0</span><span class="punctuation">]</span> <span class="operator">!=</span> <span class="literal string char">'/'</span><span class="punctuation">)</span>
|
||||
<span class="comment preproc">#endif
|
||||
</span> <span class="punctuation">{</span>
|
||||
<span class="keyword type">char</span> <span class="name">cwd</span><span class="punctuation">[</span><span class="name">TORRENT_MAX_PATH</span><span class="punctuation">];</span>
|
||||
<span class="comment preproc">#ifdef TORRENT_WINDOWS
|
||||
</span> <span class="name">_getcwd</span><span class="punctuation">(</span><span class="name">cwd</span><span class="punctuation">,</span> <span class="keyword">sizeof</span><span class="punctuation">(</span><span class="name">cwd</span><span class="punctuation">));</span>
|
||||
<span class="name">full_path</span> <span class="operator">=</span> <span class="name">cwd</span> <span class="operator">+</span> <span class="punctuation">(</span><span class="literal string">"</span><span class="literal string escape">\\</span><span class="literal string">"</span> <span class="operator">+</span> <span class="name">full_path</span><span class="punctuation">);</span>
|
||||
<span class="comment preproc">#else
|
||||
</span> <span class="name">getcwd</span><span class="punctuation">(</span><span class="name">cwd</span><span class="punctuation">,</span> <span class="keyword">sizeof</span><span class="punctuation">(</span><span class="name">cwd</span><span class="punctuation">));</span>
|
||||
<span class="name">full_path</span> <span class="operator">=</span> <span class="name">cwd</span> <span class="operator">+</span> <span class="punctuation">(</span><span class="literal string">"/"</span> <span class="operator">+</span> <span class="name">full_path</span><span class="punctuation">);</span>
|
||||
<span class="comment preproc">#endif
|
||||
</span> <span class="punctuation">}</span>
|
||||
|
||||
<span class="name">add_files</span><span class="punctuation">(</span><span class="name">fs</span><span class="punctuation">,</span> <span class="name">full_path</span><span class="punctuation">,</span> <span class="name">file_filter</span><span class="punctuation">,</span> <span class="name">flags</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">fs</span><span class="punctuation">.</span><span class="name">num_files</span><span class="punctuation">()</span> <span class="operator">==</span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fputs</span><span class="punctuation">(</span><span class="literal string">"no files specified.</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">stderr</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">create_torrent</span> <span class="name">t</span><span class="punctuation">(</span><span class="name">fs</span><span class="punctuation">,</span> <span class="name">piece_size</span><span class="punctuation">,</span> <span class="name">pad_file_limit</span><span class="punctuation">,</span> <span class="name">flags</span><span class="punctuation">);</span>
|
||||
<span class="keyword type">int</span> <span class="name">tier</span> <span class="operator">=</span> <span class="literal number integer">0</span><span class="punctuation">;</span>
|
||||
<span class="keyword">for</span> <span class="punctuation">(</span><span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="name">std</span><span class="operator">::</span><span class="name">string</span><span class="operator">>::</span><span class="name">iterator</span> <span class="name">i</span> <span class="operator">=</span> <span class="name">trackers</span><span class="punctuation">.</span><span class="name">begin</span><span class="punctuation">()</span>
|
||||
<span class="punctuation">,</span> <span class="name">end</span><span class="punctuation">(</span><span class="name">trackers</span><span class="punctuation">.</span><span class="name">end</span><span class="punctuation">());</span> <span class="name">i</span> <span class="operator">!=</span> <span class="name">end</span><span class="punctuation">;</span> <span class="operator">++</span><span class="name">i</span><span class="punctuation">,</span> <span class="operator">++</span><span class="name">tier</span><span class="punctuation">)</span>
|
||||
<span class="name">t</span><span class="punctuation">.</span><span class="name">add_tracker</span><span class="punctuation">(</span><span class="operator">*</span><span class="name">i</span><span class="punctuation">,</span> <span class="name">tier</span><span class="punctuation">);</span>
|
||||
|
||||
<span class="keyword">for</span> <span class="punctuation">(</span><span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="name">std</span><span class="operator">::</span><span class="name">string</span><span class="operator">>::</span><span class="name">iterator</span> <span class="name">i</span> <span class="operator">=</span> <span class="name">web_seeds</span><span class="punctuation">.</span><span class="name">begin</span><span class="punctuation">()</span>
|
||||
<span class="punctuation">,</span> <span class="name">end</span><span class="punctuation">(</span><span class="name">web_seeds</span><span class="punctuation">.</span><span class="name">end</span><span class="punctuation">());</span> <span class="name">i</span> <span class="operator">!=</span> <span class="name">end</span><span class="punctuation">;</span> <span class="operator">++</span><span class="name">i</span><span class="punctuation">)</span>
|
||||
<span class="name">t</span><span class="punctuation">.</span><span class="name">add_url_seed</span><span class="punctuation">(</span><span class="operator">*</span><span class="name">i</span><span class="punctuation">);</span>
|
||||
|
||||
<span class="keyword">for</span> <span class="punctuation">(</span><span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="name">std</span><span class="operator">::</span><span class="name">string</span><span class="operator">>::</span><span class="name">iterator</span> <span class="name">i</span> <span class="operator">=</span> <span class="name">collections</span><span class="punctuation">.</span><span class="name">begin</span><span class="punctuation">()</span>
|
||||
<span class="punctuation">,</span> <span class="name">end</span><span class="punctuation">(</span><span class="name">collections</span><span class="punctuation">.</span><span class="name">end</span><span class="punctuation">());</span> <span class="name">i</span> <span class="operator">!=</span> <span class="name">end</span><span class="punctuation">;</span> <span class="operator">++</span><span class="name">i</span><span class="punctuation">)</span>
|
||||
<span class="name">t</span><span class="punctuation">.</span><span class="name">add_collection</span><span class="punctuation">(</span><span class="operator">*</span><span class="name">i</span><span class="punctuation">);</span>
|
||||
|
||||
<span class="keyword">for</span> <span class="punctuation">(</span><span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="name">sha1_hash</span><span class="operator">>::</span><span class="name">iterator</span> <span class="name">i</span> <span class="operator">=</span> <span class="name">similar</span><span class="punctuation">.</span><span class="name">begin</span><span class="punctuation">()</span>
|
||||
<span class="punctuation">,</span> <span class="name">end</span><span class="punctuation">(</span><span class="name">similar</span><span class="punctuation">.</span><span class="name">end</span><span class="punctuation">());</span> <span class="name">i</span> <span class="operator">!=</span> <span class="name">end</span><span class="punctuation">;</span> <span class="operator">++</span><span class="name">i</span><span class="punctuation">)</span>
|
||||
<span class="name">t</span><span class="punctuation">.</span><span class="name">add_similar_torrent</span><span class="punctuation">(</span><span class="operator">*</span><span class="name">i</span><span class="punctuation">);</span>
|
||||
|
||||
<span class="name">error_code</span> <span class="name">ec</span><span class="punctuation">;</span>
|
||||
<span class="name">set_piece_hashes</span><span class="punctuation">(</span><span class="name">t</span><span class="punctuation">,</span> <span class="name">branch_path</span><span class="punctuation">(</span><span class="name">full_path</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">,</span> <span class="name">boost</span><span class="operator">::</span><span class="name">bind</span><span class="punctuation">(</span><span class="operator">&</span><span class="name">print_progress</span><span class="punctuation">,</span> <span class="name">_1</span><span class="punctuation">,</span> <span class="name">t</span><span class="punctuation">.</span><span class="name">num_pieces</span><span class="punctuation">()),</span> <span class="name">ec</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">ec</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"%s</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">ec</span><span class="punctuation">.</span><span class="name">message</span><span class="punctuation">().</span><span class="name">c_str</span><span class="punctuation">());</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">);</span>
|
||||
<span class="name">t</span><span class="punctuation">.</span><span class="name">set_creator</span><span class="punctuation">(</span><span class="name">creator_str</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">());</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="operator">!</span><span class="name">comment_str</span><span class="punctuation">.</span><span class="name">empty</span><span class="punctuation">())</span>
|
||||
<span class="name">t</span><span class="punctuation">.</span><span class="name">set_comment</span><span class="punctuation">(</span><span class="name">comment_str</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">());</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="operator">!</span><span class="name">root_cert</span><span class="punctuation">.</span><span class="name">empty</span><span class="punctuation">())</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="keyword type">char</span><span class="operator">></span> <span class="name">pem</span><span class="punctuation">;</span>
|
||||
<span class="name">load_file</span><span class="punctuation">(</span><span class="name">root_cert</span><span class="punctuation">,</span> <span class="name">pem</span><span class="punctuation">,</span> <span class="name">ec</span><span class="punctuation">,</span> <span class="literal number integer">10000</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">ec</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"failed to load root certificate for tracker: %s</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">ec</span><span class="punctuation">.</span><span class="name">message</span><span class="punctuation">().</span><span class="name">c_str</span><span class="punctuation">());</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="keyword">else</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">t</span><span class="punctuation">.</span><span class="name">set_root_cert</span><span class="punctuation">(</span><span class="name">std</span><span class="operator">::</span><span class="name">string</span><span class="punctuation">(</span><span class="operator">&</span><span class="name">pem</span><span class="punctuation">[</span><span class="literal number integer">0</span><span class="punctuation">],</span> <span class="name">pem</span><span class="punctuation">.</span><span class="name">size</span><span class="punctuation">()));</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="comment single">// create the torrent and print it to stdout
|
||||
</span> <span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="keyword type">char</span><span class="operator">></span> <span class="name">torrent</span><span class="punctuation">;</span>
|
||||
<span class="name">bencode</span><span class="punctuation">(</span><span class="name">back_inserter</span><span class="punctuation">(</span><span class="name">torrent</span><span class="punctuation">),</span> <span class="name">t</span><span class="punctuation">.</span><span class="name">generate</span><span class="punctuation">());</span>
|
||||
<span class="keyword type">FILE</span><span class="operator">*</span> <span class="name">output</span> <span class="operator">=</span> <span class="name">stdout</span><span class="punctuation">;</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="operator">!</span><span class="name">outfile</span><span class="punctuation">.</span><span class="name">empty</span><span class="punctuation">())</span>
|
||||
<span class="name">output</span> <span class="operator">=</span> <span class="name">fopen</span><span class="punctuation">(</span><span class="name">outfile</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">(),</span> <span class="literal string">"wb+"</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">output</span> <span class="operator">==</span> <span class="name builtin">NULL</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"failed to open file </span><span class="literal string escape">\"</span><span class="literal string">%s</span><span class="literal string escape">\"</span><span class="literal string">: (%d) %s</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="punctuation">,</span> <span class="name">outfile</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">(),</span> <span class="name">errno</span><span class="punctuation">,</span> <span class="name">strerror</span><span class="punctuation">(</span><span class="name">errno</span><span class="punctuation">));</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="name">fwrite</span><span class="punctuation">(</span><span class="operator">&</span><span class="name">torrent</span><span class="punctuation">[</span><span class="literal number integer">0</span><span class="punctuation">],</span> <span class="literal number integer">1</span><span class="punctuation">,</span> <span class="name">torrent</span><span class="punctuation">.</span><span class="name">size</span><span class="punctuation">(),</span> <span class="name">output</span><span class="punctuation">);</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">output</span> <span class="operator">!=</span> <span class="name">stdout</span><span class="punctuation">)</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">output</span><span class="punctuation">);</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="operator">!</span><span class="name">merklefile</span><span class="punctuation">.</span><span class="name">empty</span><span class="punctuation">())</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">output</span> <span class="operator">=</span> <span class="name">fopen</span><span class="punctuation">(</span><span class="name">merklefile</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">(),</span> <span class="literal string">"wb+"</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">output</span> <span class="operator">==</span> <span class="name builtin">NULL</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"failed to open file </span><span class="literal string escape">\"</span><span class="literal string">%s</span><span class="literal string escape">\"</span><span class="literal string">: (%d) %s</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="punctuation">,</span> <span class="name">merklefile</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">(),</span> <span class="name">errno</span><span class="punctuation">,</span> <span class="name">strerror</span><span class="punctuation">(</span><span class="name">errno</span><span class="punctuation">));</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="keyword type">int</span> <span class="name">ret</span> <span class="operator">=</span> <span class="name">fwrite</span><span class="punctuation">(</span><span class="operator">&</span><span class="name">t</span><span class="punctuation">.</span><span class="name">merkle_tree</span><span class="punctuation">()[</span><span class="literal number integer">0</span><span class="punctuation">],</span> <span class="literal number integer">20</span><span class="punctuation">,</span> <span class="name">t</span><span class="punctuation">.</span><span class="name">merkle_tree</span><span class="punctuation">().</span><span class="name">size</span><span class="punctuation">(),</span> <span class="name">output</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">ret</span> <span class="operator">!=</span> <span class="keyword type">int</span><span class="punctuation">(</span><span class="name">t</span><span class="punctuation">.</span><span class="name">merkle_tree</span><span class="punctuation">().</span><span class="name">size</span><span class="punctuation">()))</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"failed to write %s: (%d) %s</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="punctuation">,</span> <span class="name">merklefile</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">(),</span> <span class="name">errno</span><span class="punctuation">,</span> <span class="name">strerror</span><span class="punctuation">(</span><span class="name">errno</span><span class="punctuation">));</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">output</span><span class="punctuation">);</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="comment preproc">#ifndef BOOST_NO_EXCEPTIONS
|
||||
</span> <span class="punctuation">}</span>
|
||||
<span class="keyword">catch</span> <span class="punctuation">(</span><span class="name">std</span><span class="operator">::</span><span class="name">exception</span><span class="operator">&</span> <span class="name">e</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"%s</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">e</span><span class="punctuation">.</span><span class="name">what</span><span class="punctuation">());</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="comment preproc">#endif
|
||||
</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">0</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="dump-torrent">
|
||||
<h2>dump_torrent</h2>
|
||||
<p>This is an example of a program that will take a torrent-file as a parameter and
|
||||
print information about it to std out:</p>
|
||||
<pre class="code c++ literal-block">
|
||||
<span class="comment preproc">#include "libtorrent/entry.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/announce_entry.hpp"
|
||||
#include "libtorrent/bdecode.hpp"
|
||||
#include "libtorrent/magnet_uri.hpp"
|
||||
</span>
|
||||
<span class="keyword type">int</span> <span class="name function">load_file</span><span class="punctuation">(</span><span class="name">std</span><span class="operator">::</span><span class="name">string</span> <span class="keyword">const</span><span class="operator">&</span> <span class="name">filename</span><span class="punctuation">,</span> <span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="keyword type">char</span><span class="operator">>&</span> <span class="name">v</span>
|
||||
<span class="punctuation">,</span> <span class="name">libtorrent</span><span class="operator">::</span><span class="name">error_code</span><span class="operator">&</span> <span class="name">ec</span><span class="punctuation">,</span> <span class="keyword type">int</span> <span class="name">limit</span> <span class="operator">=</span> <span class="literal number integer">8000000</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">ec</span><span class="punctuation">.</span><span class="name">clear</span><span class="punctuation">();</span>
|
||||
<span class="keyword type">FILE</span><span class="operator">*</span> <span class="name">f</span> <span class="operator">=</span> <span class="name">fopen</span><span class="punctuation">(</span><span class="name">filename</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">(),</span> <span class="literal string">"rb"</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">f</span> <span class="operator">==</span> <span class="name builtin">NULL</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">ec</span><span class="punctuation">.</span><span class="name">assign</span><span class="punctuation">(</span><span class="name">errno</span><span class="punctuation">,</span> <span class="name">boost</span><span class="operator">::</span><span class="name">system</span><span class="operator">::</span><span class="name">system_category</span><span class="punctuation">());</span>
|
||||
<span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword type">int</span> <span class="name">r</span> <span class="operator">=</span> <span class="name">fseek</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">,</span> <span class="literal number integer">0</span><span class="punctuation">,</span> <span class="name">SEEK_END</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">r</span> <span class="operator">!=</span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">ec</span><span class="punctuation">.</span><span class="name">assign</span><span class="punctuation">(</span><span class="name">errno</span><span class="punctuation">,</span> <span class="name">boost</span><span class="operator">::</span><span class="name">system</span><span class="operator">::</span><span class="name">system_category</span><span class="punctuation">());</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="keyword type">long</span> <span class="name">s</span> <span class="operator">=</span> <span class="name">ftell</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">s</span> <span class="operator"><</span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">ec</span><span class="punctuation">.</span><span class="name">assign</span><span class="punctuation">(</span><span class="name">errno</span><span class="punctuation">,</span> <span class="name">boost</span><span class="operator">::</span><span class="name">system</span><span class="operator">::</span><span class="name">system_category</span><span class="punctuation">());</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">s</span> <span class="operator">></span> <span class="name">limit</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">2</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">r</span> <span class="operator">=</span> <span class="name">fseek</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">,</span> <span class="literal number integer">0</span><span class="punctuation">,</span> <span class="name">SEEK_SET</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">r</span> <span class="operator">!=</span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">ec</span><span class="punctuation">.</span><span class="name">assign</span><span class="punctuation">(</span><span class="name">errno</span><span class="punctuation">,</span> <span class="name">boost</span><span class="operator">::</span><span class="name">system</span><span class="operator">::</span><span class="name">system_category</span><span class="punctuation">());</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">v</span><span class="punctuation">.</span><span class="name">resize</span><span class="punctuation">(</span><span class="name">s</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">s</span> <span class="operator">==</span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">0</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">r</span> <span class="operator">=</span> <span class="name">fread</span><span class="punctuation">(</span><span class="operator">&</span><span class="name">v</span><span class="punctuation">[</span><span class="literal number integer">0</span><span class="punctuation">],</span> <span class="literal number integer">1</span><span class="punctuation">,</span> <span class="name">v</span><span class="punctuation">.</span><span class="name">size</span><span class="punctuation">(),</span> <span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">r</span> <span class="operator"><</span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">ec</span><span class="punctuation">.</span><span class="name">assign</span><span class="punctuation">(</span><span class="name">errno</span><span class="punctuation">,</span> <span class="name">boost</span><span class="operator">::</span><span class="name">system</span><span class="operator">::</span><span class="name">system_category</span><span class="punctuation">());</span>
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">fclose</span><span class="punctuation">(</span><span class="name">f</span><span class="punctuation">);</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">r</span> <span class="operator">!=</span> <span class="name">s</span><span class="punctuation">)</span> <span class="keyword">return</span> <span class="operator">-</span><span class="literal number integer">3</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="keyword">return</span> <span class="literal number integer">0</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword type">int</span> <span class="name function">main</span><span class="punctuation">(</span><span class="keyword type">int</span> <span class="name">argc</span><span class="punctuation">,</span> <span class="keyword type">char</span><span class="operator">*</span> <span class="name">argv</span><span class="punctuation">[])</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="name">libtorrent</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">argc</span> <span class="operator"><</span> <span class="literal number integer">2</span> <span class="operator">||</span> <span class="name">argc</span> <span class="operator">></span> <span class="literal number integer">4</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fputs</span><span class="punctuation">(</span><span class="literal string">"usage: dump_torrent torrent-file [total-items-limit] [recursion-limit]</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">stderr</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword type">int</span> <span class="name">item_limit</span> <span class="operator">=</span> <span class="literal number integer">1000000</span><span class="punctuation">;</span>
|
||||
<span class="keyword type">int</span> <span class="name">depth_limit</span> <span class="operator">=</span> <span class="literal number integer">1000</span><span class="punctuation">;</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">argc</span> <span class="operator">></span> <span class="literal number integer">2</span><span class="punctuation">)</span> <span class="name">item_limit</span> <span class="operator">=</span> <span class="name">atoi</span><span class="punctuation">(</span><span class="name">argv</span><span class="punctuation">[</span><span class="literal number integer">2</span><span class="punctuation">]);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">argc</span> <span class="operator">></span> <span class="literal number integer">3</span><span class="punctuation">)</span> <span class="name">depth_limit</span> <span class="operator">=</span> <span class="name">atoi</span><span class="punctuation">(</span><span class="name">argv</span><span class="punctuation">[</span><span class="literal number integer">3</span><span class="punctuation">]);</span>
|
||||
|
||||
<span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="keyword type">char</span><span class="operator">></span> <span class="name">buf</span><span class="punctuation">;</span>
|
||||
<span class="name">error_code</span> <span class="name">ec</span><span class="punctuation">;</span>
|
||||
<span class="keyword type">int</span> <span class="name">ret</span> <span class="operator">=</span> <span class="name">load_file</span><span class="punctuation">(</span><span class="name">argv</span><span class="punctuation">[</span><span class="literal number integer">1</span><span class="punctuation">],</span> <span class="name">buf</span><span class="punctuation">,</span> <span class="name">ec</span><span class="punctuation">,</span> <span class="literal number integer">40</span> <span class="operator">*</span> <span class="literal number integer">1000000</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">ret</span> <span class="operator">==</span> <span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"file too big, aborting</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">ret</span> <span class="operator">!=</span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"failed to load file: %s</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">ec</span><span class="punctuation">.</span><span class="name">message</span><span class="punctuation">().</span><span class="name">c_str</span><span class="punctuation">());</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="name">bdecode_node</span> <span class="name">e</span><span class="punctuation">;</span>
|
||||
<span class="keyword type">int</span> <span class="name">pos</span> <span class="operator">=</span> <span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="name">printf</span><span class="punctuation">(</span><span class="literal string">"decoding. recursion limit: %d total item count limit: %d</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="punctuation">,</span> <span class="name">depth_limit</span><span class="punctuation">,</span> <span class="name">item_limit</span><span class="punctuation">);</span>
|
||||
<span class="name">ret</span> <span class="operator">=</span> <span class="name">bdecode</span><span class="punctuation">(</span><span class="operator">&</span><span class="name">buf</span><span class="punctuation">[</span><span class="literal number integer">0</span><span class="punctuation">],</span> <span class="operator">&</span><span class="name">buf</span><span class="punctuation">[</span><span class="literal number integer">0</span><span class="punctuation">]</span> <span class="operator">+</span> <span class="name">buf</span><span class="punctuation">.</span><span class="name">size</span><span class="punctuation">(),</span> <span class="name">e</span><span class="punctuation">,</span> <span class="name">ec</span><span class="punctuation">,</span> <span class="operator">&</span><span class="name">pos</span>
|
||||
<span class="punctuation">,</span> <span class="name">depth_limit</span><span class="punctuation">,</span> <span class="name">item_limit</span><span class="punctuation">);</span>
|
||||
|
||||
<span class="name">printf</span><span class="punctuation">(</span><span class="literal string">"</span><span class="literal string escape">\n\n</span><span class="literal string">----- raw info -----</span><span class="literal string escape">\n\n</span><span class="literal string">%s</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">print_entry</span><span class="punctuation">(</span><span class="name">e</span><span class="punctuation">).</span><span class="name">c_str</span><span class="punctuation">());</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">ret</span> <span class="operator">!=</span> <span class="literal number integer">0</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"failed to decode: '%s' at character: %d</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">ec</span><span class="punctuation">.</span><span class="name">message</span><span class="punctuation">().</span><span class="name">c_str</span><span class="punctuation">(),</span> <span class="name">pos</span><span class="punctuation">);</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="name">torrent_info</span> <span class="name">t</span><span class="punctuation">(</span><span class="name">e</span><span class="punctuation">,</span> <span class="name">ec</span><span class="punctuation">);</span>
|
||||
<span class="keyword">if</span> <span class="punctuation">(</span><span class="name">ec</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">fprintf</span><span class="punctuation">(</span><span class="name">stderr</span><span class="punctuation">,</span> <span class="literal string">"%s</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">ec</span><span class="punctuation">.</span><span class="name">message</span><span class="punctuation">().</span><span class="name">c_str</span><span class="punctuation">());</span>
|
||||
<span class="keyword">return</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="name">e</span><span class="punctuation">.</span><span class="name">clear</span><span class="punctuation">();</span>
|
||||
<span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="keyword type">char</span><span class="operator">></span><span class="punctuation">().</span><span class="name">swap</span><span class="punctuation">(</span><span class="name">buf</span><span class="punctuation">);</span>
|
||||
|
||||
<span class="comment single">// print info about torrent
|
||||
</span> <span class="name">printf</span><span class="punctuation">(</span><span class="literal string">"</span><span class="literal string escape">\n\n</span><span class="literal string">----- torrent file info -----</span><span class="literal string escape">\n\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"nodes:</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">);</span>
|
||||
|
||||
<span class="keyword">typedef</span> <span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="name">std</span><span class="operator">::</span><span class="name">pair</span><span class="operator"><</span><span class="name">std</span><span class="operator">::</span><span class="name">string</span><span class="punctuation">,</span> <span class="keyword type">int</span><span class="operator">></span> <span class="operator">></span> <span class="name">node_vec</span><span class="punctuation">;</span>
|
||||
<span class="name">node_vec</span> <span class="keyword">const</span><span class="operator">&</span> <span class="name">nodes</span> <span class="operator">=</span> <span class="name">t</span><span class="punctuation">.</span><span class="name">nodes</span><span class="punctuation">();</span>
|
||||
<span class="keyword">for</span> <span class="punctuation">(</span><span class="name">node_vec</span><span class="operator">::</span><span class="name">const_iterator</span> <span class="name">i</span> <span class="operator">=</span> <span class="name">nodes</span><span class="punctuation">.</span><span class="name">begin</span><span class="punctuation">(),</span> <span class="name">end</span><span class="punctuation">(</span><span class="name">nodes</span><span class="punctuation">.</span><span class="name">end</span><span class="punctuation">());</span>
|
||||
<span class="name">i</span> <span class="operator">!=</span> <span class="name">end</span><span class="punctuation">;</span> <span class="operator">++</span><span class="name">i</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">printf</span><span class="punctuation">(</span><span class="literal string">"%s: %d</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">i</span><span class="operator">-></span><span class="name">first</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">(),</span> <span class="name">i</span><span class="operator">-></span><span class="name">second</span><span class="punctuation">);</span>
|
||||
<span class="punctuation">}</span>
|
||||
<span class="name">puts</span><span class="punctuation">(</span><span class="literal string">"trackers:</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">);</span>
|
||||
<span class="keyword">for</span> <span class="punctuation">(</span><span class="name">std</span><span class="operator">::</span><span class="name">vector</span><span class="operator"><</span><span class="name">announce_entry</span><span class="operator">>::</span><span class="name">const_iterator</span> <span class="name">i</span> <span class="operator">=</span> <span class="name">t</span><span class="punctuation">.</span><span class="name">trackers</span><span class="punctuation">().</span><span class="name">begin</span><span class="punctuation">();</span>
|
||||
<span class="name">i</span> <span class="operator">!=</span> <span class="name">t</span><span class="punctuation">.</span><span class="name">trackers</span><span class="punctuation">().</span><span class="name">end</span><span class="punctuation">();</span> <span class="operator">++</span><span class="name">i</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="name">printf</span><span class="punctuation">(</span><span class="literal string">"%2d: %s</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span> <span class="name">i</span><span class="operator">-></span><span class="name">tier</span><span class="punctuation">,</span> <span class="name">i</span><span class="operator">-></span><span class="name">url</span><span class="punctuation">.</span><span class="name">c_str</span><span class="punctuation">());</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword type">char</span> <span class="name">ih</span><span class="punctuation">[</span><span class="literal number integer">41</span><span class="punctuation">];</span>
|
||||
<span class="name">to_hex</span><span class="punctuation">((</span><span class="keyword type">char</span> <span class="keyword">const</span><span class="operator">*</span><span class="punctuation">)</span><span class="operator">&</span><span class="name">t</span><span class="punctuation">.</span><span class="name">info_hash</span><span class="punctuation">()[</span><span class="literal number integer">0</span><span class="punctuation">],</span> <span class="literal number integer">20</span><span class="punctuation">,</span> <span class="name">ih</span><span class="punctuation">);</span>
|
||||
<span class="name">printf</span><span class="punctuation">(</span><span class="literal string">"number of pieces: %d</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"piece length: %d</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"info hash: %s</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"comment: %s</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"created by: %s</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"magnet link: %s</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"name: %s</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"number of files: %d</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="literal string">"files:</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="punctuation">,</span> <span class="name">t</span><span class="punctuation">.</span><span class="name">num_pieces</span><span class="punctuation">()</span>
|
||||
<span class="punctuation">,</span> <span class="name">t</span><span class="punctuation">.</span><span class="name">piece_length</span><span class="punctuation">()</span>
|
||||
<span class="punctuation">,</span> <span class="name">ih</span>
|
||||
<span class="punctuation">,</span> <span class="name">t</span><span class="punctuation">.</span><span class="name">comment</span><span class="punctuation">().</span><span class="name">c_str</span><span class="punctuation">()</span>
|
||||
<span class="punctuation">,</span> <span class="name">t</span><span class="punctuation">.</span><span class="name">creator</span><span class="punctuation">().</span><span class="name">c_str</span><span class="punctuation">()</span>
|
||||
<span class="punctuation">,</span> <span class="name">make_magnet_uri</span><span class="punctuation">(</span><span class="name">t</span><span class="punctuation">).</span><span class="name">c_str</span><span class="punctuation">()</span>
|
||||
<span class="punctuation">,</span> <span class="name">t</span><span class="punctuation">.</span><span class="name">name</span><span class="punctuation">().</span><span class="name">c_str</span><span class="punctuation">()</span>
|
||||
<span class="punctuation">,</span> <span class="name">t</span><span class="punctuation">.</span><span class="name">num_files</span><span class="punctuation">());</span>
|
||||
<span class="name">file_storage</span> <span class="keyword">const</span><span class="operator">&</span> <span class="name">st</span> <span class="operator">=</span> <span class="name">t</span><span class="punctuation">.</span><span class="name">files</span><span class="punctuation">();</span>
|
||||
<span class="keyword">for</span> <span class="punctuation">(</span><span class="keyword type">int</span> <span class="name">i</span> <span class="operator">=</span> <span class="literal number integer">0</span><span class="punctuation">;</span> <span class="name">i</span> <span class="operator"><</span> <span class="name">st</span><span class="punctuation">.</span><span class="name">num_files</span><span class="punctuation">();</span> <span class="operator">++</span><span class="name">i</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">{</span>
|
||||
<span class="keyword type">int</span> <span class="name">first</span> <span class="operator">=</span> <span class="name">st</span><span class="punctuation">.</span><span class="name">map_file</span><span class="punctuation">(</span><span class="name">i</span><span class="punctuation">,</span> <span class="literal number integer">0</span><span class="punctuation">,</span> <span class="literal number integer">0</span><span class="punctuation">).</span><span class="name">piece</span><span class="punctuation">;</span>
|
||||
<span class="keyword type">int</span> <span class="name">last</span> <span class="operator">=</span> <span class="name">st</span><span class="punctuation">.</span><span class="name">map_file</span><span class="punctuation">(</span><span class="name">i</span><span class="punctuation">,</span> <span class="punctuation">(</span><span class="name">std</span><span class="operator">::</span><span class="name">max</span><span class="punctuation">)(</span><span class="name">boost</span><span class="operator">::</span><span class="keyword type">int64_t</span><span class="punctuation">(</span><span class="name">st</span><span class="punctuation">.</span><span class="name">file_size</span><span class="punctuation">(</span><span class="name">i</span><span class="punctuation">))</span><span class="operator">-</span><span class="literal number integer">1</span><span class="punctuation">,</span> <span class="name">boost</span><span class="operator">::</span><span class="keyword type">int64_t</span><span class="punctuation">(</span><span class="literal number integer">0</span><span class="punctuation">)),</span> <span class="literal number integer">0</span><span class="punctuation">).</span><span class="name">piece</span><span class="punctuation">;</span>
|
||||
<span class="keyword type">int</span> <span class="name">flags</span> <span class="operator">=</span> <span class="name">st</span><span class="punctuation">.</span><span class="name">file_flags</span><span class="punctuation">(</span><span class="name">i</span><span class="punctuation">);</span>
|
||||
<span class="name">printf</span><span class="punctuation">(</span><span class="literal string">" %8"</span> <span class="name">PRIx64</span> <span class="literal string">" %11"</span> <span class="name">PRId64</span> <span class="literal string">" %c%c%c%c [ %5d, %5d ] %7u %s %s %s%s</span><span class="literal string escape">\n</span><span class="literal string">"</span>
|
||||
<span class="punctuation">,</span> <span class="name">st</span><span class="punctuation">.</span><span class="name">file_offset</span><span class="punctuation">(</span><span class="name">i</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">,</span> <span class="name">st</span><span class="punctuation">.</span><span class="name">file_size</span><span class="punctuation">(</span><span class="name">i</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">,</span> <span class="punctuation">((</span><span class="name">flags</span> <span class="operator">&</span> <span class="name">file_storage</span><span class="operator">::</span><span class="name">flag_pad_file</span><span class="punctuation">)</span><span class="operator">?</span><span class="literal string char">'p'</span><span class="operator">:</span><span class="literal string char">'-'</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">,</span> <span class="punctuation">((</span><span class="name">flags</span> <span class="operator">&</span> <span class="name">file_storage</span><span class="operator">::</span><span class="name">flag_executable</span><span class="punctuation">)</span><span class="operator">?</span><span class="literal string char">'x'</span><span class="operator">:</span><span class="literal string char">'-'</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">,</span> <span class="punctuation">((</span><span class="name">flags</span> <span class="operator">&</span> <span class="name">file_storage</span><span class="operator">::</span><span class="name">flag_hidden</span><span class="punctuation">)</span><span class="operator">?</span><span class="literal string char">'h'</span><span class="operator">:</span><span class="literal string char">'-'</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">,</span> <span class="punctuation">((</span><span class="name">flags</span> <span class="operator">&</span> <span class="name">file_storage</span><span class="operator">::</span><span class="name">flag_symlink</span><span class="punctuation">)</span><span class="operator">?</span><span class="literal string char">'l'</span><span class="operator">:</span><span class="literal string char">'-'</span><span class="punctuation">)</span>
|
||||
<span class="punctuation">,</span> <span class="name">first</span><span class="punctuation">,</span> <span class="name">last</span>
|
||||
<span class="punctuation">,</span> <span class="name">boost</span><span class="operator">::</span><span class="keyword type">uint32_t</span><span class="punctuation">(</span><span class="name">st</span><span class="punctuation">.</span><span class="name">mtime</span><span class="punctuation">(</span><span class="name">i</span><span class="punctuation">))</span>
|
||||
<span class="punctuation">,</span> <span class="name">st</span><span class="punctuation">.</span><span class="name">hash</span><span class="punctuation">(</span><span class="name">i</span><span class="punctuation">)</span> <span class="operator">!=</span> <span class="name">sha1_hash</span><span class="punctuation">(</span><span class="literal number integer">0</span><span class="punctuation">)</span> <span class="operator">?</span> <span class="name">to_hex</span><span class="punctuation">(</span><span class="name">st</span><span class="punctuation">.</span><span class="name">hash</span><span class="punctuation">(</span><span class="name">i</span><span class="punctuation">).</span><span class="name">to_string</span><span class="punctuation">()).</span><span class="name">c_str</span><span class="punctuation">()</span> <span class="operator">:</span> <span class="literal string">""</span>
|
||||
<span class="punctuation">,</span> <span class="name">st</span><span class="punctuation">.</span><span class="name">file_path</span><span class="punctuation">(</span><span class="name">i</span><span class="punctuation">).</span><span class="name">c_str</span><span class="punctuation">()</span>
|
||||
<span class="punctuation">,</span> <span class="punctuation">(</span><span class="name">flags</span> <span class="operator">&</span> <span class="name">file_storage</span><span class="operator">::</span><span class="name">flag_symlink</span><span class="punctuation">)</span> <span class="operator">?</span> <span class="literal string">"-> "</span> <span class="operator">:</span> <span class="literal string">""</span>
|
||||
<span class="punctuation">,</span> <span class="punctuation">(</span><span class="name">flags</span> <span class="operator">&</span> <span class="name">file_storage</span><span class="operator">::</span><span class="name">flag_symlink</span><span class="punctuation">)</span> <span class="operator">?</span> <span class="name">st</span><span class="punctuation">.</span><span class="name">symlink</span><span class="punctuation">(</span><span class="name">i</span><span class="punctuation">).</span><span class="name">c_str</span><span class="punctuation">()</span> <span class="operator">:</span> <span class="literal string">""</span><span class="punctuation">);</span>
|
||||
<span class="punctuation">}</span>
|
||||
|
||||
<span class="keyword">return</span> <span class="literal number integer">0</span><span class="punctuation">;</span>
|
||||
<span class="punctuation">}</span>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,498 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title></title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org Ludvig Strigeus, ludde@utorrent.com" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.css" />
|
||||
<style type="text/css">
|
||||
/* Hides from IE-mac \*/
|
||||
* html pre { height: 1%; }
|
||||
/* End hide from IE-mac */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document">
|
||||
<div id="container">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<div id="main">
|
||||
|
||||
<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="reference external" href="mailto:arvid@libtorrent.org">arvid@libtorrent.org</a>
|
||||
Ludvig Strigeus, <a class="last reference external" href="mailto:ludde@utorrent.com">ludde@utorrent.com</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="section" id="extension-protocol-for-bittorrent">
|
||||
<h1>extension protocol for bittorrent</h1>
|
||||
<p>The intention of this protocol is to provide a simple and thin transport
|
||||
for extensions to the bittorrent protocol. Supporting this protocol makes
|
||||
it easy to add new extensions without interfering with the standard
|
||||
bittorrent protocol or clients that don't support this extension or the
|
||||
one you want to add.</p>
|
||||
<p>To advertise to other clients that you support, one bit from the reserved
|
||||
bytes is used.</p>
|
||||
<p>The bit selected for the extension protocol is bit 20 from the right (counting
|
||||
starts at 0). So (reserved_byte[5] & 0x10) is the expression to use for checking
|
||||
if the client supports extended messaging.</p>
|
||||
<p>Once support for the protocol is established, the client is supposed to
|
||||
support 1 new message:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="86%" />
|
||||
<col width="14%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">name</th>
|
||||
<th class="head">id</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td><tt class="docutils literal">extended</tt></td>
|
||||
<td>20</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>This message is sent as any other bittorrent message, with a 4 byte length
|
||||
prefix and a single byte identifying the message (the single byte being 20
|
||||
in this case). At the start of the payload of the message, is a single byte
|
||||
message identifier. This identifier can refer to different extension messages
|
||||
and only one ID is specified, 0. If the ID is 0, the message is a handshake
|
||||
message which is described below. The layout of a general <tt class="docutils literal">extended</tt> message
|
||||
follows (including the message headers used by the bittorrent protocol):</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="15%" />
|
||||
<col width="85%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>uint32_t</td>
|
||||
<td>length prefix. Specifies the number of bytes for the
|
||||
entire message. (Big endian)</td>
|
||||
</tr>
|
||||
<tr><td>uint8_t</td>
|
||||
<td>bittorrent message ID, = 20</td>
|
||||
</tr>
|
||||
<tr><td>uint8_t</td>
|
||||
<td>extended message ID. 0 = handshake, >0 = extended
|
||||
message as specified by the handshake.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="section" id="handshake-message">
|
||||
<h2>handshake message</h2>
|
||||
<p>The payload of the handshake message is a bencoded dictionary. All items
|
||||
in the dictionary are optional. Any unknown names should be ignored
|
||||
by the client. All parts of the dictionary are case sensitive.
|
||||
This is the defined item in the dictionary:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="11%" />
|
||||
<col width="89%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>m</td>
|
||||
<td><p class="first">Dictionary of supported extension messages which maps
|
||||
names of extensions to an extended message ID for each
|
||||
extension message. The only requirement on these IDs
|
||||
is that no extension message share the same one. Setting
|
||||
an extension number to zero means that the extension is
|
||||
not supported/disabled. The client should ignore any
|
||||
extension names it doesn't recognize.</p>
|
||||
<p class="last">The extension message IDs are the IDs used to send the
|
||||
extension messages to the peer sending this handshake.
|
||||
i.e. The IDs are local to this particular peer.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Here are some other items that an implementation may choose to support:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="12%" />
|
||||
<col width="88%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>p</td>
|
||||
<td>Local TCP listen port. Allows each side to learn about
|
||||
the TCP port number of the other side. Note that there is
|
||||
no need for the receiving side of the connection to send
|
||||
this extension message, since its port number is already
|
||||
known.</td>
|
||||
</tr>
|
||||
<tr><td>v</td>
|
||||
<td>Client name and version (as a utf-8 string).
|
||||
This is a much more reliable way of identifying the
|
||||
client than relying on the peer id encoding.</td>
|
||||
</tr>
|
||||
<tr><td>yourip</td>
|
||||
<td>A string containing the compact representation of the ip
|
||||
address this peer sees you as. i.e. this is the
|
||||
receiver's external ip address (no port is included).
|
||||
This may be either an IPv4 (4 bytes) or an IPv6
|
||||
(16 bytes) address.</td>
|
||||
</tr>
|
||||
<tr><td>ipv6</td>
|
||||
<td>If this peer has an IPv6 interface, this is the compact
|
||||
representation of that address (16 bytes). The client may
|
||||
prefer to connect back via the IPv6 address.</td>
|
||||
</tr>
|
||||
<tr><td>ipv4</td>
|
||||
<td>If this peer has an IPv4 interface, this is the compact
|
||||
representation of that address (4 bytes). The client may
|
||||
prefer to connect back via this interface.</td>
|
||||
</tr>
|
||||
<tr><td>reqq</td>
|
||||
<td>An integer, the number of outstanding request messages
|
||||
this client supports without dropping any. The default in
|
||||
in libtorrent is 250.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The handshake dictionary could also include extended handshake
|
||||
information, such as support for encrypted headers or anything
|
||||
imaginable.</p>
|
||||
<p>An example of what the payload of a handshake message could look like:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="36%" />
|
||||
<col width="64%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head" colspan="2">Dictionary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td><tt class="docutils literal">m</tt></td>
|
||||
<td><table border="1" class="first last docutils">
|
||||
<colgroup>
|
||||
<col width="88%" />
|
||||
<col width="12%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head" colspan="2">Dictionary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td><tt class="docutils literal">LT_metadata</tt></td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">ut_pex</tt></td>
|
||||
<td>2</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">p</tt></td>
|
||||
<td>6881</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">v</tt></td>
|
||||
<td>"uTorrent 1.2"</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>and in the encoded form:</p>
|
||||
<p><tt class="docutils literal">d1:md11:LT_metadatai1e6:ut_pexi2ee1:pi6881e1:v12:uTorrent 1.2e</tt></p>
|
||||
<p>To make sure the extension names do not collide by mistake, they should be
|
||||
prefixed with the two (or one) character code that is used to identify the
|
||||
client that introduced the extension. This applies for both the names of
|
||||
extension messages, and for any additional information put inside the
|
||||
top-level dictionary. All one and two byte identifiers are invalid to use
|
||||
unless defined by this specification.</p>
|
||||
<p>This message should be sent immediately after the standard bittorrent handshake
|
||||
to any peer that supports this extension protocol. It is valid to send the
|
||||
handshake message more than once during the lifetime of a connection,
|
||||
the sending client should not be disconnected. An implementation may choose
|
||||
to ignore the subsequent handshake messages (or parts of them).</p>
|
||||
<p>Subsequent handshake messages can be used to enable/disable extensions
|
||||
without restarting the connection. If a peer supports changing extensions
|
||||
at run time, it should note that the <tt class="docutils literal">m</tt> dictionary is additive.
|
||||
It's enough that it contains the actual <em>CHANGES</em> to the extension list.
|
||||
To disable the support for <tt class="docutils literal">LT_metadata</tt> at run-time, without affecting
|
||||
any other extensions, this message should be sent:
|
||||
<tt class="docutils literal">d11:LT_metadatai0ee</tt>.
|
||||
As specified above, the value 0 is used to turn off an extension.</p>
|
||||
<p>The extension IDs must be stored for every peer, becuase every peer may have
|
||||
different IDs for the same extension.</p>
|
||||
<p>This specification, deliberately, does not specify any extensions such as
|
||||
peer-exchange or metadata exchange. This protocol is merely a transport
|
||||
for the actual extensions to the bittorrent protocol and the extensions
|
||||
named in the example above (such as <tt class="docutils literal">p</tt>) are just examples of possible
|
||||
extensions.</p>
|
||||
</div>
|
||||
<div class="section" id="rationale">
|
||||
<h2>rationale</h2>
|
||||
<p>The reason why the extension messages' IDs would be defined in the handshake
|
||||
is to avoid having a global registry of message IDs. Instead the names of the
|
||||
extension messages requires unique names, which is much easier to do without
|
||||
a global registry. The convention is to use a two letter prefix on the
|
||||
extension message names, the prefix would identify the client first
|
||||
implementing the extension message. e.g. <tt class="docutils literal">LT_metadata</tt> is implemented by
|
||||
libtorrent, and hence it has the <tt class="docutils literal">LT</tt> prefix.</p>
|
||||
<p>If the client supporting the extensions can decide which numbers the messages
|
||||
it receives will have, it means they are constants within that client. i.e.
|
||||
they can be used in <tt class="docutils literal">switch</tt> statements. It's easy for the other end to
|
||||
store an array with the ID's we expect for each message and use that for
|
||||
lookups each time it sends an extension message.</p>
|
||||
<p>The reason for having a dictionary instead of having an array (using
|
||||
implicitly assigned index numbers to the extensions) is that if a client
|
||||
want to disable some extensions, the ID numbers would change, and it wouldn't
|
||||
be able to use constants (and hence, not use them in a <tt class="docutils literal">switch</tt>). If the
|
||||
messages IDs would map directly to bittorrent message IDs, It would also make
|
||||
it possible to map extensions in the handshake to existing extensions with
|
||||
fixed message IDs.</p>
|
||||
<p>The reasoning behind having a single byte as extended message identifier is
|
||||
to follow the the bittorrent spec. with its single byte message identifiers.
|
||||
It is also considered to be enough. It won't limit the total number of
|
||||
extensions, only the number of extensions used simultaneously.</p>
|
||||
<p>The reason for using single byte identifiers for the standardized handshake
|
||||
identifiers is 1) The mainline DHT uses single byte identifiers. 2) Saves
|
||||
bandwidth. The only advantage of longer messages is that it makes the
|
||||
protocol more readable for a human, but the BT protocol wasn't designed to
|
||||
be a human readable protocol, so why bother.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="extensions">
|
||||
<h1>extensions</h1>
|
||||
<p>These extensions all operates within the <a class="reference external" href="extension_protocol.html">extension protocol</a>. The name of the
|
||||
extension is the name used in the extension-list packets, and the payload is
|
||||
the data in the extended message (not counting the length-prefix, message-id
|
||||
nor extension-id).</p>
|
||||
<p>Note that since this protocol relies on one of the reserved bits in the
|
||||
handshake, it may be incompatible with future versions of the mainline
|
||||
bittorrent client.</p>
|
||||
<p>These are the extensions that are currently implemented.</p>
|
||||
<div class="section" id="metadata-from-peers">
|
||||
<h2>metadata from peers</h2>
|
||||
<p>Extension name: "LT_metadata"</p>
|
||||
<div class="note">
|
||||
<p class="first admonition-title">Note</p>
|
||||
<p class="last">This extension is deprecated in favor of the more widely supported
|
||||
<tt class="docutils literal">ut_metadata</tt> extension, see <a class="reference external" href="http://bittorrent.org/beps/bep_0009.html">BEP 9</a>.</p>
|
||||
</div>
|
||||
<p>The point with this extension is that you don't have to distribute the
|
||||
metadata (.torrent-file) separately. The metadata can be distributed
|
||||
through the bittorrent swarm. The only thing you need to download such
|
||||
a torrent is the tracker url and the info-hash of the torrent.</p>
|
||||
<p>It works by assuming that the initial seeder has the metadata and that the
|
||||
metadata will propagate through the network as more peers join.</p>
|
||||
<p>There are three kinds of messages in the metadata extension. These packets are
|
||||
put as payload to the extension message. The three packets are:</p>
|
||||
<blockquote>
|
||||
<ul class="simple">
|
||||
<li>request metadata</li>
|
||||
<li>metadata</li>
|
||||
<li>don't have metadata</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<p>request metadata:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="17%" />
|
||||
<col width="23%" />
|
||||
<col width="61%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>uint8_t</td>
|
||||
<td>msg_type</td>
|
||||
<td>Determines the kind of message this is
|
||||
0 means 'request metadata'</td>
|
||||
</tr>
|
||||
<tr><td>uint8_t</td>
|
||||
<td>start</td>
|
||||
<td>The start of the metadata block that
|
||||
is requested. It is given in 256:ths
|
||||
of the total size of the metadata,
|
||||
since the requesting client don't know
|
||||
the size of the metadata.</td>
|
||||
</tr>
|
||||
<tr><td>uint8_t</td>
|
||||
<td>size</td>
|
||||
<td>The size of the metadata block that is
|
||||
requested. This is also given in
|
||||
256:ths of the total size of the
|
||||
metadata. The size is given as size-1.
|
||||
That means that if this field is set
|
||||
0, the request wants one 256:th of the
|
||||
metadata.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>metadata:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="17%" />
|
||||
<col width="23%" />
|
||||
<col width="61%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>uint8_t</td>
|
||||
<td>msg_type</td>
|
||||
<td>1 means 'metadata'</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>total_size</td>
|
||||
<td>The total size of the metadata, given
|
||||
in number of bytes.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>offset</td>
|
||||
<td>The offset of where the metadata block
|
||||
in this message belongs in the final
|
||||
metadata. This is given in bytes.</td>
|
||||
</tr>
|
||||
<tr><td>uint8_t[]</td>
|
||||
<td>metadata</td>
|
||||
<td>The actual metadata block. The size of
|
||||
this part is given implicit by the
|
||||
length prefix in the bittorrent
|
||||
protocol packet.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Don't have metadata:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="17%" />
|
||||
<col width="23%" />
|
||||
<col width="61%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>uint8_t</td>
|
||||
<td>msg_type</td>
|
||||
<td>2 means 'I don't have metadata'.
|
||||
This message is sent as a reply to a
|
||||
metadata request if the the client
|
||||
doesn't have any metadata.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section" id="dont-have">
|
||||
<h2>dont_have</h2>
|
||||
<p>Extension name: "lt_donthave"</p>
|
||||
<p>The <tt class="docutils literal">dont_have</tt> extension message is used to tell peers that the client no
|
||||
longer has a specific piece. The extension message should be advertised in the
|
||||
<tt class="docutils literal">m</tt> dictionary as <tt class="docutils literal">lt_donthave</tt>. The message format mimics the regular
|
||||
<tt class="docutils literal">HAVE</tt> bittorrent message.</p>
|
||||
<p>Just like all extension messages, the first 2 bytes in the mssage itself are 20
|
||||
(the bittorrent extension message) and the message ID assigned to this
|
||||
extension in the <tt class="docutils literal">m</tt> dictionary in the handshake.</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="17%" />
|
||||
<col width="23%" />
|
||||
<col width="61%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>uint32_t</td>
|
||||
<td>piece</td>
|
||||
<td>index of the piece the peer no longer
|
||||
has.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The length of this message (including the extension message prefix) is 6 bytes,
|
||||
i.e. one byte longer than the normal <tt class="docutils literal">HAVE</tt> message, because of the extension
|
||||
message wrapping.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,415 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>libtorrent manual</title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<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@libtorrent.org">arvid@libtorrent.org</a></td></tr>
|
||||
<tr><th class="docinfo-name">Version:</th>
|
||||
<td>1.1.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="#introduction" id="id2">introduction</a></li>
|
||||
<li><a class="reference internal" href="#features" id="id3">features</a><ul>
|
||||
<li><a class="reference internal" href="#extensions" id="id4">extensions</a></li>
|
||||
<li><a class="reference internal" href="#disk-management" id="id5">disk management</a></li>
|
||||
<li><a class="reference internal" href="#network" id="id6">network</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#highlighted-features" id="id7">highlighted features</a><ul>
|
||||
<li><a class="reference internal" href="#disk-caching" id="id8">disk caching</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="#piece-picker" id="id11">piece picker</a></li>
|
||||
<li><a class="reference internal" href="#share-mode" id="id12">share mode</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="#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>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#portability" id="id16">portability</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="introduction">
|
||||
<h1>introduction</h1>
|
||||
<p>libtorrent is a feature complete C++ bittorrent implementation focusing
|
||||
on efficiency and scalability. It runs on embedded devices as well as
|
||||
desktops. It boasts a well documented library interface that is easy to
|
||||
use. It comes with a simple bittorrent client demonstrating the use of
|
||||
the library.</p>
|
||||
</div>
|
||||
<div class="section" id="features">
|
||||
<h1>features</h1>
|
||||
<p>libtorrent is an ongoing project under active development. Its
|
||||
current state supports and includes the following features:</p>
|
||||
<div class="section" id="extensions">
|
||||
<h2>extensions</h2>
|
||||
<ul class="simple">
|
||||
<li>plugin interface for implementing custom bittorrent extensions
|
||||
without having to modify libtorrent</li>
|
||||
<li>supports trackerless torrents (using the Mainline kademlia DHT protocol) with
|
||||
some <a class="reference external" href="dht_extensions.html">DHT extensions</a>. <a class="reference external" href="http://bittorrent.org/beps/bep_0005.html">BEP 5</a>.</li>
|
||||
<li>supports the bittorrent <a class="reference external" href="extension_protocol.html">extension protocol</a>. See <a class="reference external" href="manual-ref.html#extensions">extensions</a>. <a class="reference external" href="http://bittorrent.org/beps/bep_0010.html">BEP 10</a>.</li>
|
||||
<li>supports the uTorrent metadata transfer protocol <a class="reference external" href="http://bittorrent.org/beps/bep_0009.html">BEP 9</a> (i.e. magnet links).</li>
|
||||
<li>supports the uTorrent peer exchange protocol (PEX).</li>
|
||||
<li>supports local peer discovery (multicasts for peers on the same local network)</li>
|
||||
<li>multitracker extension support (supports both strict <a class="reference external" href="http://bittorrent.org/beps/bep_0012.html">BEP 12</a> and the
|
||||
uTorrent interpretation).</li>
|
||||
<li>tracker scrapes</li>
|
||||
<li>supports lt_trackers extension, to exchange trackers between peers</li>
|
||||
<li><a class="reference external" href="manual-ref.html#http-seeding">HTTP seeding</a>, as specified in <a class="reference external" href="http://bittorrent.org/beps/bep_0017.html">BEP 17</a> and <a class="reference external" href="http://bittorrent.org/beps/bep_0019.html">BEP 19</a>.</li>
|
||||
<li>supports the udp-tracker protocol. (<a class="reference external" href="http://bittorrent.org/beps/bep_0015.html">BEP 15</a>).</li>
|
||||
<li>supports the <tt class="docutils literal">no_peer_id=1</tt> extension that will ease the load off trackers.</li>
|
||||
<li>supports the <tt class="docutils literal">compact=1</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>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 merkle hash tree torrents. This makes the size of torrent files
|
||||
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>
|
||||
</div>
|
||||
<div class="section" id="disk-management">
|
||||
<h2>disk management</h2>
|
||||
<ul class="simple">
|
||||
<li>can use multipled disk I/O threads to not have the disk block network or
|
||||
client interaction.</li>
|
||||
<li>supports verifying the SHA-1 hash of pieces in multiple threads, to take
|
||||
advantage of multi core machines.</li>
|
||||
<li>supports files > 2 gigabytes.</li>
|
||||
<li>fast resume support, a way to avoid the costly piece check at the
|
||||
start of a resumed torrent. Saves the storage state, piece_picker state
|
||||
as well as all local peers in a fast-resume file.</li>
|
||||
<li>has an adjustable read and write disk cache for improved disk throughput.</li>
|
||||
<li>queues torrents for file check, instead of checking all of them in parallel.</li>
|
||||
<li>does not have any requirements on the piece order in a torrent that it
|
||||
resumes. This means it can resume a torrent downloaded by any client.</li>
|
||||
<li>seed mode, where the files on disk are assumed to be complete, and each
|
||||
piece's hash is verified the first time it is requested.</li>
|
||||
<li>implements an ARC disk cache, tuned for performing well under bittorrent work
|
||||
loads</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="network">
|
||||
<h2>network</h2>
|
||||
<ul class="simple">
|
||||
<li>a high quality uTP implementation (<a class="reference external" href="http://bittorrent.org/beps/bep_0029.html">BEP 29</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>serves multiple torrents on a single port and in a single thread</li>
|
||||
<li>piece picking on block-level (as opposed to piece-level).
|
||||
This means it can download parts of the same piece from different peers.
|
||||
It will also prefer to download whole pieces from single peers if the
|
||||
download speed is high enough from that particular peer.</li>
|
||||
<li>supports http proxies and basic proxy authentication</li>
|
||||
<li>supports gzipped tracker-responses</li>
|
||||
<li>can limit the upload and download bandwidth usage and the maximum number of
|
||||
unchoked peers</li>
|
||||
<li>possibility to limit the number of connections.</li>
|
||||
<li>delays have messages if there's no other outgoing traffic to the peer, and
|
||||
doesn't send have messages to peers that already has the piece. This saves
|
||||
bandwidth.</li>
|
||||
<li>selective downloading. The ability to select which parts of a torrent you
|
||||
want to download.</li>
|
||||
<li>ip filter to disallow ip addresses and ip ranges from connecting and
|
||||
being connected.</li>
|
||||
<li>NAT-PMP and UPnP support (automatic port mapping on routers that supports it)</li>
|
||||
<li>implements automatic upload slots, to optimize download rate without spreading
|
||||
upload capacity too thin. The number of upload slots is adjusted based on the
|
||||
peers' download capacity to work even for connections that are orders of
|
||||
magnitude faster than others.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="highlighted-features">
|
||||
<h1>highlighted features</h1>
|
||||
<div class="section" id="disk-caching">
|
||||
<h2>disk caching</h2>
|
||||
<p>All disk I/O in libtorrent is done asynchronously to the network thread, by the
|
||||
disk io thread. When a block is read, the disk io thread reads all subsequent
|
||||
blocks from that piece into the read cache, assuming that the peer requesting
|
||||
the block will also request more blocks from the same piece. This decreases the
|
||||
number of syscalls for reading data. It also decreases delay from seeking.</p>
|
||||
<p>Similarly, for write requests, blocks are cached and flushed to disk once one full
|
||||
piece is complete or the piece is the least recently updated one when more cache
|
||||
space is needed. The cache dynamically allocates space between the write and read
|
||||
cache. The write cache is strictly prioritized over the read cache.</p>
|
||||
<p>The cache blocks that are in used, are locked into physical memory to avoid it
|
||||
being paged out to disk. Allowing the disk cache to be paged out to disk means
|
||||
that it would become extremely inefficient to flush it, since it would have to be
|
||||
read back into physical memory only to be flushed back out to disk again.</p>
|
||||
<p>In order to conserve memory, and system calls, iovec file operations are
|
||||
used to flush multiple cache blocks in a single call.</p>
|
||||
<p>On low-memory systems, the disk cache can be disabled altogether or set to smaller
|
||||
limit, to save memory.</p>
|
||||
<p>The disk caching algorithm is configurable between 'LRU' and 'largest contiguous'.
|
||||
The largest contiguous algorithm is the default and flushes the largest contiguous
|
||||
block of buffers, instead of flushing all blocks belonging to the piece which was
|
||||
written to least recently.</p>
|
||||
<p>For version 0.15 a lot of work went into optimizing the cache algorithm, trying
|
||||
to increase the cache hit rate and utilization. The graph to the left shows the
|
||||
memory utilization in 0.14. This cache is a straight forward, fairly naive, implementation.
|
||||
Every block read will also read all subsequent blocks in that piece into the cache.
|
||||
Whenever we need more space, the entire oldest piece is evicted from the cache. Caching
|
||||
writes always takes presedence over the read cache. Whenever a piece is fully downloaded,
|
||||
it is flushed to disk.</p>
|
||||
<img alt="disk_buffer_before_optimization.png" src="disk_buffer_before_optimization.png" style="width: 49%;" />
|
||||
<img alt="disk_buffer.png" src="disk_buffer.png" style="width: 49%;" />
|
||||
<p>The left graph shows the problem of evicting entire pieces at a time, and waiting until
|
||||
an entire piece is downloaded until flushing it. These graphs were generated for a torrent
|
||||
with fairly large pieces. This means that granularity was poor in 0.14, since it only
|
||||
dealt with entire pieces. In 0.15, the granularity problem has been fixed by evicting one
|
||||
block at a time from the read cache. This maximizes the read cache utilization. The write
|
||||
cache is also flushed when a sufficient number of contiguous blocks have been downloaded
|
||||
for a piece, which is not tied to the piece size anymore. This way the cache scales a lot
|
||||
better with piece sizes.</p>
|
||||
<p>The graph to the right shows the same download but with the new optimized disk cache
|
||||
algorithm. It clearly shows an increased utilization, which means higher read hit rates
|
||||
or smaller caches with maintained hit rate.</p>
|
||||
</div>
|
||||
<div class="section" id="high-performance-disk-subsystem">
|
||||
<h2>high performance disk subsystem</h2>
|
||||
<p>In some circumstances, the disk cache may not suffice to provide maximum performance.
|
||||
One such example is high performance seeding, to a large number of peers, over a fast
|
||||
up-link. In such a case, the amount of RAM may simply not be enough to cache disk
|
||||
reads. When there's not enough RAM to cache disk reads, the disk throughput would
|
||||
typically degrade to perform as poorly as with no cache at all, with the majority
|
||||
of the time spent waiting for the disk head to seek.</p>
|
||||
<p>To solve this problem, libtorrent sorts read requests by their physical offset on the
|
||||
disk. They are processed by having the disk read head sweep back and forth over the drive.</p>
|
||||
<p>This makes libtorrent very suitable for large scale, high-throughput seeding.</p>
|
||||
<img alt="disk_access_no_elevator.png" src="disk_access_no_elevator.png" style="width: 49%;" />
|
||||
<img alt="disk_access_elevator.png" src="disk_access_elevator.png" style="width: 49%;" />
|
||||
<p>These plots illustrates the physical disk offset for reads over time. The left plot
|
||||
is of a run where disk operation re-ordering is turned off and the righ is when it's
|
||||
turned on. The right one has a relatively smooth sine wave shape whereas the left
|
||||
one is more random and involves much longer seeks back and forth over the disk.</p>
|
||||
<p>True physical disk offset queries are only supported on newer linux kernels, Mac OS X and
|
||||
Windows 2000 and up.</p>
|
||||
</div>
|
||||
<div class="section" id="network-buffers">
|
||||
<h2>network buffers</h2>
|
||||
<p>On CPUs with small L2 caches, copying memory can be expensive operations. It is important
|
||||
to keep copying to a minimum on such machines. This mostly applies to embedded systems.</p>
|
||||
<p>In order to minimize the number of times received data is copied, the receive buffer
|
||||
for payload data is received directly into a page aligned disk buffer. If the connection
|
||||
is encrypted, the buffer is decrypted in-place. The buffer is then moved into the disk
|
||||
cache without being copied. Once all the blocks for a piece have been received, or the
|
||||
cache needs to be flushed, all the blocks are passed directly to <tt class="docutils literal">writev()</tt> to flush
|
||||
them in a single syscall. This means a single copy into user space memory, and a single
|
||||
copy back into kernel memory, as illustrated by this figure:</p>
|
||||
<img alt="write_disk_buffers.png" src="write_disk_buffers.png" style="width: 100%;" />
|
||||
<p>When seeding and uploading in general, unnecessary copying is avoided by caching blocks
|
||||
in aligned buffers, that are copied once into the peer's send buffer. The peer's send buffer
|
||||
is not guaranteed to be aligned, even though it is most of the time. The send buffer is
|
||||
then encrypted with the peer specific key and chained onto the <tt class="docutils literal">iovec</tt> for sending.
|
||||
This means there is one user space copy in order to allow unaligned peer requests and
|
||||
peer-specific encryption. This is illustrated by the following figure:</p>
|
||||
<img alt="read_disk_buffers.png" src="read_disk_buffers.png" style="width: 100%;" />
|
||||
</div>
|
||||
<div class="section" id="piece-picker">
|
||||
<h2>piece picker</h2>
|
||||
<p>The piece picker is a central component in a bittorrent implementation. The piece picker
|
||||
in libtorrent is optimized for quickly finding the rarest pieces. It keeps a list of all
|
||||
available pieces sorted by rarity, and pieces with the same rarity, shuffled. The rarest
|
||||
first mode is the dominant piece picker mode. Other modes are supported as well, and
|
||||
used by peers in specific situations.</p>
|
||||
<p>The piece picker allows to combine the availability of a piece with a priority. Together
|
||||
they determine the sort order of the piece list. Pieces with priority 0 will never be
|
||||
picked, which is used for the selective download feature.</p>
|
||||
<p>In order to have as few partially finished pieces as possible, peers have an affinity
|
||||
towards picking blocks from the same pieces as other peers in the same speed category.
|
||||
The speed category is a coarse categorization of peers based on their download rate. This
|
||||
makes slow peers pick blocks from the same piece, and fast peers pick from the same piece,
|
||||
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>
|
||||
</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">
|
||||
<h2>merkle hash tree torrents</h2>
|
||||
<img alt="merkle_tree.png" class="align-right" src="merkle_tree.png" />
|
||||
<p>Merkle hash tree torrents is an extension that lets a torrent file only contain the
|
||||
root hash of the hash tree forming the piece hashes. The main benefit of this feature
|
||||
is that regardless of how many pieces there is in a torrent, the .torrent file will
|
||||
always be the same size. It will only grow with the number of files (since it still
|
||||
has to contain the file names).</p>
|
||||
<p>With regular torrents, clients have to request multiple blocks for pieces, typically
|
||||
from different peers, before the data can be verified against the piece hash. The
|
||||
larger the pieces are, the longer it will take to download a complete piece and verify
|
||||
it. Before the piece is verified, it cannot be shared with the swarm, which means the
|
||||
larger piece sizes, the slower turnaround data has when it is downloaded by peers.
|
||||
Since on average the data has to sit around, waiting, in client buffers before it has
|
||||
been verified and can be uploaded again.</p>
|
||||
<p>Another problem with large piece sizes is that it is harder for a client to pinpoint
|
||||
the malicious or buggy peer when a piece fails, and it will take longer to re-download
|
||||
it and take more tries before the piece succeeds the larger the pieces are.</p>
|
||||
<p>The piece size in regular torrents is a tradeoff between the size of the .torrent file
|
||||
itself and the piece size. Often, for files that are 4 GB, the piece size is 2 or 4 MB,
|
||||
just to avoid making the .torrent file too big.</p>
|
||||
<p>Merkle torrents solves these problems by removing the tradeoff between .torrent size and
|
||||
piece size. With merkle torrents, the piece size can be the minimum block size (16 kB),
|
||||
which lets peers verify every block of data received from peers, immediately. This
|
||||
gives a minimum turnaround time and completely removes the problem of identifying malicious
|
||||
peers.</p>
|
||||
<p>The root hash is built by hashing all the piece hashes pair-wise, until they all collapse
|
||||
down to the root.</p>
|
||||
</div>
|
||||
<div class="section" id="customizable-file-storage">
|
||||
<h2>customizable file storage</h2>
|
||||
<img alt="storage.png" class="align-right" src="storage.png" />
|
||||
<p>libtorrent's storage implementation is customizable. That means a special purpose bittorrent
|
||||
client can replace the default way to store files on disk.</p>
|
||||
<p>When implementing a bittorrent cache, it doesn't matter how the data is stored on disk, as
|
||||
long as it can be retrieved and seeded. In that case a new storage class can be implemented
|
||||
(inheriting from the <tt class="docutils literal">storage_interface</tt> class) that avoids the unnecessary step of mapping
|
||||
slots to files and offsets. The storage can ignore the file boundaries and just store the
|
||||
entire torrent in a single file (which will end up being all the files concatenated). The main
|
||||
advantage of this, other than a slight cpu performance gain, is that all file operations would
|
||||
be page (and sector) aligned. This enables efficient unbuffered I/O, and can potentially
|
||||
lead to more efficient read caching (using the built in disk cache rather than relying on the
|
||||
operating system's disk cache).</p>
|
||||
<p>The storage interface supports operating systems where you can ask for sparse regions
|
||||
(such as Windows and Solaris). The advantage of this is that when checking files, the regions
|
||||
that are known to be sparse can be skipped, which can reduce the time to check a torrent
|
||||
significantly.</p>
|
||||
</div>
|
||||
<div class="section" id="easy-to-use-api">
|
||||
<h2>easy to use API</h2>
|
||||
<p>One of the design goals of the libtorrent API is to make common operations simple, but still
|
||||
have it possible to do complicated and advanced operations. This is best illustrated by example
|
||||
code to implement a simple bittorrent client:</p>
|
||||
<pre class="literal-block">
|
||||
#include <iostream>
|
||||
#include "libtorrent/session.hpp"
|
||||
|
||||
// usage a.out [torrent-file]
|
||||
int main(int argc, char* argv[]) try
|
||||
{
|
||||
using namespace libtorrent;
|
||||
|
||||
session s;
|
||||
s.listen_on(std::make_pair(6881, 6889));
|
||||
add_torrent_params p;
|
||||
p.save_path = "./";
|
||||
p.ti = new torrent_info(argv[1]);
|
||||
s.add_torrent(p);
|
||||
|
||||
// wait for the user to end
|
||||
char a;
|
||||
std::cin.unsetf(std::ios_base::skipws);
|
||||
std::cin >> a;
|
||||
return 0;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << ec.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
</pre>
|
||||
<p>This client doesn't give the user any status information or progress about the torrent, but
|
||||
it is fully functional.</p>
|
||||
<p>libtorrent also comes with python bindings for easy access for python developers.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="portability">
|
||||
<h1>portability</h1>
|
||||
<p>libtorrent runs on most major operating systems, including Windows,
|
||||
MacOS X, Linux, BSD and Solaris.
|
||||
It uses Boost.Thread, Boost.Filesystem, Boost.Date_time and various other
|
||||
boost libraries. At least version 1.46.1 of boost is required.</p>
|
||||
<p>libtorrent uses asio, hence it will take full advantage of high performance
|
||||
network APIs on the most popular platforms. I/O completion ports on windows,
|
||||
epoll on linux and kqueue on MacOS X and BSD.</p>
|
||||
<p>libtorrent does not build with the following compilers:</p>
|
||||
<ul class="simple">
|
||||
<li>GCC 2.95.4</li>
|
||||
<li>Visual Studio 6, 7.0, 7.1</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -129,7 +129,7 @@ disk caching
|
|||
------------
|
||||
|
||||
All disk I/O in libtorrent is done asynchronously to the network thread, by the
|
||||
disk io thread. When a block is read, the disk io thread reads all subsequent
|
||||
disk io threads. When a block is read, the disk io thread reads all subsequent
|
||||
blocks from that piece into the read cache, assuming that the peer requesting
|
||||
the block will also request more blocks from the same piece. This decreases the
|
||||
number of syscalls for reading data. It also decreases delay from seeking.
|
||||
|
@ -155,62 +155,6 @@ The largest contiguous algorithm is the default and flushes the largest contiguo
|
|||
block of buffers, instead of flushing all blocks belonging to the piece which was
|
||||
written to least recently.
|
||||
|
||||
For version 0.15 a lot of work went into optimizing the cache algorithm, trying
|
||||
to increase the cache hit rate and utilization. The graph to the left shows the
|
||||
memory utilization in 0.14. This cache is a straight forward, fairly naive, implementation.
|
||||
Every block read will also read all subsequent blocks in that piece into the cache.
|
||||
Whenever we need more space, the entire oldest piece is evicted from the cache. Caching
|
||||
writes always takes presedence over the read cache. Whenever a piece is fully downloaded,
|
||||
it is flushed to disk.
|
||||
|
||||
.. image:: disk_buffer_before_optimization.png
|
||||
:width: 49%
|
||||
|
||||
.. image:: disk_buffer.png
|
||||
:width: 49%
|
||||
|
||||
The left graph shows the problem of evicting entire pieces at a time, and waiting until
|
||||
an entire piece is downloaded until flushing it. These graphs were generated for a torrent
|
||||
with fairly large pieces. This means that granularity was poor in 0.14, since it only
|
||||
dealt with entire pieces. In 0.15, the granularity problem has been fixed by evicting one
|
||||
block at a time from the read cache. This maximizes the read cache utilization. The write
|
||||
cache is also flushed when a sufficient number of contiguous blocks have been downloaded
|
||||
for a piece, which is not tied to the piece size anymore. This way the cache scales a lot
|
||||
better with piece sizes.
|
||||
|
||||
The graph to the right shows the same download but with the new optimized disk cache
|
||||
algorithm. It clearly shows an increased utilization, which means higher read hit rates
|
||||
or smaller caches with maintained hit rate.
|
||||
|
||||
high performance disk subsystem
|
||||
-------------------------------
|
||||
|
||||
In some circumstances, the disk cache may not suffice to provide maximum performance.
|
||||
One such example is high performance seeding, to a large number of peers, over a fast
|
||||
up-link. In such a case, the amount of RAM may simply not be enough to cache disk
|
||||
reads. When there's not enough RAM to cache disk reads, the disk throughput would
|
||||
typically degrade to perform as poorly as with no cache at all, with the majority
|
||||
of the time spent waiting for the disk head to seek.
|
||||
|
||||
To solve this problem, libtorrent sorts read requests by their physical offset on the
|
||||
disk. They are processed by having the disk read head sweep back and forth over the drive.
|
||||
|
||||
This makes libtorrent very suitable for large scale, high-throughput seeding.
|
||||
|
||||
.. image:: disk_access_no_elevator.png
|
||||
:width: 49%
|
||||
|
||||
.. image:: disk_access_elevator.png
|
||||
:width: 49%
|
||||
|
||||
These plots illustrates the physical disk offset for reads over time. The left plot
|
||||
is of a run where disk operation re-ordering is turned off and the righ is when it's
|
||||
turned on. The right one has a relatively smooth sine wave shape whereas the left
|
||||
one is more random and involves much longer seeks back and forth over the disk.
|
||||
|
||||
True physical disk offset queries are only supported on newer linux kernels, Mac OS X and
|
||||
Windows 2000 and up.
|
||||
|
||||
network buffers
|
||||
---------------
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ libtorrent starts 3 to 5 threads.
|
|||
* The third thread is the SHA-1 hash thread. By default there's only one hash thread,
|
||||
but on multi-core machines downloading at very high rates, libtorrent can be configured
|
||||
to start any number of hashing threads, to take full use of multi core systems.
|
||||
(see ``session_settings::hashing_threads``).
|
||||
(see ``settings_pack::aio_threads``).
|
||||
|
||||
* The fourth and fifth threads are spawned by asio on systems that don't support
|
||||
asynchronous host name resolution, in order to simulate non-blocking ``getaddrinfo()``.
|
||||
|
|
171
docs/index.html
|
@ -1,171 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title></title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.css" />
|
||||
<style type="text/css">
|
||||
/* Hides from IE-mac \*/
|
||||
* html pre { height: 1%; }
|
||||
/* End hide from IE-mac */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document">
|
||||
<div id="container">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<div id="main">
|
||||
|
||||
<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@libtorrent.org">arvid@libtorrent.org</a></td></tr>
|
||||
<tr><th class="docinfo-name">Version:</th>
|
||||
<td>1.1.0</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="librarySidebar"><ul class="simple">
|
||||
<li><a class="reference external" href="https://github.com/arvidn/libtorrent/releases">download</a></li>
|
||||
<li><a class="reference external" href="features.html">features</a></li>
|
||||
<li><a class="reference external" href="examples.html">examples</a></li>
|
||||
<li><a class="reference external" href="manual-ref.html">overview</a></li>
|
||||
<li><a class="reference external" href="reference.html">reference documentation</a></li>
|
||||
<li><a class="reference external" href="contributing.html">contributing</a></li>
|
||||
<li><a class="reference external" href="building.html">building</a></li>
|
||||
<li><a class="reference external" href="troubleshooting.html">troubleshooting</a></li>
|
||||
<li><a class="reference external" href="tuning.html">tuning</a></li>
|
||||
<li><a class="reference external" href="client_test.png">screenshot</a></li>
|
||||
<li><a class="reference external" href="http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss">mailing list</a> (<a class="reference external" href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">archive</a>)</li>
|
||||
<li><a class="reference external" href="projects.html">who's using libtorrent?</a></li>
|
||||
<li><a class="reference external" href="https://github.com/arvidn/libtorrent/issues">report bugs</a></li>
|
||||
<li><a class="reference external" href="https://github.com/arvidn/libtorrent">github page</a></li>
|
||||
<li><a class="reference external" href="http://blog.libtorrent.org">blog</a></li>
|
||||
</ul>
|
||||
<hr class="docutils" />
|
||||
<p>Extensions</p>
|
||||
<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="reference-Plugins.html">plugin interface</a></li>
|
||||
<li><a class="reference external" href="streaming.html">streaming</a></li>
|
||||
<li><a class="reference external" href="dht_extensions.html">DHT extensions</a></li>
|
||||
<li><a class="reference external" href="dht_sec.html">DHT security extension</a></li>
|
||||
<li><a class="reference external" href="dht_store.html">DHT store extension</a></li>
|
||||
<li><a class="reference external" href="udp_tracker_protocol.html">UDP tracker protocol</a></li>
|
||||
<li><a class="reference external" href="http://www.getright.com/seedtorrent.html">HTTP seed</a></li>
|
||||
<li><a class="reference external" href="http://bittorrent.org/beps/bep_0012.html">multitracker</a></li>
|
||||
</ul>
|
||||
<hr class="docutils" />
|
||||
<p>Bindings</p>
|
||||
<ul class="simple">
|
||||
<li><a class="reference external" href="http://libtorrent-ruby.rubyforge.org/">ruby bindings</a></li>
|
||||
<li><a class="reference external" href="python_binding.html">python bindings</a></li>
|
||||
</ul>
|
||||
<hr class="docutils" />
|
||||
<ul class="simple">
|
||||
<li><a class="reference external" href="bittorrent.pdf">Introduction, slides</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="libraryBody"><div class="section" id="libtorrent">
|
||||
<h1>libtorrent</h1>
|
||||
<p>libtorrent is a feature complete C++ bittorrent implementation focusing
|
||||
on efficiency and scalability. It runs on embedded devices as well as
|
||||
desktops. It boasts a well documented library interface that is easy to
|
||||
use. It comes with a <a class="reference external" href="client_test.html">simple bittorrent client</a> demonstrating the use of
|
||||
the library.</p>
|
||||
<p>The main goals of libtorrent are:</p>
|
||||
<ul class="simple">
|
||||
<li>to be cpu efficient</li>
|
||||
<li>to be memory efficient</li>
|
||||
<li>to be very easy to use</li>
|
||||
</ul>
|
||||
<div class="section" id="donate">
|
||||
<h2>Donate</h2>
|
||||
<p>Support the development of libtorrent</p>
|
||||
<a class="FlattrButton" style="display:none;" href="http://libtorrent.org"></a>
|
||||
<noscript><a href="https://flattr.com/thing/95662/libtorrent" target="_blank">
|
||||
<img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a></noscript></div>
|
||||
<div class="section" id="feedback">
|
||||
<h2>Feedback</h2>
|
||||
<p>There's a <a class="reference external" href="http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss">mailing list</a>, general libtorrent discussion.</p>
|
||||
<p>You can usually find me as hydri in <tt class="docutils literal">#libtorrent</tt> on <tt class="docutils literal">irc.freenode.net</tt>.</p>
|
||||
</div>
|
||||
<div class="section" id="license">
|
||||
<h2>license</h2>
|
||||
<p>libtorrent is released under the <a class="reference external" href="http://opensource.org/licenses/bsd-license.php">BSD-license</a>.</p>
|
||||
<p>This means that you can use the library in your project without having to
|
||||
release its source code. The only requirement is that you give credit
|
||||
to the author of the library by including the libtorrent license in your
|
||||
software or documentation.</p>
|
||||
<p>It is however greatly appreciated if additional features are contributed
|
||||
back to the open source project. Patches can be emailed to the mailing
|
||||
list or posted to the <a class="reference external" href="https://github.com/arvidn/libtorrent/issues">bug tracker</a>.</p>
|
||||
</div>
|
||||
<div class="section" id="acknowledgements">
|
||||
<h2>Acknowledgements</h2>
|
||||
<p>Written by Arvid Norberg. Copyright © 2003-2016</p>
|
||||
<p>Contributions by Steven Siloti, Magnus Jonsson, Daniel Wallin and Cory Nelson</p>
|
||||
<p>Thanks to Reimond Retz for bugfixes, suggestions and testing</p>
|
||||
<p>Thanks to <a class="reference external" href="http://www.cs.umu.se">Umeå University</a> for providing development and test hardware.</p>
|
||||
<p>Project is hosted by <a class="reference external" href="https://www.github.com/arvidn/libtorrent">github</a>.</p>
|
||||
</div></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,222 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>projects using libtorrent</title>
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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="projects-using-libtorrent">
|
||||
<div id="container">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<div id="main">
|
||||
<h1 class="title">projects using libtorrent</h1>
|
||||
|
||||
<p>These are some of the public projects that uses libtorrent. If you want your
|
||||
project listed here, let <a class="reference external" href="mailto:arvid@libtorrent.org">me</a> know.</p>
|
||||
<div class="section" id="wyzo">
|
||||
<h1>Wyzo</h1>
|
||||
<p><a class="reference external" href="http://www.wyzo.com/">wyzo</a> is a media browser with built-in bittorrent support.</p>
|
||||
</div>
|
||||
<div class="section" id="deluge">
|
||||
<h1>deluge</h1>
|
||||
<p><a class="reference external" href="http://deluge-torrent.org/">deluge Torrent</a> is a more full-featured yet still lightweight bittorrent
|
||||
client. It has the ability to automatically resume partial downloads and
|
||||
background to the system tray.</p>
|
||||
</div>
|
||||
<div class="section" id="qbittorrent">
|
||||
<h1>qBittorrent</h1>
|
||||
<p><a class="reference external" href="http://www.qbittorrent.org/">qBittorrent</a> is a QT bittorrent client available for linux (likely portable to
|
||||
most other desktops as well). Written by Christophe Dumez.</p>
|
||||
</div>
|
||||
<div class="section" id="tonidoplug">
|
||||
<h1>tonidoplug</h1>
|
||||
<p><a class="reference external" href="http://www.tonidoplug.com/">Tonidoplug</a> is a tiny, low-power, low-cost home server and
|
||||
NAS device powered by Tonido software that allows you to access
|
||||
your apps, files, music and media from anywhere.</p>
|
||||
</div>
|
||||
<div class="section" id="folx">
|
||||
<h1>Folx</h1>
|
||||
<p><a class="reference external" href="http://www.mac-downloader.com/">Folx</a> is a torrent client and download manager for Mac OS X.
|
||||
The Free version of Folx has all the basic functionality of the torrent
|
||||
client, which allows users to download and create torrent files.
|
||||
Folx PRO (available for a small fee) features the possibility to search
|
||||
for torrent files just from Folx interface. So there is no need to
|
||||
browse through multiple torrent trackers searching for particular file.</p>
|
||||
</div>
|
||||
<div class="section" id="miro">
|
||||
<h1>Miro</h1>
|
||||
<p><a class="reference external" href="http://getmiro.com">Miro</a> is a free application for channels of internet video (also known as
|
||||
video podcasts and video rss). Miro is designed to be easy to use and to give
|
||||
you an elegant fullscreen viewing experience.</p>
|
||||
</div>
|
||||
<div class="section" id="moopolice">
|
||||
<h1>MooPolice</h1>
|
||||
<p><a class="reference external" href="http://www.moopolice.de">MooPolice</a> is a windows bittorrent client with a unique look.</p>
|
||||
</div>
|
||||
<div class="section" id="leechcraft">
|
||||
<h1>LeechCraft</h1>
|
||||
<p><a class="reference external" href="http://leechcraft.org/">LeechCraft</a> LeechCraft is a free open source cross-platform extensible
|
||||
software, which primary goal is support of file sharing networks and protocols
|
||||
like HTTP and FTP</p>
|
||||
</div>
|
||||
<div class="section" id="free-download-manager">
|
||||
<h1>Free download manager</h1>
|
||||
<p><a class="reference external" href="http://www.freedownloadmanager.org/">FDM</a> is a powerful, easy-to-use and absolutely free download accelerator and
|
||||
manager. Moreover, FDM is 100% safe, open-source software distributed under
|
||||
GPL License.</p>
|
||||
</div>
|
||||
<div class="section" id="btg">
|
||||
<h1>btg</h1>
|
||||
<p><a class="reference external" href="http://btg.berlios.de//">btg</a> is a unix bittorrent client which is run as a daemon. It has multiple user
|
||||
interfaces which connects to the daemon. One GUI (Gtkmm), one terminal
|
||||
interface (ncurses) and one web interface (accessable through a web browser).
|
||||
Written by Michael Wojciechowski and Johan Strom.</p>
|
||||
</div>
|
||||
<div class="section" id="electric-sheep">
|
||||
<h1>electric sheep</h1>
|
||||
<p><a class="reference external" href="http://electricsheep.org">electric sheep</a> is a screensaver which collectively generates animations and
|
||||
lets the users vote which one to live on.</p>
|
||||
</div>
|
||||
<div class="section" id="tvitty">
|
||||
<h1>Tvitty</h1>
|
||||
<p><a class="reference external" href="http://tvitty.com">tvitty</a> is a bittorrent client for Vista Media Center, which allows
|
||||
searching and downloading of torrents directly on your TV.</p>
|
||||
</div>
|
||||
<div class="section" id="hrktorrent">
|
||||
<h1>hrktorrent</h1>
|
||||
<p><a class="reference external" href="http://50hz.ws/hrktorrent/">hrktorrent</a> hrktorrent is a light console torrent client written in C++.</p>
|
||||
</div>
|
||||
<div class="section" id="fatrat">
|
||||
<h1>FatRat</h1>
|
||||
<p><a class="reference external" href="http://fatrat.dolezel.info">FatRat</a> is an open source download manager for Linux/Unix systems written in
|
||||
C++ with the help of the Trolltech Qt 4 library. It's simple to use and
|
||||
install.</p>
|
||||
</div>
|
||||
<div class="section" id="halite-bittorrent">
|
||||
<h1>halite BitTorrent</h1>
|
||||
<p><a class="reference external" href="http://www.binarynotions.com/halite-bittorrent-client">Halite</a> is a windows bittorrent client controllabel via an xml-rpc
|
||||
interface.</p>
|
||||
</div>
|
||||
<div class="section" id="arctic-torrent">
|
||||
<h1>Arctic Torrent</h1>
|
||||
<p><a class="reference external" href="http://www.int64.org/arctic.html">Arctic Torrent</a> is a light-weight
|
||||
bittorrent client for windows.
|
||||
Written by Cory Nelson.</p>
|
||||
</div>
|
||||
<div class="section" id="bubba">
|
||||
<h1>bubba</h1>
|
||||
<p><a class="reference external" href="http://excito.com/bubba/about-bubba.html">Bubba</a> is a mini-sized server, designed to fit your home better than
|
||||
an always running PC. Boasting Torrent downloader, DAAP streaming,
|
||||
Web, E-mail, printer and FTP server etc.</p>
|
||||
</div>
|
||||
<div class="section" id="tvblob">
|
||||
<h1>tvblob</h1>
|
||||
<p>The <a class="reference external" href="http://www.tvblob.com">BLOBbox</a> represents the ability to harness all of the content available
|
||||
on the web, without any filtering or pre-selection by a third party just
|
||||
like surfing the web.</p>
|
||||
<p>This means that anyone will have the ability to reach viewers via the Internet
|
||||
directly on TV, without them having to connect a PC.</p>
|
||||
</div>
|
||||
<div class="section" id="flush">
|
||||
<h1>Flush</h1>
|
||||
<p><a class="reference external" href="https://sourceforge.net/projects/flush/">Flush</a> is a GTK-based BitTorrent client.</p>
|
||||
</div>
|
||||
<div class="section" id="lince">
|
||||
<h1>Lince</h1>
|
||||
<p><a class="reference external" href="http://lincetorrent.sourceforge.net/">Lince</a> is a bittorrent client using libtorrent to handle bittorrent protocol
|
||||
and gtkmm for the interface, it has been designed to be a light and full
|
||||
featured client.</p>
|
||||
</div>
|
||||
<div class="section" id="linkage">
|
||||
<h1>Linkage</h1>
|
||||
<p><a class="reference external" href="http://code.google.com/p/linkage/">Linkage</a> is a gtkmm client that aims to be middle weight.</p>
|
||||
</div>
|
||||
<div class="section" id="bitfox">
|
||||
<h1>Bitfox</h1>
|
||||
<p><a class="reference external" href="http://code.google.com/p/bitfox/">Bitfox</a> is a firefox plugin integrating bittorrent downloads in firefox.</p>
|
||||
</div>
|
||||
<div class="section" id="bitslug">
|
||||
<h1>BitSlug</h1>
|
||||
<p><a class="reference external" href="http://bitslug.sourceforge.net/">BitSlug</a> is a MacOSX cocoa client.</p>
|
||||
</div>
|
||||
<div class="section" id="delco">
|
||||
<h1>DelCo</h1>
|
||||
<p><a class="reference external" href="http://delco.cs.tut.fi/">DelCo</a> is a research project at Tampere university of technology, finland.</p>
|
||||
</div>
|
||||
<div class="section" id="torrent2exe">
|
||||
<h1>Torrent2Exe</h1>
|
||||
<p><a class="reference external" href="http://torrent2exe.com">Torrent2Exe</a> Torrent2exe is a small BitTorrent client. Its basic idea is to
|
||||
let users download a custom-built EXE program with the torrent file
|
||||
integrated into it.</p>
|
||||
</div>
|
||||
<div class="section" id="zyxel-nsa-220">
|
||||
<h1>ZyXEL NSA-220</h1>
|
||||
<p><a class="reference external" href="http://us.zyxel.com/Products/details.aspx?PC1IndexFlag=20050125090459&CategoryGroupNo=758BFE64-3A95-463C-9E1E-3D30E3B58D9C">ZyXEL</a> NSA220 makes it easy to store, protect and share files between users
|
||||
on your home network. The built-in DLNA server works with many set top boxes
|
||||
to allow you to play back music, watch video files, or view photos on your
|
||||
home theater system, while the built in download manager can automatically
|
||||
download video and audio podcasts as well as allow you to download bittorrent
|
||||
files without needing to leave your computer on.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,209 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>libtorrent python binding</title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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-python-binding">
|
||||
<div id="container">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<div id="main">
|
||||
<h1 class="title">libtorrent python binding</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@libtorrent.org">arvid@libtorrent.org</a></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="#building" id="id2">building</a><ul>
|
||||
<li><a class="reference internal" href="#building-using-setup-py" id="id3">building using setup.py</a></li>
|
||||
<li><a class="reference internal" href="#building-using-boost-build" id="id4">building using boost build</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#using-libtorrent-in-python" id="id5">using libtorrent in python</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="building">
|
||||
<h1>building</h1>
|
||||
<p>Building the libtorrent python bindings will produce a shared library (DLL)
|
||||
which is a python module that can be imported in a python program.</p>
|
||||
<div class="section" id="building-using-setup-py">
|
||||
<h2>building using setup.py</h2>
|
||||
<p>There is a <tt class="docutils literal">setup.py</tt> shipped with libtorrent that can be used on windows.
|
||||
On windows the setup.py will invoke <tt class="docutils literal">bjam</tt> and assume that you have boost
|
||||
sources at <tt class="docutils literal">$BOOST_PATH</tt>. The resulting executable is self-contained, it does
|
||||
not depend any boost or libtorrent dlls.</p>
|
||||
<p>On other systems, the setup.py is generated by running
|
||||
<tt class="docutils literal">./configure <span class="pre">--enable-python-binding</span></tt>.</p>
|
||||
<p>To build the Python bindings do:</p>
|
||||
<ol class="arabic">
|
||||
<li><p class="first">Run:</p>
|
||||
<pre class="literal-block">
|
||||
python setup.py build
|
||||
</pre>
|
||||
</li>
|
||||
<li><p class="first">As root, run:</p>
|
||||
<pre class="literal-block">
|
||||
python setup.py install
|
||||
</pre>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="section" id="building-using-boost-build">
|
||||
<h2>building using boost build</h2>
|
||||
<p>To set up your build environment, you need to add some settings to your
|
||||
<tt class="docutils literal"><span class="pre">$BOOST_BUILD_PATH/user-config.jam</span></tt>.</p>
|
||||
<p>Make sure your user config contains the following line:</p>
|
||||
<pre class="literal-block">
|
||||
using python : 2.3 ;
|
||||
</pre>
|
||||
<p>Set the version to the version of python you have installed or want to use. If
|
||||
you've installed python in a non-standard location, you have to add the prefix
|
||||
path used when you installed python as a second option. Like this:</p>
|
||||
<pre class="literal-block">
|
||||
using python : 2.6 : /usr/bin/python2.6 : /usr/include/python2.6 : /usr/lib/python2.6 ;
|
||||
</pre>
|
||||
<p>The bindings require <em>at least</em> python version 2.2.</p>
|
||||
<p>For more information on how to install and set up boost-build, see the
|
||||
<a class="reference external" href="building.html#step-2-setup-bbv2">building libtorrent</a> section.</p>
|
||||
<p>Once you have boost-build set up, you cd to the <tt class="docutils literal">bindings/python</tt>
|
||||
directory and invoke <tt class="docutils literal">bjam</tt> with the apropriate settings. For the available
|
||||
build variants, see <a class="reference external" href="building.html#step-3-building-libtorrent">libtorrent build options</a>.</p>
|
||||
<p>For example:</p>
|
||||
<pre class="literal-block">
|
||||
$ bjam dht-support=on link=static
|
||||
</pre>
|
||||
<p>On Mac OS X, this will produce the following python module:</p>
|
||||
<pre class="literal-block">
|
||||
bin/darwin-4.0/release/dht-support-on/link-static/logging-none/threading-multi/libtorrent.so
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="using-libtorrent-in-python">
|
||||
<h1>using libtorrent in python</h1>
|
||||
<p>The python interface is nearly identical to the C++ interface. Please refer to
|
||||
the <a class="reference external" href="reference.html">library reference</a>. The main differences are:</p>
|
||||
<dl class="docutils">
|
||||
<dt>asio::tcp::endpoint</dt>
|
||||
<dd>The endpoint type is represented as a tuple of a string (as the address) and an int for
|
||||
the port number. E.g. <tt class="docutils literal">('127.0.0.1', 6881)</tt> represents the localhost port 6881.</dd>
|
||||
<dt>libtorrent::time_duration</dt>
|
||||
<dd>The time duration is represented as a number of seconds in a regular integer.</dd>
|
||||
</dl>
|
||||
<p>The following functions takes a reference to a container that is filled with
|
||||
entries by the function. The python equivalent of these functions instead returns
|
||||
a list of entries.</p>
|
||||
<ul class="simple">
|
||||
<li>torrent_handle::get_peer_info</li>
|
||||
<li>torrent_handle::file_progress</li>
|
||||
<li>torrent_handle::get_download_queue</li>
|
||||
<li>torrent_handle::piece_availability</li>
|
||||
</ul>
|
||||
<p><tt class="docutils literal"><span class="pre">create_torrent::add_node()</span></tt> takes two arguments, one string and one integer,
|
||||
instead of a pair. The string is the address and the integer is the port.</p>
|
||||
<p><tt class="docutils literal"><span class="pre">session::set_settings()</span></tt> not only accepts a <tt class="docutils literal">session_settings</tt> object, but also
|
||||
a dictionary with keys matching the names of the members of the <tt class="docutils literal">session_settings</tt> struct.
|
||||
When calling <tt class="docutils literal">set_settings</tt>, the dictionary does not need to have every settings set,
|
||||
keys that are not present, are set to their default value.</p>
|
||||
<p>For backwards compatibility, <tt class="docutils literal"><span class="pre">session::settings()</span></tt> still returns a <tt class="docutils literal">session_settings</tt>
|
||||
struct. To get a python dictionary of the settings, call <tt class="docutils literal"><span class="pre">session::get_settings</span></tt>.</p>
|
||||
<p>For an example python program, see <tt class="docutils literal">client.py</tt> in the <tt class="docutils literal">bindings/python</tt>
|
||||
directory.</p>
|
||||
<p>A very simple example usage of the module would be something like this:</p>
|
||||
<pre class="literal-block">
|
||||
import libtorrent as lt
|
||||
import time
|
||||
|
||||
ses = lt.session()
|
||||
ses.listen_on(6881, 6891)
|
||||
|
||||
e = lt.bdecode(open("test.torrent", 'rb').read())
|
||||
info = lt.torrent_info(e)
|
||||
|
||||
params = { 'save_path': '.', \
|
||||
'storage_mode': lt.storage_mode_t.storage_mode_sparse, \
|
||||
'ti': info }
|
||||
h = ses.add_torrent(params)
|
||||
|
||||
s = h.status()
|
||||
while (not s.is_seeding):
|
||||
s = h.status()
|
||||
|
||||
state_str = ['queued', 'checking', 'downloading metadata', \
|
||||
'downloading', 'finished', 'seeding', 'allocating']
|
||||
print '%.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s' % \
|
||||
(s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, \
|
||||
s.num_peers, state_str[s.state])
|
||||
|
||||
time.sleep(1)
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -98,13 +98,12 @@ a list of entries.
|
|||
``create_torrent::add_node()`` takes two arguments, one string and one integer,
|
||||
instead of a pair. The string is the address and the integer is the port.
|
||||
|
||||
``session::set_settings()`` not only accepts a ``session_settings`` object, but also
|
||||
a dictionary with keys matching the names of the members of the ``session_settings`` struct.
|
||||
When calling ``set_settings``, the dictionary does not need to have every settings set,
|
||||
keys that are not present, are set to their default value.
|
||||
``session::apply_settings()`` accepts a dictionary with keys matching the names
|
||||
of settings in settings_pack.
|
||||
When calling ``apply_settings``, the dictionary does not need to have every settings set,
|
||||
keys that are not present are not updated.
|
||||
|
||||
For backwards compatibility, ``session::settings()`` still returns a ``session_settings``
|
||||
struct. To get a python dictionary of the settings, call ``session::get_settings``.
|
||||
To get a python dictionary of the settings, call ``session::get_settings``.
|
||||
|
||||
.. _`library reference`: reference.html
|
||||
|
||||
|
|
3268
docs/settings.rst
10465
docs/todo.html
|
@ -28,7 +28,7 @@ digraph no_download {
|
|||
node_upload_mode [label="Is the torrent in upload mode?\n(torrent_status::upload_mode)"];
|
||||
node_bwstate [label="What is the peer read_state set to?\n(peer_info::read_state)"];
|
||||
|
||||
node_dl_limit [label="There is a download rate limit in affect on your peers.\nDo you have a download rate limit set?\n(session_settings::download_rate_limit)"];
|
||||
node_dl_limit [label="There is a download rate limit in affect on your peers.\nDo you have a download rate limit set?\n(settings_pack::download_rate_limit)"];
|
||||
|
||||
node_dl_disk [label="Peers are blocked waiting on the disk.\nThis typically means your disk is overloaded"];
|
||||
|
||||
|
@ -36,7 +36,7 @@ digraph no_download {
|
|||
|
||||
// end states
|
||||
|
||||
node_end_queued [label="This means the torrent is 'queued'. i.e. it will\nbe started once the torrents in front of it\ncompletes downloading. To know the queue\norder, see torrent_status::queue_position. To\nconfigure the number of simultaneous downloads,\nsee session_settings::active_limit and\nsession_settings::active_downloads."];
|
||||
node_end_queued [label="This means the torrent is 'queued'. i.e. it will\nbe started once the torrents in front of it\ncompletes downloading. To know the queue\norder, see torrent_status::queue_position. To\nconfigure the number of simultaneous downloads,\nsee settings_pack::active_limit and\nsettings_pack::active_downloads."];
|
||||
|
||||
node_end_stopped [label="This means the torrent is\n'stopped'. To start it call\ntorrent_handle::resume()."];
|
||||
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>libtorrent manual</title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<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@libtorrent.org">arvid@libtorrent.org</a></td></tr>
|
||||
<tr><th class="docinfo-name">Version:</th>
|
||||
<td>1.1.0</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The following troubleshooting chart may help in finding out why torrents fail
|
||||
to download. It is not complete, please submit suggestions via mail to
|
||||
<a class="reference external" href="mailto:arvid@libtorrent.org">arvid@libtorrent.org</a> or to the <a class="reference external" href="http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss">mailing list</a>. Ideally in the form of patches
|
||||
against <tt class="docutils literal">docs/troubleshooting.dot</tt>.</p>
|
||||
<p><a class="reference external" href="troubleshooting.png"><img alt="thumb" src="troubleshooting_thumb.png" /></a></p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 365 KiB |
628
docs/tuning.html
|
@ -1,628 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>libtorrent manual</title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<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@libtorrent.org">arvid@libtorrent.org</a></td></tr>
|
||||
<tr><th class="docinfo-name">Version:</th>
|
||||
<td>1.1.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="#tuning-libtorrent" id="id1">tuning libtorrent</a></li>
|
||||
<li><a class="reference internal" href="#reducing-memory-footprint" id="id2">reducing memory footprint</a><ul>
|
||||
<li><a class="reference internal" href="#disable-disk-cache" id="id3">disable disk cache</a></li>
|
||||
<li><a class="reference internal" href="#remove-torrents" id="id4">remove torrents</a></li>
|
||||
<li><a class="reference internal" href="#socket-buffer-sizes" id="id5">socket buffer sizes</a></li>
|
||||
<li><a class="reference internal" href="#peer-list-size" id="id6">peer list size</a></li>
|
||||
<li><a class="reference internal" href="#send-buffer-watermark" id="id7">send buffer watermark</a></li>
|
||||
<li><a class="reference internal" href="#optimize-hashing-for-memory-usage" id="id8">optimize hashing for memory usage</a></li>
|
||||
<li><a class="reference internal" href="#reduce-executable-size" id="id9">reduce executable size</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#play-nice-with-the-disk" id="id10">play nice with the disk</a></li>
|
||||
<li><a class="reference internal" href="#high-performance-seeding" id="id11">high performance seeding</a><ul>
|
||||
<li><a class="reference internal" href="#file-pool" id="id12">file pool</a></li>
|
||||
<li><a class="reference internal" href="#disk-cache" id="id13">disk cache</a></li>
|
||||
<li><a class="reference internal" href="#ssd-as-level-2-cache" id="id14">SSD as level 2 cache</a></li>
|
||||
<li><a class="reference internal" href="#utp-tcp-mixed-mode" id="id15">uTP-TCP mixed mode</a></li>
|
||||
<li><a class="reference internal" href="#send-buffer-low-watermark" id="id16">send buffer low watermark</a></li>
|
||||
<li><a class="reference internal" href="#peers" id="id17">peers</a></li>
|
||||
<li><a class="reference internal" href="#torrent-limits" id="id18">torrent limits</a></li>
|
||||
<li><a class="reference internal" href="#sha-1-hashing" id="id19">SHA-1 hashing</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#scalability" id="id20">scalability</a></li>
|
||||
<li><a class="reference internal" href="#benchmarking" id="id21">benchmarking</a><ul>
|
||||
<li><a class="reference internal" href="#disk-metrics" id="id22">disk metrics</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#understanding-the-disk-threads" id="id23">understanding the disk threads</a></li>
|
||||
<li><a class="reference internal" href="#contributions" id="id24">contributions</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="tuning-libtorrent">
|
||||
<h1>tuning libtorrent</h1>
|
||||
<p>libtorrent expose most constants used in the bittorrent engine for
|
||||
customization through the <tt class="docutils literal">session_settings</tt>. This makes it possible to
|
||||
test and tweak the parameters for certain algorithms to make a client
|
||||
that fits a wide range of needs. From low memory embedded devices to
|
||||
servers seeding thousands of torrents. The default settings in libtorrent
|
||||
are tuned for an end-user bittorrent client running on a normal desktop
|
||||
computer.</p>
|
||||
<p>This document describes techniques to benchmark libtorrent performance
|
||||
and how parameters are likely to affect it.</p>
|
||||
</div>
|
||||
<div class="section" id="reducing-memory-footprint">
|
||||
<h1>reducing memory footprint</h1>
|
||||
<p>These are things you can do to reduce the memory footprint of libtorrent. You get
|
||||
some of this by basing your default <tt class="docutils literal">session_settings</tt> on the <tt class="docutils literal">min_memory_usage()</tt>
|
||||
setting preset function.</p>
|
||||
<p>Keep in mind that lowering memory usage will affect performance, always profile
|
||||
and benchmark your settings to determine if it's worth the trade-off.</p>
|
||||
<p>The typical buffer usage of libtorrent, for a single download, with the cache
|
||||
size set to 256 blocks (256 * 16 kiB = 4 MiB) is:</p>
|
||||
<pre class="literal-block">
|
||||
read cache: 128.6 (2058 kiB)
|
||||
write cache: 103.5 (1656 kiB)
|
||||
receive buffers: 7.3 (117 kiB)
|
||||
send buffers: 4.8 (77 kiB)
|
||||
hash temp: 0.001 (19 Bytes)
|
||||
</pre>
|
||||
<p>The receive buffers is proportional to the number of connections we make, and is
|
||||
limited by the total number of connections in the session (default is 200).</p>
|
||||
<p>The send buffers is proportional to the number of upload slots that are allowed
|
||||
in the session. The default is auto configured based on the observed upload rate.</p>
|
||||
<p>The read and write cache can be controlled (see section below).</p>
|
||||
<p>The "hash temp" entry size depends on whether or not hashing is optimized for
|
||||
speed or memory usage. In this test run it was optimized for memory usage.</p>
|
||||
<div class="section" id="disable-disk-cache">
|
||||
<h2>disable disk cache</h2>
|
||||
<p>The bulk of the memory libtorrent will use is used for the disk cache. To save
|
||||
the absolute most amount of memory, you can disable the cache by setting
|
||||
<tt class="docutils literal"><span class="pre">session_settings::cache_size</span></tt> to 0. You might want to consider using the cache
|
||||
but just disable caching read operations. You do this by settings
|
||||
<tt class="docutils literal"><span class="pre">session_settings::use_read_cache</span></tt> to false. This is the main factor in how much
|
||||
memory will be used by the client. Keep in mind that you will degrade performance
|
||||
by disabling the cache. You should benchmark the disk access in order to make an
|
||||
informed trade-off.</p>
|
||||
</div>
|
||||
<div class="section" id="remove-torrents">
|
||||
<h2>remove torrents</h2>
|
||||
<p>Torrents that have been added to libtorrent will inevitably use up memory, even
|
||||
when it's paused. A paused torrent will not use any peer connection objects or
|
||||
any send or receive buffers though. Any added torrent holds the entire .torrent
|
||||
file in memory, it also remembers the entire list of peers that it's heard about
|
||||
(which can be fairly long unless it's capped). It also retains information about
|
||||
which blocks and pieces we have on disk, which can be significant for torrents
|
||||
with many pieces.</p>
|
||||
<p>If you need to minimize the memory footprint, consider removing torrents from
|
||||
the session rather than pausing them. This will likely only make a difference
|
||||
when you have a very large number of torrents in a session.</p>
|
||||
<p>The downside of removing them is that they will no longer be auto-managed. Paused
|
||||
auto managed torrents are scraped periodically, to determine which torrents are
|
||||
in the greatest need of seeding, and libtorrent will prioritize to seed those.</p>
|
||||
</div>
|
||||
<div class="section" id="socket-buffer-sizes">
|
||||
<h2>socket buffer sizes</h2>
|
||||
<p>You can make libtorrent explicitly set the kernel buffer sizes of all its peer
|
||||
sockets. If you set this to a low number, you may see reduced throughput, especially
|
||||
for high latency connections. It is however an opportunity to save memory per
|
||||
connection, and might be worth considering if you have a very large number of
|
||||
peer connections. This memory will not be visible in your process, this sets
|
||||
the amount of kernel memory is used for your sockets.</p>
|
||||
<p>Change this by setting <tt class="docutils literal"><span class="pre">session_settings::recv_socket_buffer_size</span></tt> and
|
||||
<tt class="docutils literal"><span class="pre">session_settings::send_socket_buffer_size</span></tt>.</p>
|
||||
</div>
|
||||
<div class="section" id="peer-list-size">
|
||||
<h2>peer list size</h2>
|
||||
<p>The default maximum for the peer list is 4000 peers. For IPv4 peers, each peer
|
||||
entry uses 32 bytes, which ends up using 128 kB per torrent. If seeding 4 popular
|
||||
torrents, the peer lists alone uses about half a megabyte.</p>
|
||||
<p>The default limit is the same for paused torrents as well, so if you have a
|
||||
large number of paused torrents (that are popular) it will be even more
|
||||
significant.</p>
|
||||
<p>If you're short of memory, you should consider lowering the limit. 500 is probably
|
||||
enough. You can do this by setting <tt class="docutils literal"><span class="pre">session_settings::max_peerlist_size</span></tt> to
|
||||
the max number of peers you want in a torrent's peer list. This limit applies per
|
||||
torrent. For 5 torrents, the total number of peers in peerlists will be 5 times
|
||||
the setting.</p>
|
||||
<p>You should also lower the same limit but for paused torrents. It might even make sense
|
||||
to set that even lower, since you only need a few peers to start up while waiting
|
||||
for the tracker and DHT to give you fresh ones. The max peer list size for paused
|
||||
torrents is set by <tt class="docutils literal"><span class="pre">session_settings::max_paused_peerlist_size</span></tt>.</p>
|
||||
<p>The drawback of lowering this number is that if you end up in a position where
|
||||
the tracker is down for an extended period of time, your only hope of finding live
|
||||
peers is to go through your list of all peers you've ever seen. Having a large
|
||||
peer list will also help increase performance when starting up, since the torrent
|
||||
can start connecting to peers in parallel with connecting to the tracker.</p>
|
||||
</div>
|
||||
<div class="section" id="send-buffer-watermark">
|
||||
<h2>send buffer watermark</h2>
|
||||
<p>The send buffer watermark controls when libtorrent will ask the disk I/O thread
|
||||
to read blocks from disk, and append it to a peer's send buffer.</p>
|
||||
<p>When the send buffer has fewer than or equal number of bytes as
|
||||
<tt class="docutils literal"><span class="pre">session_settings::send_buffer_watermark</span></tt>, the peer will ask the disk I/O thread
|
||||
for more data to send. The trade-off here is between wasting memory by having too
|
||||
much data in the send buffer, and hurting send rate by starving out the socket,
|
||||
waiting for the disk read operation to complete.</p>
|
||||
<p>If your main objective is memory usage and you're not concerned about being able
|
||||
to achieve high send rates, you can set the watermark to 9 bytes. This will guarantee
|
||||
that no more than a single (16 kiB) block will be on the send buffer at a time, for
|
||||
all peers. This is the least amount of memory possible for the send buffer.</p>
|
||||
<p>You should benchmark your max send rate when adjusting this setting. If you have
|
||||
a very fast disk, you are less likely see a performance hit.</p>
|
||||
</div>
|
||||
<div class="section" id="optimize-hashing-for-memory-usage">
|
||||
<h2>optimize hashing for memory usage</h2>
|
||||
<p>When libtorrent is doing hash checks of a file, or when it re-reads a piece that
|
||||
was just completed to verify its hash, there are two options. The default one
|
||||
is optimized for speed, which allocates buffers for the entire piece, reads in
|
||||
the whole piece in one read call, then hashes it.</p>
|
||||
<p>The second option is to optimize for memory usage instead, where a single buffer
|
||||
is allocated, and the piece is read one block at a time, hashing it as each
|
||||
block is read from the file. For low memory environments, this latter approach
|
||||
is recommended. Change this by settings <tt class="docutils literal"><span class="pre">session_settings::optimize_hashing_for_speed</span></tt>
|
||||
to false. This will significantly reduce peak memory usage, especially for
|
||||
torrents with very large pieces.</p>
|
||||
</div>
|
||||
<div class="section" id="reduce-executable-size">
|
||||
<h2>reduce executable size</h2>
|
||||
<p>Compilers generally add a significant number of bytes to executables that make use
|
||||
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
|
||||
support, you need to patch parts of boost.</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">TORRENT_*</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">TORRENT_NO_DEPRECATE</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="play-nice-with-the-disk">
|
||||
<h1>play nice with the disk</h1>
|
||||
<p>When checking a torrent, libtorrent will try to read as fast as possible from the disk.
|
||||
The only thing that might hold it back is a CPU that is slow at calculating SHA-1 hashes,
|
||||
but typically the file checking is limited by disk read speed. Most operating systems
|
||||
today do not prioritize disk access based on the importance of the operation, this means
|
||||
that checking a torrent might delay other disk accesses, such as virtual memory swapping
|
||||
or just loading file by other (interactive) applications.</p>
|
||||
<p>In order to play nicer with the disk, and leave some spare time for it to service other
|
||||
processes that might be of higher importance to the end-user, you can introduce a sleep
|
||||
between the disc accesses. This is a direct tradeoff between how fast you can check a
|
||||
torrent and how soft you will hit the disk.</p>
|
||||
<p>You control this by setting the <tt class="docutils literal"><span class="pre">session_settings::file_checks_delay_per_block</span></tt> to greater
|
||||
than zero. This number is the number of milliseconds to sleep between each read of 16 kiB.</p>
|
||||
<p>The sleeps are not necessarily in between each 16 kiB block (it might be read in larger chunks),
|
||||
but the number will be multiplied by the number of blocks that were read, to maintain the
|
||||
same semantics.</p>
|
||||
</div>
|
||||
<div class="section" id="high-performance-seeding">
|
||||
<h1>high performance seeding</h1>
|
||||
<p>In the case of a high volume seed, there are two main concerns. Performance and scalability.
|
||||
This translates into high send rates, and low memory and CPU usage per peer connection.</p>
|
||||
<div class="section" id="file-pool">
|
||||
<h2>file pool</h2>
|
||||
<p>libtorrent keeps an LRU file cache. Each file that is opened, is stuck in the cache. The main
|
||||
purpose of this is because of anti-virus software that hooks on file-open and file close to
|
||||
scan the file. Anti-virus software that does that will significantly increase the cost of
|
||||
opening and closing files. However, for a high performance seed, the file open/close might
|
||||
be so frequent that it becomes a significant cost. It might therefore be a good idea to allow
|
||||
a large file descriptor cache. Adjust this though <tt class="docutils literal"><span class="pre">session_settings::file_pool_size</span></tt>.</p>
|
||||
<p>Don't forget to set a high rlimit for file descriptors in your process as well. This limit
|
||||
must be high enough to keep all connections and files open.</p>
|
||||
</div>
|
||||
<div class="section" id="disk-cache">
|
||||
<h2>disk cache</h2>
|
||||
<p>You typically want to set the cache size to as high as possible. The
|
||||
<tt class="docutils literal"><span class="pre">session_settings::cache_size</span></tt> is specified in 16 kiB blocks. Since you're seeding,
|
||||
the cache would be useless unless you also set <tt class="docutils literal"><span class="pre">session_settings::use_read_cache</span></tt>
|
||||
to true.</p>
|
||||
<p>In order to increase the possibility of read cache hits, set the
|
||||
<tt class="docutils literal"><span class="pre">session_settings::cache_expiry</span></tt> to a large number. This won't degrade anything as
|
||||
long as the client is only seeding, and not downloading any torrents.</p>
|
||||
<p>In order to increase the disk cache hit rate, you can enable suggest messages based on
|
||||
what's in the read cache. To do this, set <tt class="docutils literal"><span class="pre">session_settings::suggest_mode</span></tt> to
|
||||
<tt class="docutils literal"><span class="pre">session_settings::suggest_read_cache</span></tt>. This will send suggest messages to peers
|
||||
for the most recently used pieces in the read cache. This is especially useful if you
|
||||
also enable explicit read cache, by settings <tt class="docutils literal"><span class="pre">session_settings::explicit_read_cache</span></tt>
|
||||
to the number of pieces to keep in the cache. The explicit read cache will make the
|
||||
disk read cache stick, and not be evicted by cache misses. The explicit read cache
|
||||
will automatically pull in the rarest pieces in the read cache.</p>
|
||||
<p>Assuming that you seed much more data than you can keep in the cache, to a large
|
||||
numbers of peers (so that the read cache wouldn't be useful anyway), this may be a
|
||||
good idea.</p>
|
||||
<p>When peers first connect, libtorrent will send them a number of allow-fast messages,
|
||||
which lets the peers download certain pieces even when they are choked, since peers
|
||||
are choked by default, this often triggers immediate requests for those pieces. In the
|
||||
case of using explicit read cache and suggesting those pieces, allowing fast pieces
|
||||
should be disabled, to not systematically trigger requests for pieces that are not cached
|
||||
for all peers. You can turn off allow-fast by settings <tt class="docutils literal"><span class="pre">session_settings::allowed_fast_set_size</span></tt>
|
||||
to 0.</p>
|
||||
<p>As an alternative to the explicit cache and suggest messages, there's a <em>guided cache</em>
|
||||
mode. This means the size of the read cache line that's stored in the cache is determined
|
||||
based on the upload rate to the peer that triggered the read operation. The idea being
|
||||
that slow peers don't use up a disproportional amount of space in the cache. This
|
||||
is enabled through <tt class="docutils literal"><span class="pre">session_settings::guided_read_cache</span></tt>.</p>
|
||||
<p>In cases where the assumption is that the cache is only used as a read-ahead, and that no
|
||||
other peer will ever request the same block while it's still in the cache, the read
|
||||
cache can be set to be <em>volatile</em>. This means that every block that is requested out of
|
||||
the read cache is removed immediately. This saves a significant amount of cache space
|
||||
which can be used as read-ahead for other peers. This mode should <strong>never</strong> be combined
|
||||
with either <tt class="docutils literal">explicit_read_cache</tt> or <tt class="docutils literal">suggest_read_cache</tt>, since those uses opposite
|
||||
strategies for the read cache. You don't want to on one hand attract peers to request
|
||||
the same pieces, and on the other hand assume that they won't request the same pieces
|
||||
and drop them when the first peer requests it. To enable volatile read cache, set
|
||||
<tt class="docutils literal"><span class="pre">session_settings::volatile_read_cache</span></tt> to true.</p>
|
||||
</div>
|
||||
<div class="section" id="ssd-as-level-2-cache">
|
||||
<h2>SSD as level 2 cache</h2>
|
||||
<p>It is possible to introduce a second level of cache, below the RAM disk cache. This is done
|
||||
by setting <tt class="docutils literal"><span class="pre">session_settings::mmap_cache</span></tt> to a file path pointing to the SSD drive, and
|
||||
increasing the <tt class="docutils literal"><span class="pre">session_settings::cache_size</span></tt> to the number of 16 kiB blocks would fit
|
||||
on the drive (or less).</p>
|
||||
<p>This will allocate disk buffers (for reading and writing) from a memory region that has
|
||||
been mapped to the specified file. If the drive this file lives on is not significantly
|
||||
faster than the destination drive, performance will be degraded. The point is to take
|
||||
advantage primarily of the fast read speed from SSD drives and use it to extend the read
|
||||
cache, improving seed performance.</p>
|
||||
<p>Which parts of the cache that actually live in RAM is determined by the operating system.</p>
|
||||
<p>Note that when using this feature, any block which ends up being pulled from the mmapped
|
||||
file will be considered a cache hit.</p>
|
||||
</div>
|
||||
<div class="section" id="utp-tcp-mixed-mode">
|
||||
<h2>uTP-TCP mixed mode</h2>
|
||||
<p>libtorrent supports <a class="reference external" href="utp.html">uTP</a>, which has a delay based congestion controller. In order to
|
||||
avoid having a single TCP bittorrent connection completely starve out any uTP connection,
|
||||
there is a mixed mode algorithm. This attempts to detect congestion on the uTP peers and
|
||||
throttle TCP to avoid it taking over all bandwidth. This balances the bandwidth resources
|
||||
between the two protocols. When running on a network where the bandwidth is in such an
|
||||
abundance that it's virtually infinite, this algorithm is no longer necessary, and might
|
||||
even be harmful to throughput. It is adviced to experiment with the
|
||||
<tt class="docutils literal"><span class="pre">session_setting::mixed_mode_algorithm</span></tt>, setting it to <tt class="docutils literal"><span class="pre">session_settings::prefer_tcp</span></tt>.
|
||||
This setting entirely disables the balancing and unthrottles all connections. On a typical
|
||||
home connection, this would mean that none of the benefits of uTP would be preserved
|
||||
(the modem's send buffer would be full at all times) and uTP connections would for the most
|
||||
part be squashed by the TCP traffic.</p>
|
||||
</div>
|
||||
<div class="section" id="send-buffer-low-watermark">
|
||||
<h2>send buffer low watermark</h2>
|
||||
<p>libtorrent uses a low watermark for send buffers to determine when a new piece should
|
||||
be requested from the disk I/O subsystem, to be appended to the send buffer. The low
|
||||
watermark is determined based on the send rate of the socket. It needs to be large
|
||||
enough to not draining the socket's send buffer before the disk operation completes.</p>
|
||||
<p>The watermark is bound to a max value, to avoid buffer sizes growing out of control.
|
||||
The default max send buffer size might not be enough to sustain very high upload rates,
|
||||
and you might have to increase it. It's specified in bytes in
|
||||
<tt class="docutils literal"><span class="pre">session_settings::send_buffer_watermark</span></tt>.</p>
|
||||
</div>
|
||||
<div class="section" id="peers">
|
||||
<h2>peers</h2>
|
||||
<p>First of all, in order to allow many connections, set the global connection limit
|
||||
high, <tt class="docutils literal"><span class="pre">session::set_max_connections()</span></tt>. Also set the upload rate limit to
|
||||
infinite, <tt class="docutils literal"><span class="pre">session::set_upload_rate_limit()</span></tt>, passing 0 means infinite.</p>
|
||||
<p>When dealing with a large number of peers, it might be a good idea to have slightly
|
||||
stricter timeouts, to get rid of lingering connections as soon as possible.</p>
|
||||
<p>There are a couple of relevant settings: <tt class="docutils literal"><span class="pre">session_settings::request_timeout</span></tt>,
|
||||
<tt class="docutils literal"><span class="pre">session_settings::peer_timeout</span></tt> and <tt class="docutils literal"><span class="pre">session_settings::inactivity_timeout</span></tt>.</p>
|
||||
<p>For seeds that are critical for a delivery system, you most likely want to allow
|
||||
multiple connections from the same IP. That way two people from behind the same NAT
|
||||
can use the service simultaneously. This is controlled by
|
||||
<tt class="docutils literal"><span class="pre">session_settings::allow_multiple_connections_per_ip</span></tt>.</p>
|
||||
<p>In order to always unchoke peers, turn off automatic unchoke
|
||||
<tt class="docutils literal"><span class="pre">session_settings::auto_upload_slots</span></tt> and set the number of upload slots to a large
|
||||
number via <tt class="docutils literal"><span class="pre">session::set_max_uploads()</span></tt>, or use -1 (which means infinite).</p>
|
||||
</div>
|
||||
<div class="section" id="torrent-limits">
|
||||
<h2>torrent limits</h2>
|
||||
<p>To seed thousands of torrents, you need to increase the <tt class="docutils literal"><span class="pre">session_settings::active_limit</span></tt>
|
||||
and <tt class="docutils literal"><span class="pre">session_settings::active_seeds</span></tt>.</p>
|
||||
</div>
|
||||
<div class="section" id="sha-1-hashing">
|
||||
<h2>SHA-1 hashing</h2>
|
||||
<p>When downloading at very high rates, it is possible to have the CPU be the bottleneck
|
||||
for passing every downloaded byte through SHA-1. In order to enable calculating SHA-1
|
||||
hashes in parallel, on multi-core systems, set <tt class="docutils literal"><span class="pre">session_settings::hashing_threads</span></tt>
|
||||
to the number of threads libtorrent should start to do SHA-1 hashing. This defaults
|
||||
to 1, and only if that thread is close to saturating one core does it make sense to
|
||||
increase the number of threads.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="scalability">
|
||||
<h1>scalability</h1>
|
||||
<p>In order to make more efficient use of the libtorrent interface when running a large
|
||||
number of torrents simultaneously, one can use the <tt class="docutils literal"><span class="pre">session::get_torrent_status()</span></tt> call
|
||||
together with <tt class="docutils literal"><span class="pre">session::refresh_torrent_status()</span></tt>. Keep in mind that every call into
|
||||
libtorrent that return some value have to block your thread while posting a message to
|
||||
the main network thread and then wait for a response (calls that don't return any data
|
||||
will simply post the message and then immediately return). The time this takes might
|
||||
become significant once you reach a few hundred torrents (depending on how many calls
|
||||
you make to each torrent and how often). <tt class="docutils literal">get_torrent_status</tt> lets you query the
|
||||
status of all torrents in a single call. This will actually loop through all torrents
|
||||
and run a provided predicate function to determine whether or not to include it in
|
||||
the returned vector. If you have a lot of torrents, you might want to update the status
|
||||
of only certain torrents. For instance, you might only be interested in torrents that
|
||||
are being downloaded.</p>
|
||||
<p>The intended use of these functions is to start off by calling <tt class="docutils literal">get_torrent_status</tt>
|
||||
to get a list of all torrents that match your criteria. Then call <tt class="docutils literal">refresh_torrent_status</tt>
|
||||
on that list. This will only refresh the status for the torrents in your list, and thus
|
||||
ignore all other torrents you might be running. This may save a significant amount of
|
||||
time, especially if the number of torrents you're interested in is small. In order to
|
||||
keep your list of interested torrents up to date, you can either call <tt class="docutils literal">get_torrent_status</tt>
|
||||
from time to time, to include torrents you might have become interested in since the last
|
||||
time. In order to stop refreshing a certain torrent, simply remove it from the list.</p>
|
||||
<p>A more efficient way however, would be to subscribe to status alert notifications, and
|
||||
update your list based on these alerts. There are alerts for when torrents are added, removed,
|
||||
paused, resumed, completed etc. Doing this ensures that you only query status for the
|
||||
minimal set of torrents you are actually interested in.</p>
|
||||
</div>
|
||||
<div class="section" id="benchmarking">
|
||||
<h1>benchmarking</h1>
|
||||
<p>There is a bunch of built-in instrumentation of libtorrent that can be used to get an insight
|
||||
into what it's doing and how well it performs. This instrumentation is enabled by defining
|
||||
preprocessor symbols when building.</p>
|
||||
<p>There are also a number of scripts that parses the log files and generates graphs (requires
|
||||
gnuplot and python).</p>
|
||||
<div class="section" id="disk-metrics">
|
||||
<h2>disk metrics</h2>
|
||||
<p>To enable disk I/O instrumentation, define <tt class="docutils literal">TORRENT_DISK_STATS</tt> when building. When built
|
||||
with this configuration libtorrent will create three log files, measuring various aspects of
|
||||
the disk I/O. The following table is an overview of these files and what they measure.</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="30%" />
|
||||
<col width="70%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">filename</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td><tt class="docutils literal">disk_io_thread.log</tt></td>
|
||||
<td>This is a log of which operation the disk I/O thread is
|
||||
engaged in, with timestamps. This tells you what the thread
|
||||
is spending its time doing.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">disk_buffers.log</tt></td>
|
||||
<td>This log keeps track of what the buffers allocated from the
|
||||
disk buffer pool are used for. There are 5 categories.
|
||||
receive buffer, send buffer, write cache, read cache and
|
||||
temporary hash storage. This is key when optimizing memory
|
||||
usage.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">disk_access.log</tt></td>
|
||||
<td>This is a low level log of read and write operations, with
|
||||
timestamps and file offsets. The file offsets are byte
|
||||
offsets in the torrent (not in any particular file, in the
|
||||
case of a multi-file torrent). This can be used as an
|
||||
estimate of the physical drive location. The purpose of
|
||||
this log is to identify the amount of seeking the drive has
|
||||
to do.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="section" id="disk-io-thread-log">
|
||||
<h3>disk_io_thread.log</h3>
|
||||
<p>The structure of this log is simple. For each line, there are two columns, a timestamp and
|
||||
the operation that was started. There is a special operation called <tt class="docutils literal">idle</tt> which means
|
||||
it looped back to the top and started waiting for new jobs. If there are more jobs to
|
||||
handle immediately, the <tt class="docutils literal">idle</tt> state is still there, but the timestamp is the same as the
|
||||
next job that is handled.</p>
|
||||
<p>Some operations have a 3:rd column with an optional parameter. <tt class="docutils literal">read</tt> and <tt class="docutils literal">write</tt> tells
|
||||
you the number of bytes that were requested to be read or written. <tt class="docutils literal">flushing</tt> tells you
|
||||
the number of bytes that were flushed from the disk cache.</p>
|
||||
<p>This is an example excerpt from a log:</p>
|
||||
<pre class="literal-block">
|
||||
3702 idle
|
||||
3706 check_fastresume
|
||||
3707 idle
|
||||
4708 save_resume_data
|
||||
4708 idle
|
||||
8230 read 16384
|
||||
8255 idle
|
||||
8431 read 16384
|
||||
</pre>
|
||||
<p>The script to parse this log and generate a graph is called <tt class="docutils literal">parse_disk_log.py</tt>. It takes
|
||||
the log file as the first command line argument, and produces a file: <tt class="docutils literal">disk_io.png</tt>.
|
||||
The time stamp is in milliseconds since start.</p>
|
||||
<p>You can pass in a second, optional, argument to specify the window size it will average
|
||||
the time measurements over. The default is 5 seconds. For long test runs, it might be interesting
|
||||
to increase that number. It is specified as a number of seconds.</p>
|
||||
<img alt="disk_io.png" src="disk_io.png" />
|
||||
<p>This is an example graph generated by the parse script.</p>
|
||||
</div>
|
||||
<div class="section" id="disk-buffers-log">
|
||||
<h3>disk_buffers.log</h3>
|
||||
<p>The disk buffer log tells you where the buffer memory is used. The log format has a time stamp,
|
||||
the name of the buffer usage which use-count changed, colon, and the new number of blocks that are
|
||||
in use for this particular key. For example:</p>
|
||||
<pre class="literal-block">
|
||||
23671 write cache: 18
|
||||
23671 receive buffer: 3
|
||||
24153 receive buffer: 2
|
||||
24153 write cache: 19
|
||||
24154 receive buffer: 3
|
||||
24198 receive buffer: 2
|
||||
24198 write cache: 20
|
||||
24202 receive buffer: 3
|
||||
24305 send buffer: 0
|
||||
24305 send buffer: 1
|
||||
24909 receive buffer: 2
|
||||
24909 write cache: 21
|
||||
24910 receive buffer: 3
|
||||
</pre>
|
||||
<p>The time stamp is in milliseconds since start.</p>
|
||||
<p>To generate a graph, use <tt class="docutils literal">parse_disk_buffer_log.py</tt>. It takes the log file as the first
|
||||
command line argument. It generates <tt class="docutils literal">disk_buffer.png</tt>.</p>
|
||||
<img alt="disk_buffer_sample.png" src="disk_buffer_sample.png" />
|
||||
<p>This is an example graph generated by the parse script.</p>
|
||||
</div>
|
||||
<div class="section" id="disk-access-log">
|
||||
<h3>disk_access.log</h3>
|
||||
<p><em>The disk access log is now binary</em></p>
|
||||
<p>The disc access log has three fields. The timestamp (milliseconds since start), operation
|
||||
and offset. The offset is the absolute offset within the torrent (not within a file). This
|
||||
log is only useful when you're downloading a single torrent, otherwise the offsets will not
|
||||
be unique.</p>
|
||||
<p>In order to easily plot this directly in gnuplot, without parsing it, there are two lines
|
||||
associated with each read or write operation. The first one is the offset where the operation
|
||||
started, and the second one is where the operation ended.</p>
|
||||
<p>Example:</p>
|
||||
<pre class="literal-block">
|
||||
15437 read 301187072
|
||||
15437 read_end 301203456
|
||||
16651 read 213385216
|
||||
16680 read_end 213647360
|
||||
25879 write 249036800
|
||||
25879 write_end 249298944
|
||||
26811 read 325582848
|
||||
26943 read_end 325844992
|
||||
36736 read 367001600
|
||||
36766 read_end 367263744
|
||||
</pre>
|
||||
<p>The disk access log does not have any good visualization tool yet. There is however a gnuplot
|
||||
file, <tt class="docutils literal">disk_access.gnuplot</tt> which assumes <tt class="docutils literal">disk_access.log</tt> is in the current directory.</p>
|
||||
<img alt="disk_access.png" src="disk_access.png" />
|
||||
<p>The density of the disk seeks tells you how hard the drive has to work.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="understanding-the-disk-threads">
|
||||
<h1>understanding the disk threads</h1>
|
||||
<p><em>This section is somewhat outdated, there are potentially more than one disk
|
||||
thread</em></p>
|
||||
<p>All disk operations are funneled through a separate thread, referred to as the
|
||||
disk thread. The main interface to the disk thread is a queue where disk jobs
|
||||
are posted, and the results of these jobs are then posted back on the main
|
||||
thread's io_service.</p>
|
||||
<p>A disk job is essentially one of:</p>
|
||||
<ol class="arabic">
|
||||
<li><dl class="first docutils">
|
||||
<dt>write this block to disk, i.e. a write job. For the most part this is just a</dt>
|
||||
<dd><p class="first last">matter of sticking the block in the disk cache, but if we've run out of
|
||||
cache space or completed a whole piece, we'll also flush blocks to disk.
|
||||
This is typically very fast, since the OS just sticks these buffers in its
|
||||
write cache which will be flushed at a later time, presumably when the drive
|
||||
head will pass the place on the platter where the blocks go.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li><dl class="first docutils">
|
||||
<dt>read this block from disk. The first thing that happens is we look in the</dt>
|
||||
<dd><p class="first last">cache to see if the block is already in RAM. If it is, we'll return
|
||||
immediately with this block. If it's a cache miss, we'll have to hit the
|
||||
disk. Here we decide to defer this job. We find the physical offset on the
|
||||
drive for this block and insert the job in an ordered queue, sorted by the
|
||||
physical location. At a later time, once we don't have any more non-read
|
||||
jobs left in the queue, we pick one read job out of the ordered queue and
|
||||
service it. The order we pick jobs out of the queue is according to an
|
||||
elevator cursor moving up and down along the ordered queue of read jobs. If
|
||||
we have enough space in the cache we'll read read_cache_line_size number of
|
||||
blocks and stick those in the cache. This defaults to 32 blocks. If the
|
||||
system supports asynchronous I/O (Windows, Linux, Mac OS X, BSD, Solars for
|
||||
instance), jobs will be issued immediately to the OS. This especially
|
||||
increases read throughput, since the OS has a much greater flexibility to
|
||||
reorder the read jobs.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
</ol>
|
||||
<p>Other disk job consist of operations that needs to be synchronized with the
|
||||
disk I/O, like renaming files, closing files, flushing the cache, updating the
|
||||
settings etc. These are relatively rare though.</p>
|
||||
</div>
|
||||
<div class="section" id="contributions">
|
||||
<h1>contributions</h1>
|
||||
<p>If you have added instrumentation for some part of libtorrent that is not
|
||||
covered here, or if you have improved any of the parser scrips, please consider
|
||||
contributing it back to the project.</p>
|
||||
<p>If you have run tests and found that some algorithm or default value in
|
||||
libtorrent is suboptimal, please contribute that knowledge back as well, to
|
||||
allow us to improve the library.</p>
|
||||
<p>If you have additional suggestions on how to tune libtorrent for any specific
|
||||
use case, please let us know and we'll update this document.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
219
docs/tuning.rst
|
@ -12,8 +12,8 @@ libtorrent manual
|
|||
tuning libtorrent
|
||||
=================
|
||||
|
||||
libtorrent expose most constants used in the bittorrent engine for
|
||||
customization through the ``session_settings``. This makes it possible to
|
||||
libtorrent expose most parameters used in the bittorrent engine for
|
||||
customization through the ``settings_pack``. This makes it possible to
|
||||
test and tweak the parameters for certain algorithms to make a client
|
||||
that fits a wide range of needs. From low memory embedded devices to
|
||||
servers seeding thousands of torrents. The default settings in libtorrent
|
||||
|
@ -27,7 +27,7 @@ reducing memory footprint
|
|||
=========================
|
||||
|
||||
These are things you can do to reduce the memory footprint of libtorrent. You get
|
||||
some of this by basing your default ``session_settings`` on the ``min_memory_usage()``
|
||||
some of this by basing your default ``settings_pack`` on the ``min_memory_usage()``
|
||||
setting preset function.
|
||||
|
||||
Keep in mind that lowering memory usage will affect performance, always profile
|
||||
|
@ -58,9 +58,9 @@ disable disk cache
|
|||
|
||||
The bulk of the memory libtorrent will use is used for the disk cache. To save
|
||||
the absolute most amount of memory, you can disable the cache by setting
|
||||
``session_settings::cache_size`` to 0. You might want to consider using the cache
|
||||
``settings_pack::cache_size`` to 0. You might want to consider using the cache
|
||||
but just disable caching read operations. You do this by settings
|
||||
``session_settings::use_read_cache`` to false. This is the main factor in how much
|
||||
``settings_pack::use_read_cache`` to false. This is the main factor in how much
|
||||
memory will be used by the client. Keep in mind that you will degrade performance
|
||||
by disabling the cache. You should benchmark the disk access in order to make an
|
||||
informed trade-off.
|
||||
|
@ -94,8 +94,8 @@ connection, and might be worth considering if you have a very large number of
|
|||
peer connections. This memory will not be visible in your process, this sets
|
||||
the amount of kernel memory is used for your sockets.
|
||||
|
||||
Change this by setting ``session_settings::recv_socket_buffer_size`` and
|
||||
``session_settings::send_socket_buffer_size``.
|
||||
Change this by setting ``settings_pack::recv_socket_buffer_size`` and
|
||||
``settings_pack::send_socket_buffer_size``.
|
||||
|
||||
peer list size
|
||||
--------------
|
||||
|
@ -109,7 +109,7 @@ large number of paused torrents (that are popular) it will be even more
|
|||
significant.
|
||||
|
||||
If you're short of memory, you should consider lowering the limit. 500 is probably
|
||||
enough. You can do this by setting ``session_settings::max_peerlist_size`` to
|
||||
enough. You can do this by setting ``settings_pack::max_peerlist_size`` to
|
||||
the max number of peers you want in a torrent's peer list. This limit applies per
|
||||
torrent. For 5 torrents, the total number of peers in peerlists will be 5 times
|
||||
the setting.
|
||||
|
@ -117,7 +117,7 @@ the setting.
|
|||
You should also lower the same limit but for paused torrents. It might even make sense
|
||||
to set that even lower, since you only need a few peers to start up while waiting
|
||||
for the tracker and DHT to give you fresh ones. The max peer list size for paused
|
||||
torrents is set by ``session_settings::max_paused_peerlist_size``.
|
||||
torrents is set by ``settings_pack::max_paused_peerlist_size``.
|
||||
|
||||
The drawback of lowering this number is that if you end up in a position where
|
||||
the tracker is down for an extended period of time, your only hope of finding live
|
||||
|
@ -132,7 +132,7 @@ The send buffer watermark controls when libtorrent will ask the disk I/O thread
|
|||
to read blocks from disk, and append it to a peer's send buffer.
|
||||
|
||||
When the send buffer has fewer than or equal number of bytes as
|
||||
``session_settings::send_buffer_watermark``, the peer will ask the disk I/O thread
|
||||
``settings_pack::send_buffer_watermark``, the peer will ask the disk I/O thread
|
||||
for more data to send. The trade-off here is between wasting memory by having too
|
||||
much data in the send buffer, and hurting send rate by starving out the socket,
|
||||
waiting for the disk read operation to complete.
|
||||
|
@ -156,7 +156,7 @@ the whole piece in one read call, then hashes it.
|
|||
The second option is to optimize for memory usage instead, where a single buffer
|
||||
is allocated, and the piece is read one block at a time, hashing it as each
|
||||
block is read from the file. For low memory environments, this latter approach
|
||||
is recommended. Change this by settings ``session_settings::optimize_hashing_for_speed``
|
||||
is recommended. Change this by settings ``settings_pack::optimize_hashing_for_speed``
|
||||
to false. This will significantly reduce peak memory usage, especially for
|
||||
torrents with very large pieces.
|
||||
|
||||
|
@ -200,7 +200,7 @@ processes that might be of higher importance to the end-user, you can introduce
|
|||
between the disc accesses. This is a direct tradeoff between how fast you can check a
|
||||
torrent and how soft you will hit the disk.
|
||||
|
||||
You control this by setting the ``session_settings::file_checks_delay_per_block`` to greater
|
||||
You control this by setting the ``settings_pack::file_checks_delay_per_block`` to greater
|
||||
than zero. This number is the number of milliseconds to sleep between each read of 16 kiB.
|
||||
|
||||
The sleeps are not necessarily in between each 16 kiB block (it might be read in larger chunks),
|
||||
|
@ -221,7 +221,7 @@ purpose of this is because of anti-virus software that hooks on file-open and fi
|
|||
scan the file. Anti-virus software that does that will significantly increase the cost of
|
||||
opening and closing files. However, for a high performance seed, the file open/close might
|
||||
be so frequent that it becomes a significant cost. It might therefore be a good idea to allow
|
||||
a large file descriptor cache. Adjust this though ``session_settings::file_pool_size``.
|
||||
a large file descriptor cache. Adjust this though ``settings_pack::file_pool_size``.
|
||||
|
||||
Don't forget to set a high rlimit for file descriptors in your process as well. This limit
|
||||
must be high enough to keep all connections and files open.
|
||||
|
@ -230,58 +230,33 @@ disk cache
|
|||
----------
|
||||
|
||||
You typically want to set the cache size to as high as possible. The
|
||||
``session_settings::cache_size`` is specified in 16 kiB blocks. Since you're seeding,
|
||||
the cache would be useless unless you also set ``session_settings::use_read_cache``
|
||||
``settings_pack::cache_size`` is specified in 16 kiB blocks. Since you're seeding,
|
||||
the cache would be useless unless you also set ``settings_pack::use_read_cache``
|
||||
to true.
|
||||
|
||||
In order to increase the possibility of read cache hits, set the
|
||||
``session_settings::cache_expiry`` to a large number. This won't degrade anything as
|
||||
``settings_pack::cache_expiry`` to a large number. This won't degrade anything as
|
||||
long as the client is only seeding, and not downloading any torrents.
|
||||
|
||||
In order to increase the disk cache hit rate, you can enable suggest messages based on
|
||||
what's in the read cache. To do this, set ``session_settings::suggest_mode`` to
|
||||
``session_settings::suggest_read_cache``. This will send suggest messages to peers
|
||||
for the most recently used pieces in the read cache. This is especially useful if you
|
||||
also enable explicit read cache, by settings ``session_settings::explicit_read_cache``
|
||||
to the number of pieces to keep in the cache. The explicit read cache will make the
|
||||
disk read cache stick, and not be evicted by cache misses. The explicit read cache
|
||||
will automatically pull in the rarest pieces in the read cache.
|
||||
|
||||
Assuming that you seed much more data than you can keep in the cache, to a large
|
||||
numbers of peers (so that the read cache wouldn't be useful anyway), this may be a
|
||||
good idea.
|
||||
|
||||
When peers first connect, libtorrent will send them a number of allow-fast messages,
|
||||
which lets the peers download certain pieces even when they are choked, since peers
|
||||
are choked by default, this often triggers immediate requests for those pieces. In the
|
||||
case of using explicit read cache and suggesting those pieces, allowing fast pieces
|
||||
should be disabled, to not systematically trigger requests for pieces that are not cached
|
||||
for all peers. You can turn off allow-fast by settings ``session_settings::allowed_fast_set_size``
|
||||
to 0.
|
||||
|
||||
As an alternative to the explicit cache and suggest messages, there's a *guided cache*
|
||||
mode. This means the size of the read cache line that's stored in the cache is determined
|
||||
based on the upload rate to the peer that triggered the read operation. The idea being
|
||||
that slow peers don't use up a disproportional amount of space in the cache. This
|
||||
is enabled through ``session_settings::guided_read_cache``.
|
||||
There's a *guided cache* mode. This means the size of the read cache line that's
|
||||
stored in the cache is determined based on the upload rate to the peer that
|
||||
triggered the read operation. The idea being that slow peers don't use up a
|
||||
disproportional amount of space in the cache. This is enabled through
|
||||
``settings_pack::guided_read_cache``.
|
||||
|
||||
In cases where the assumption is that the cache is only used as a read-ahead, and that no
|
||||
other peer will ever request the same block while it's still in the cache, the read
|
||||
cache can be set to be *volatile*. This means that every block that is requested out of
|
||||
the read cache is removed immediately. This saves a significant amount of cache space
|
||||
which can be used as read-ahead for other peers. This mode should **never** be combined
|
||||
with either ``explicit_read_cache`` or ``suggest_read_cache``, since those uses opposite
|
||||
strategies for the read cache. You don't want to on one hand attract peers to request
|
||||
the same pieces, and on the other hand assume that they won't request the same pieces
|
||||
and drop them when the first peer requests it. To enable volatile read cache, set
|
||||
``session_settings::volatile_read_cache`` to true.
|
||||
which can be used as read-ahead for other peers. To enable volatile read cache, set
|
||||
``settings_pack::volatile_read_cache`` to true.
|
||||
|
||||
SSD as level 2 cache
|
||||
--------------------
|
||||
|
||||
It is possible to introduce a second level of cache, below the RAM disk cache. This is done
|
||||
by setting ``session_settings::mmap_cache`` to a file path pointing to the SSD drive, and
|
||||
increasing the ``session_settings::cache_size`` to the number of 16 kiB blocks would fit
|
||||
by setting ``settings_pack::mmap_cache`` to a file path pointing to the SSD drive, and
|
||||
increasing the ``settings_pack::cache_size`` to the number of 16 kiB blocks would fit
|
||||
on the drive (or less).
|
||||
|
||||
This will allocate disk buffers (for reading and writing) from a memory region that has
|
||||
|
@ -305,7 +280,7 @@ throttle TCP to avoid it taking over all bandwidth. This balances the bandwidth
|
|||
between the two protocols. When running on a network where the bandwidth is in such an
|
||||
abundance that it's virtually infinite, this algorithm is no longer necessary, and might
|
||||
even be harmful to throughput. It is adviced to experiment with the
|
||||
``session_setting::mixed_mode_algorithm``, setting it to ``session_settings::prefer_tcp``.
|
||||
``session_setting::mixed_mode_algorithm``, setting it to ``settings_pack::prefer_tcp``.
|
||||
This setting entirely disables the balancing and unthrottles all connections. On a typical
|
||||
home connection, this would mean that none of the benefits of uTP would be preserved
|
||||
(the modem's send buffer would be full at all times) and uTP connections would for the most
|
||||
|
@ -324,7 +299,7 @@ enough to not draining the socket's send buffer before the disk operation comple
|
|||
The watermark is bound to a max value, to avoid buffer sizes growing out of control.
|
||||
The default max send buffer size might not be enough to sustain very high upload rates,
|
||||
and you might have to increase it. It's specified in bytes in
|
||||
``session_settings::send_buffer_watermark``.
|
||||
``settings_pack::send_buffer_watermark``.
|
||||
|
||||
peers
|
||||
-----
|
||||
|
@ -336,33 +311,33 @@ infinite, ``session::set_upload_rate_limit()``, passing 0 means infinite.
|
|||
When dealing with a large number of peers, it might be a good idea to have slightly
|
||||
stricter timeouts, to get rid of lingering connections as soon as possible.
|
||||
|
||||
There are a couple of relevant settings: ``session_settings::request_timeout``,
|
||||
``session_settings::peer_timeout`` and ``session_settings::inactivity_timeout``.
|
||||
There are a couple of relevant settings: ``settings_pack::request_timeout``,
|
||||
``settings_pack::peer_timeout`` and ``settings_pack::inactivity_timeout``.
|
||||
|
||||
For seeds that are critical for a delivery system, you most likely want to allow
|
||||
multiple connections from the same IP. That way two people from behind the same NAT
|
||||
can use the service simultaneously. This is controlled by
|
||||
``session_settings::allow_multiple_connections_per_ip``.
|
||||
``settings_pack::allow_multiple_connections_per_ip``.
|
||||
|
||||
In order to always unchoke peers, turn off automatic unchoke
|
||||
``session_settings::auto_upload_slots`` and set the number of upload slots to a large
|
||||
``settings_pack::auto_upload_slots`` and set the number of upload slots to a large
|
||||
number via ``session::set_max_uploads()``, or use -1 (which means infinite).
|
||||
|
||||
torrent limits
|
||||
--------------
|
||||
|
||||
To seed thousands of torrents, you need to increase the ``session_settings::active_limit``
|
||||
and ``session_settings::active_seeds``.
|
||||
To seed thousands of torrents, you need to increase the ``settings_pack::active_limit``
|
||||
and ``settings_pack::active_seeds``.
|
||||
|
||||
SHA-1 hashing
|
||||
-------------
|
||||
|
||||
When downloading at very high rates, it is possible to have the CPU be the bottleneck
|
||||
for passing every downloaded byte through SHA-1. In order to enable calculating SHA-1
|
||||
hashes in parallel, on multi-core systems, set ``session_settings::hashing_threads``
|
||||
to the number of threads libtorrent should start to do SHA-1 hashing. This defaults
|
||||
to 1, and only if that thread is close to saturating one core does it make sense to
|
||||
increase the number of threads.
|
||||
When downloading at very high rates, it is possible to have the CPU be the
|
||||
bottleneck for passing every downloaded byte through SHA-1. In order to enable
|
||||
calculating SHA-1 hashes in parallel, on multi-core systems, set
|
||||
``settings_pack::aio_threads`` to the number of threads libtorrent should
|
||||
perform I/O and do SHA-1 hashing in. Only if that thread is close to saturating
|
||||
one core does it make sense to increase the number of threads.
|
||||
|
||||
scalability
|
||||
===========
|
||||
|
@ -415,19 +390,7 @@ the disk I/O. The following table is an overview of these files and what they me
|
|||
+--------------------------+--------------------------------------------------------------+
|
||||
| filename | description |
|
||||
+==========================+==============================================================+
|
||||
| ``disk_io_thread.log`` | This is a log of which operation the disk I/O thread is |
|
||||
| | engaged in, with timestamps. This tells you what the thread |
|
||||
| | is spending its time doing. |
|
||||
| | |
|
||||
+--------------------------+--------------------------------------------------------------+
|
||||
| ``disk_buffers.log`` | This log keeps track of what the buffers allocated from the |
|
||||
| | disk buffer pool are used for. There are 5 categories. |
|
||||
| | receive buffer, send buffer, write cache, read cache and |
|
||||
| | temporary hash storage. This is key when optimizing memory |
|
||||
| | usage. |
|
||||
| | |
|
||||
+--------------------------+--------------------------------------------------------------+
|
||||
| ``disk_access.log`` | This is a low level log of read and write operations, with |
|
||||
| ``file_access.log`` | This is a low level log of read and write operations, with |
|
||||
| | timestamps and file offsets. The file offsets are byte |
|
||||
| | offsets in the torrent (not in any particular file, in the |
|
||||
| | case of a multi-file torrent). This can be used as an |
|
||||
|
@ -437,106 +400,12 @@ the disk I/O. The following table is an overview of these files and what they me
|
|||
| | |
|
||||
+--------------------------+--------------------------------------------------------------+
|
||||
|
||||
|
||||
disk_io_thread.log
|
||||
''''''''''''''''''
|
||||
|
||||
The structure of this log is simple. For each line, there are two columns, a timestamp and
|
||||
the operation that was started. There is a special operation called ``idle`` which means
|
||||
it looped back to the top and started waiting for new jobs. If there are more jobs to
|
||||
handle immediately, the ``idle`` state is still there, but the timestamp is the same as the
|
||||
next job that is handled.
|
||||
|
||||
Some operations have a 3:rd column with an optional parameter. ``read`` and ``write`` tells
|
||||
you the number of bytes that were requested to be read or written. ``flushing`` tells you
|
||||
the number of bytes that were flushed from the disk cache.
|
||||
|
||||
This is an example excerpt from a log::
|
||||
|
||||
3702 idle
|
||||
3706 check_fastresume
|
||||
3707 idle
|
||||
4708 save_resume_data
|
||||
4708 idle
|
||||
8230 read 16384
|
||||
8255 idle
|
||||
8431 read 16384
|
||||
|
||||
The script to parse this log and generate a graph is called ``parse_disk_log.py``. It takes
|
||||
the log file as the first command line argument, and produces a file: ``disk_io.png``.
|
||||
The time stamp is in milliseconds since start.
|
||||
|
||||
You can pass in a second, optional, argument to specify the window size it will average
|
||||
the time measurements over. The default is 5 seconds. For long test runs, it might be interesting
|
||||
to increase that number. It is specified as a number of seconds.
|
||||
|
||||
.. image:: disk_io.png
|
||||
|
||||
This is an example graph generated by the parse script.
|
||||
|
||||
disk_buffers.log
|
||||
''''''''''''''''
|
||||
|
||||
The disk buffer log tells you where the buffer memory is used. The log format has a time stamp,
|
||||
the name of the buffer usage which use-count changed, colon, and the new number of blocks that are
|
||||
in use for this particular key. For example::
|
||||
|
||||
23671 write cache: 18
|
||||
23671 receive buffer: 3
|
||||
24153 receive buffer: 2
|
||||
24153 write cache: 19
|
||||
24154 receive buffer: 3
|
||||
24198 receive buffer: 2
|
||||
24198 write cache: 20
|
||||
24202 receive buffer: 3
|
||||
24305 send buffer: 0
|
||||
24305 send buffer: 1
|
||||
24909 receive buffer: 2
|
||||
24909 write cache: 21
|
||||
24910 receive buffer: 3
|
||||
|
||||
The time stamp is in milliseconds since start.
|
||||
|
||||
To generate a graph, use ``parse_disk_buffer_log.py``. It takes the log file as the first
|
||||
command line argument. It generates ``disk_buffer.png``.
|
||||
|
||||
.. image:: disk_buffer_sample.png
|
||||
|
||||
This is an example graph generated by the parse script.
|
||||
|
||||
disk_access.log
|
||||
file_access.log
|
||||
'''''''''''''''
|
||||
|
||||
*The disk access log is now binary*
|
||||
|
||||
The disc access log has three fields. The timestamp (milliseconds since start), operation
|
||||
and offset. The offset is the absolute offset within the torrent (not within a file). This
|
||||
log is only useful when you're downloading a single torrent, otherwise the offsets will not
|
||||
be unique.
|
||||
|
||||
In order to easily plot this directly in gnuplot, without parsing it, there are two lines
|
||||
associated with each read or write operation. The first one is the offset where the operation
|
||||
started, and the second one is where the operation ended.
|
||||
|
||||
Example::
|
||||
|
||||
15437 read 301187072
|
||||
15437 read_end 301203456
|
||||
16651 read 213385216
|
||||
16680 read_end 213647360
|
||||
25879 write 249036800
|
||||
25879 write_end 249298944
|
||||
26811 read 325582848
|
||||
26943 read_end 325844992
|
||||
36736 read 367001600
|
||||
36766 read_end 367263744
|
||||
|
||||
The disk access log does not have any good visualization tool yet. There is however a gnuplot
|
||||
file, ``disk_access.gnuplot`` which assumes ``disk_access.log`` is in the current directory.
|
||||
|
||||
.. image:: disk_access.png
|
||||
|
||||
The density of the disk seeks tells you how hard the drive has to work.
|
||||
The disk access log is a binary file that can be parsed and converted to human
|
||||
readable by the script ``tools/parse_access_log.py``. This tool produces a
|
||||
graphical representation of the disk access and requires ``gnuplot``.
|
||||
|
||||
understanding the disk threads
|
||||
==============================
|
||||
|
|
|
@ -1,605 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>Bittorrent udp-tracker protocol extension</title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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="bittorrent-udp-tracker-protocol-extension">
|
||||
<div id="container">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<div id="main">
|
||||
<h1 class="title">Bittorrent udp-tracker protocol extension</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@libtorrent.org">arvid@libtorrent.org</a></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="#introduction" id="id2">introduction</a></li>
|
||||
<li><a class="reference internal" href="#connecting" id="id3">connecting</a></li>
|
||||
<li><a class="reference internal" href="#announcing" id="id4">announcing</a></li>
|
||||
<li><a class="reference internal" href="#scraping" id="id5">scraping</a></li>
|
||||
<li><a class="reference internal" href="#errors" id="id6">errors</a></li>
|
||||
<li><a class="reference internal" href="#actions" id="id7">actions</a></li>
|
||||
<li><a class="reference internal" href="#extensions" id="id8">extensions</a><ul>
|
||||
<li><a class="reference internal" href="#authentication" id="id9">authentication</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#request-string" id="id10">request string</a></li>
|
||||
<li><a class="reference internal" href="#credits" id="id11">credits</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="introduction">
|
||||
<h1>introduction</h1>
|
||||
<p>A tracker with the protocol "udp://" in its URI
|
||||
is supposed to be contacted using this protocol.</p>
|
||||
<p>This protocol is supported by
|
||||
<a class="reference external" href="http://xbtt.sourceforge.net">xbt-tracker</a>.</p>
|
||||
<p>For additional information and descritptions of
|
||||
the terminology used in this document, see
|
||||
the <a class="reference external" href="http://wiki.theory.org/index.php/BitTorrentSpecification">protocol specification</a></p>
|
||||
<p>All values are sent in network byte order (big endian). The sizes
|
||||
are specified with ANSI-C standard types.</p>
|
||||
<p>If no response to a request is received within 15 seconds, resend
|
||||
the request. If no reply has been received after 60 seconds, stop
|
||||
retrying.</p>
|
||||
</div>
|
||||
<div class="section" id="connecting">
|
||||
<h1>connecting</h1>
|
||||
<p>Client sends packet:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="18%" />
|
||||
<col width="28%" />
|
||||
<col width="54%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>int64_t</td>
|
||||
<td>connection_id</td>
|
||||
<td>Must be initialized to 0x41727101980
|
||||
in network byte order. This will
|
||||
identify the protocol.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>action</td>
|
||||
<td>0 for a connection request</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>transaction_id</td>
|
||||
<td>Randomized by client.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Server replies with packet:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="18%" />
|
||||
<col width="28%" />
|
||||
<col width="54%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>int32_t</td>
|
||||
<td>action</td>
|
||||
<td>Describes the type of packet, in this
|
||||
case it should be 0, for connect.
|
||||
If 3 (for error) see <a class="reference internal" href="#errors">errors</a>.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>transaction_id</td>
|
||||
<td>Must match the transaction_id sent
|
||||
from the client.</td>
|
||||
</tr>
|
||||
<tr><td>int64_t</td>
|
||||
<td>connection_id</td>
|
||||
<td>A connection id, this is used when
|
||||
further information is exchanged with
|
||||
the tracker, to identify you.
|
||||
This connection id can be reused for
|
||||
multiple requests, but if it's cached
|
||||
for too long, it will not be valid
|
||||
anymore.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section" id="announcing">
|
||||
<h1>announcing</h1>
|
||||
<p>Client sends packet:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="18%" />
|
||||
<col width="28%" />
|
||||
<col width="54%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>int64_t</td>
|
||||
<td>connection_id</td>
|
||||
<td>The connection id acquired from
|
||||
establishing the connection.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>action</td>
|
||||
<td>Action. in this case, 1 for announce.
|
||||
See <a class="reference internal" href="#actions">actions</a>.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>transaction_id</td>
|
||||
<td>Randomized by client.</td>
|
||||
</tr>
|
||||
<tr><td>int8_t[20]</td>
|
||||
<td>info_hash</td>
|
||||
<td>The info-hash of the torrent you want
|
||||
announce yourself in.</td>
|
||||
</tr>
|
||||
<tr><td>int8_t[20]</td>
|
||||
<td>peer_id</td>
|
||||
<td>Your peer id.</td>
|
||||
</tr>
|
||||
<tr><td>int64_t</td>
|
||||
<td>downloaded</td>
|
||||
<td>The number of byte you've downloaded
|
||||
in this session.</td>
|
||||
</tr>
|
||||
<tr><td>int64_t</td>
|
||||
<td>left</td>
|
||||
<td>The number of bytes you have left to
|
||||
download until you're finished.</td>
|
||||
</tr>
|
||||
<tr><td>int64_t</td>
|
||||
<td>uploaded</td>
|
||||
<td>The number of bytes you have uploaded
|
||||
in this session.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>event</td>
|
||||
<td><p class="first">The event, one of</p>
|
||||
<blockquote class="last">
|
||||
<ul class="simple">
|
||||
<li>none = 0</li>
|
||||
<li>completed = 1</li>
|
||||
<li>started = 2</li>
|
||||
<li>stopped = 3</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td>uint32_t</td>
|
||||
<td>ip</td>
|
||||
<td>Your ip address. Set to 0 if you want
|
||||
the tracker to use the <tt class="docutils literal">sender</tt> of
|
||||
this udp packet.</td>
|
||||
</tr>
|
||||
<tr><td>uint32_t</td>
|
||||
<td>key</td>
|
||||
<td>A unique key that is randomized by the
|
||||
client.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>num_want</td>
|
||||
<td>The maximum number of peers you want
|
||||
in the reply. Use -1 for default.</td>
|
||||
</tr>
|
||||
<tr><td>uint16_t</td>
|
||||
<td>port</td>
|
||||
<td>The port you're listening on.</td>
|
||||
</tr>
|
||||
<tr><td>uint16_t</td>
|
||||
<td>extensions</td>
|
||||
<td>See <a class="reference internal" href="#extensions">extensions</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Server replies with packet:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="18%" />
|
||||
<col width="28%" />
|
||||
<col width="54%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>int32_t</td>
|
||||
<td>action</td>
|
||||
<td>The action this is a reply to. Should
|
||||
in this case be 1 for announce.
|
||||
If 3 (for error) see <a class="reference internal" href="#errors">errors</a>.
|
||||
See <a class="reference internal" href="#actions">actions</a>.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>transaction_id</td>
|
||||
<td>Must match the transaction_id sent
|
||||
in the announce request.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>interval</td>
|
||||
<td>the number of seconds you should wait
|
||||
until reannouncing yourself.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>leechers</td>
|
||||
<td>The number of peers in the swarm that
|
||||
has not finished downloading.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>seeders</td>
|
||||
<td>The number of peers in the swarm that
|
||||
has finished downloading and are
|
||||
seeding.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The rest of the server reply is a variable number of the following structure:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="18%" />
|
||||
<col width="28%" />
|
||||
<col width="54%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>int32_t</td>
|
||||
<td>ip</td>
|
||||
<td>The ip of a peer in the swarm.</td>
|
||||
</tr>
|
||||
<tr><td>uint16_t</td>
|
||||
<td>port</td>
|
||||
<td>The peer's listen port.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section" id="scraping">
|
||||
<h1>scraping</h1>
|
||||
<p>Client sends packet:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="18%" />
|
||||
<col width="28%" />
|
||||
<col width="54%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>int64_t</td>
|
||||
<td>connection_id</td>
|
||||
<td>The connection id retreived from the
|
||||
establishing of the connection.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>action</td>
|
||||
<td>The action, in this case, 2 for
|
||||
scrape. See <a class="reference internal" href="#actions">actions</a>.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>transaction_id</td>
|
||||
<td>Randomized by client.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The following structure is repeated for each info-hash to scrape, but limited by
|
||||
the MTU.</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="18%" />
|
||||
<col width="28%" />
|
||||
<col width="54%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>int8_t[20]</td>
|
||||
<td>info_hash</td>
|
||||
<td>The info hash that is to be scraped.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Server replies with packet:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="18%" />
|
||||
<col width="28%" />
|
||||
<col width="54%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>int32_t</td>
|
||||
<td>action</td>
|
||||
<td>The action, should in this case be
|
||||
2 for scrape.
|
||||
If 3 (for error) see <a class="reference internal" href="#errors">errors</a>.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>transaction_id</td>
|
||||
<td>Must match the sent transaction id.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The rest of the packet contains the following structures once for each info-hash
|
||||
you asked in the scrape request.</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="18%" />
|
||||
<col width="28%" />
|
||||
<col width="54%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>int32_t</td>
|
||||
<td>complete</td>
|
||||
<td>The current number of connected seeds.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>downloaded</td>
|
||||
<td>The number of times this torrent has
|
||||
been downloaded.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>incomplete</td>
|
||||
<td>The current number of connected
|
||||
leechers.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section" id="errors">
|
||||
<h1>errors</h1>
|
||||
<p>In case of a tracker error,</p>
|
||||
<p>server replies packet:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="18%" />
|
||||
<col width="28%" />
|
||||
<col width="54%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>int32_t</td>
|
||||
<td>action</td>
|
||||
<td>The action, in this case 3, for error.
|
||||
See <a class="reference internal" href="#actions">actions</a>.</td>
|
||||
</tr>
|
||||
<tr><td>int32_t</td>
|
||||
<td>transaction_id</td>
|
||||
<td>Must match the transaction_id sent
|
||||
from the client.</td>
|
||||
</tr>
|
||||
<tr><td>int8_t[]</td>
|
||||
<td>error_string</td>
|
||||
<td>The rest of the packet is a string
|
||||
describing the error.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section" id="actions">
|
||||
<h1>actions</h1>
|
||||
<p>The action fields has the following encoding:</p>
|
||||
<blockquote>
|
||||
<ul class="simple">
|
||||
<li>connect = 0</li>
|
||||
<li>announce = 1</li>
|
||||
<li>scrape = 2</li>
|
||||
<li>error = 3 (only in server replies)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
</div>
|
||||
<div class="section" id="extensions">
|
||||
<h1>extensions</h1>
|
||||
<p>The extensions field is a bitmask. The following
|
||||
bits are assigned:</p>
|
||||
<blockquote>
|
||||
<ul class="simple">
|
||||
<li>1 = <a class="reference internal" href="#authentication">authentication</a>.</li>
|
||||
<li>2 = <a class="reference internal" href="#request-string">request string</a>.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<p>If multiple bits are present in the extension field, the extension
|
||||
bodies are appended to the packet in the order of least significant
|
||||
bit first. For instance, if both bit 1 and 2 are set, the extension
|
||||
represented by bit 1 comes first, followed by the extension represented
|
||||
by bit 2.</p>
|
||||
<div class="section" id="authentication">
|
||||
<h2>authentication</h2>
|
||||
<p>The packet will have an authentication part
|
||||
appended to it. It has the following format:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="18%" />
|
||||
<col width="28%" />
|
||||
<col width="54%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>int8_t</td>
|
||||
<td>username_length</td>
|
||||
<td>The number of characters in the
|
||||
username.</td>
|
||||
</tr>
|
||||
<tr><td>int8_t[]</td>
|
||||
<td>username</td>
|
||||
<td>The username, the number of characters
|
||||
as specified in the previous field.</td>
|
||||
</tr>
|
||||
<tr><td>uint8_t[8]</td>
|
||||
<td>passwd_hash</td>
|
||||
<td>sha1(packet + sha1(password))
|
||||
The packet in this case means the
|
||||
entire packet except these 8 bytes
|
||||
that are the password hash. These are
|
||||
the 8 first bytes (most significant)
|
||||
from the 20 bytes hash calculated.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="request-string">
|
||||
<h1>request string</h1>
|
||||
<p>The request string extension is meant to allow torrent creators pass along
|
||||
cookies back to the tracker. This can be useful for authenticating that a
|
||||
torrent is allowed to be tracked by a tracker for instance. It could also
|
||||
be used to authenticate users by generating torrents with unique tokens
|
||||
in the tracker URL for each user. The extension body has the following format:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="18%" />
|
||||
<col width="28%" />
|
||||
<col width="54%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">size</th>
|
||||
<th class="head">name</th>
|
||||
<th class="head">description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>int8_t</td>
|
||||
<td>request length</td>
|
||||
<td>The number of bytes in the request
|
||||
string.</td>
|
||||
</tr>
|
||||
<tr><td>int8_t[]</td>
|
||||
<td>request string</td>
|
||||
<td>The string that comes after the host-
|
||||
name and port in the udp tracker URL.
|
||||
Typically this starts with "/announce"
|
||||
The bittorrent client is not expected
|
||||
to append query string arguments for
|
||||
stats reporting, like "uploaded" and
|
||||
"downloaded" since this is already
|
||||
reported in the udp tracker protocol.
|
||||
However, the client is free to add
|
||||
arguments as extensions.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section" id="credits">
|
||||
<h1>credits</h1>
|
||||
<p>Protocol designed by Olaf van der Spek and extended by Arvid Norberg</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
370
docs/utp.html
|
@ -1,370 +0,0 @@
|
|||
<?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.12: http://docutils.sourceforge.net/" />
|
||||
<title>libtorrent manual</title>
|
||||
<meta name="author" content="Arvid Norberg, arvid@libtorrent.org" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
(function() {
|
||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
||||
s.type = 'text/javascript';
|
||||
s.async = true;
|
||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
||||
t.parentNode.insertBefore(s, t);
|
||||
})();
|
||||
/* ]]> */
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="rst.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">
|
||||
<table id="header">
|
||||
<tr><td id="orange"></td>
|
||||
<td id="logo">libtorrent</td></tr>
|
||||
</table>
|
||||
<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@libtorrent.org">arvid@libtorrent.org</a></td></tr>
|
||||
<tr><th class="docinfo-name">Version:</th>
|
||||
<td>1.1.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 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 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 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>
|
||||
<div id="gradient"></div>
|
||||
<div id="footer">
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="index.html">home</a></td>
|
||||
<td><a href="http://blog.libtorrent.org">blog</a></td>
|
||||
<td><a href="utp.html">uTP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/libtorrent/">download</a></td>
|
||||
<td><a href="reference.html">documentation</a></td>
|
||||
<td><a href="dht_store.html">DHT put extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://sourceforge.net/projects/libtorrent/files/py-libtorrent/">python bindings</a></td>
|
||||
<td><a href="features.html">features</a></td>
|
||||
<td><a href="dht_sec.html">DHT security extension</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://dir.gmane.org/gmane.network.bit-torrent.libtorrent">mailing list archive</a></td>
|
||||
<td><a href="contributing.html">contributing</a></td>
|
||||
<td><a href="streaming.html">streaming</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://code.google.com/p/libtorrent/issues/entry">report a bug</a></td>
|
||||
<td><a href="building.html">building</a></td>
|
||||
<td><a href="bittorrent.pdf">bittorrent slides</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="filler"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -264,7 +264,7 @@ int main(int argc, char* argv[])
|
|||
case 'p':
|
||||
++i;
|
||||
pad_file_limit = atoi(argv[i]);
|
||||
flags |= create_torrent::optimize;
|
||||
flags |= create_torrent::optimize_alignment;
|
||||
break;
|
||||
case 's':
|
||||
++i;
|
||||
|
|
|
@ -169,7 +169,7 @@ namespace libtorrent
|
|||
// priorities for torrents in share mode, it will make it not work.
|
||||
//
|
||||
// The share mode has one setting, the share ratio target, see
|
||||
// ``session_settings::share_mode_target`` for more info.
|
||||
// ``settings_pack::share_mode_target`` for more info.
|
||||
flag_share_mode = 0x008,
|
||||
|
||||
// determines if the IP filter should apply to this torrent or not. By
|
||||
|
|
|
@ -54,7 +54,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
// alerts (warnings, messages and errors from libtorrent). If no alerts have
|
||||
// been posted by libtorrent pop_alerts() will return an empty list.
|
||||
//
|
||||
// By default, only errors are reported. session_settings::alert_mask can be
|
||||
// By default, only errors are reported. settings_pack::alert_mask can be
|
||||
// used to specify which kinds of events should be reported. The alert mask is
|
||||
// comprised by bits from the category_t enum.
|
||||
//
|
||||
|
|
|
@ -937,6 +937,7 @@ namespace libtorrent
|
|||
// torrents.
|
||||
int m_auto_scrape_time_scaler;
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
// the index of the torrent that we'll
|
||||
// refresh the next time
|
||||
int m_next_explicit_cache_torrent;
|
||||
|
@ -945,6 +946,7 @@ namespace libtorrent
|
|||
// the next time the read cache is rotated, if we're
|
||||
// using an explicit read read cache.
|
||||
int m_cache_rotation_timer;
|
||||
#endif
|
||||
|
||||
// the index of the torrent that we'll
|
||||
// refresh the next time
|
||||
|
|
|
@ -114,7 +114,7 @@ namespace libtorrent
|
|||
// files, to keep the impact down for clients that don't support
|
||||
// them.
|
||||
optimize_alignment = 1,
|
||||
#ifndef TORRENT_NO_DEPRECATED
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
// same as optimize_alignment, for backwards compatibility
|
||||
optimize = 1,
|
||||
#endif
|
||||
|
@ -158,8 +158,8 @@ namespace libtorrent
|
|||
// If a ``pad_size_limit`` is specified (other than -1), any file larger than
|
||||
// the specified number of bytes will be preceeded by a pad file to align it
|
||||
// with the start of a piece. The pad_file_limit is ignored unless the
|
||||
// ``optimize`` flag is passed. Typically it doesn't make sense to set this
|
||||
// any lower than 4kiB.
|
||||
// ``optimize_alignment`` flag is passed. Typically it doesn't make sense
|
||||
// to set this any lower than 4kiB.
|
||||
//
|
||||
// The overload that takes a ``torrent_info`` object will make a verbatim
|
||||
// copy of its info dictionary (to preserve the info-hash). The copy of
|
||||
|
@ -175,7 +175,8 @@ namespace libtorrent
|
|||
// eligible files are aligned to. The default is -1, which means the
|
||||
// piece size of the torrent.
|
||||
create_torrent(file_storage& fs, int piece_size = 0
|
||||
, int pad_file_limit = -1, int flags = optimize, int alignment = -1);
|
||||
, int pad_file_limit = -1, int flags = optimize_alignment
|
||||
, int alignment = -1);
|
||||
create_torrent(torrent_info const& ti);
|
||||
|
||||
// internal
|
||||
|
@ -302,7 +303,7 @@ namespace libtorrent
|
|||
private:
|
||||
|
||||
file_storage& m_files;
|
||||
// if m_info_dict is initialized, it is
|
||||
// if m_info_dict is initialized, it is
|
||||
// used instead of m_files to generate
|
||||
// the info dictionary
|
||||
entry m_info_dict;
|
||||
|
|
|
@ -71,6 +71,8 @@ namespace libtorrent
|
|||
, std::vector<std::string>& links
|
||||
, boost::function<void(disk_io_job const*)> const& handler) = 0;
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
virtual void async_cache_piece(piece_manager* storage, int piece
|
||||
, boost::function<void(disk_io_job const*)> const& handler) = 0;
|
||||
virtual void async_finalize_file(piece_manager*, int file
|
||||
, boost::function<void(disk_io_job const*)> const& handler
|
||||
= boost::function<void(disk_io_job const*)>()) = 0;
|
||||
|
@ -78,8 +80,6 @@ namespace libtorrent
|
|||
virtual void async_flush_piece(piece_manager* storage, int piece
|
||||
, boost::function<void(disk_io_job const*)> const& handler
|
||||
= boost::function<void(disk_io_job const*)>()) = 0;
|
||||
virtual void async_cache_piece(piece_manager* storage, int piece
|
||||
, boost::function<void(disk_io_job const*)> const& handler) = 0;
|
||||
virtual void async_stop_torrent(piece_manager* storage
|
||||
, boost::function<void(disk_io_job const*)> const& handler)= 0;
|
||||
virtual void async_rename_file(piece_manager* storage, int index, std::string const& name
|
||||
|
|
|
@ -92,8 +92,8 @@ namespace libtorrent
|
|||
, check_fastresume
|
||||
, rename_file
|
||||
, stop_torrent
|
||||
, cache_piece
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
, cache_piece
|
||||
, finalize_file
|
||||
#endif
|
||||
, flush_piece
|
||||
|
|
|
@ -321,9 +321,9 @@ namespace libtorrent
|
|||
, boost::function<void(disk_io_job const*)> const& handler) TORRENT_OVERRIDE;
|
||||
void async_stop_torrent(piece_manager* storage
|
||||
, boost::function<void(disk_io_job const*)> const& handler) TORRENT_OVERRIDE;
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
void async_cache_piece(piece_manager* storage, int piece
|
||||
, boost::function<void(disk_io_job const*)> const& handler) TORRENT_OVERRIDE;
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
void async_finalize_file(piece_manager* storage, int file
|
||||
, boost::function<void(disk_io_job const*)> const& handler
|
||||
= boost::function<void(disk_io_job const*)>()) TORRENT_OVERRIDE;
|
||||
|
@ -414,8 +414,8 @@ namespace libtorrent
|
|||
int do_rename_file(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
int do_stop_torrent(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
int do_read_and_hash(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
int do_cache_piece(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
int do_cache_piece(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
int do_finalize_file(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
#endif
|
||||
int do_flush_piece(disk_io_job* j, jobqueue_t& completed_jobs);
|
||||
|
|
|
@ -865,7 +865,7 @@ namespace libtorrent
|
|||
|
||||
// this is the limit on the number of outstanding requests
|
||||
// we have to this peer. This is initialized to the settings
|
||||
// in the session_settings structure. But it may be lowered
|
||||
// in the settings_pack. But it may be lowered
|
||||
// if the peer is known to require a smaller limit (like BitComet).
|
||||
// or if the extended handshake sets a limit.
|
||||
// web seeds also has a limit on the queue size.
|
||||
|
|
|
@ -233,7 +233,7 @@ namespace libtorrent
|
|||
|
||||
// the number of seconds until the current front piece request will time
|
||||
// out. This timeout can be adjusted through
|
||||
// ``session_settings::request_timeout``.
|
||||
// ``settings_pack::request_timeout``.
|
||||
// -1 means that there is not outstanding request.
|
||||
int request_timeout;
|
||||
|
||||
|
@ -317,7 +317,7 @@ namespace libtorrent
|
|||
|
||||
// the number of bytes this peer has pending in the disk-io thread.
|
||||
// Downloaded and waiting to be written to disk. This is what is capped
|
||||
// by ``session_settings::max_queued_disk_bytes``.
|
||||
// by ``settings_pack::max_queued_disk_bytes``.
|
||||
int pending_disk_bytes;
|
||||
|
||||
// number of outstanding bytes to read
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace libtorrent
|
|||
// saved when calling save_state().
|
||||
enum save_state_flags_t
|
||||
{
|
||||
// saves settings (i.e. the session_settings)
|
||||
// saves settings (i.e. the settings_pack)
|
||||
save_settings = 0x001,
|
||||
|
||||
// saves dht_settings
|
||||
|
@ -844,7 +844,7 @@ namespace libtorrent
|
|||
// aren't working or fail, will automatically be disabled and packets
|
||||
// will flow without using any proxy. If you want to enforce using a
|
||||
// proxy, even when the proxy doesn't work, enable anonymous_mode in
|
||||
// session_settings.
|
||||
// settings_pack.
|
||||
TORRENT_DEPRECATED
|
||||
void set_proxy(proxy_settings const& s);
|
||||
TORRENT_DEPRECATED
|
||||
|
@ -957,7 +957,7 @@ namespace libtorrent
|
|||
// The alert queue in the session will not grow indefinitely. Make sure
|
||||
// to pop periodically to not miss notifications. To control the max
|
||||
// number of alerts that's queued by the session, see
|
||||
// ``session_settings::alert_queue_size``.
|
||||
// ``settings_pack::alert_queue_size``.
|
||||
//
|
||||
// Some alerts are considered so important that they are posted even when
|
||||
// the alert queue is full. Some alerts are considered mandatory and cannot
|
||||
|
|
|
@ -451,6 +451,7 @@ namespace libtorrent
|
|||
// once we want to calculate the piece hash
|
||||
bool dont_flush_write_cache;
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
// defaults to 0. If set to something greater than 0, the disk read cache
|
||||
// will not be evicted by cache misses and will explicitly be controlled
|
||||
// based on the rarity of pieces. Rare pieces are more likely to be
|
||||
|
@ -468,6 +469,7 @@ namespace libtorrent
|
|||
// the cache, so that subsequent refreshes only swaps in pieces that are
|
||||
// rarer than whatever is in the cache at the time.
|
||||
int explicit_cache_interval;
|
||||
#endif
|
||||
|
||||
// the buffer modes to use for reading and writing. Set
|
||||
// session_settings::disk_io_read_mode and disk_io_write_mode to one of
|
||||
|
|
|
@ -136,7 +136,7 @@ namespace libtorrent
|
|||
//
|
||||
// Since this setting sets a hard upper limit on cache usage, it
|
||||
// cannot be combined with
|
||||
// ``session_settings::contiguous_recv_buffer``, since that feature
|
||||
// ``settings_pack::contiguous_recv_buffer``, since that feature
|
||||
// treats the ``cache_size`` setting as a soft (but still pretty hard)
|
||||
// limit. The result of combining the two is peers being disconnected
|
||||
// after failing to allocate more disk buffers.
|
||||
|
@ -273,7 +273,7 @@ namespace libtorrent
|
|||
// reading blocks back from the disk multiple times for popular
|
||||
// pieces.
|
||||
use_read_cache,
|
||||
#ifndef TORRENT_NO_DEPRECATED
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
use_write_cache,
|
||||
#else
|
||||
deprecated11,
|
||||
|
@ -284,6 +284,7 @@ namespace libtorrent
|
|||
// hash
|
||||
dont_flush_write_cache,
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
// ``explicit_read_cache`` defaults to 0. If set to something greater
|
||||
// than 0, the disk read cache will not be evicted by cache misses and
|
||||
// will explicitly be controlled based on the rarity of pieces. Rare
|
||||
|
@ -293,6 +294,9 @@ namespace libtorrent
|
|||
// actual read cache can't fit as many, it will essentially be
|
||||
// clamped.
|
||||
explicit_read_cache,
|
||||
#else
|
||||
deprecated12,
|
||||
#endif
|
||||
|
||||
// allocate separate, contiguous, buffers for read and write calls.
|
||||
// Only used where writev/readv cannot be used will use more RAM but
|
||||
|
@ -938,6 +942,7 @@ namespace libtorrent
|
|||
cache_buffer_chunk_size,
|
||||
cache_expiry,
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
// ``explicit_cache_interval`` is the number of seconds in between
|
||||
// each refresh of a part of the explicit read cache. Torrents take
|
||||
// turns in refreshing and this is the time in between each torrent
|
||||
|
@ -947,6 +952,9 @@ namespace libtorrent
|
|||
// subsequent refreshes only swaps in pieces that are rarer than
|
||||
// whatever is in the cache at the time.
|
||||
explicit_cache_interval,
|
||||
#else
|
||||
deprecated13,
|
||||
#endif
|
||||
|
||||
// determines how files are opened when they're in read only mode
|
||||
// versus read and write mode. The options are:
|
||||
|
@ -1397,6 +1405,9 @@ namespace libtorrent
|
|||
// received by the metadata extension, i.e. magnet links.
|
||||
max_metadata_size,
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
// DEPRECTED: use aio_threads instead
|
||||
|
||||
// ``hashing_threads`` is the number of threads to use for piece hash
|
||||
// verification. It defaults to 1. For very high download rates, on
|
||||
// machines with multiple cores, this could be incremented. Setting it
|
||||
|
@ -1404,6 +1415,9 @@ namespace libtorrent
|
|||
// any benefit of setting it to the number of cores. If it's set to 0,
|
||||
// hashing is done in the disk thread.
|
||||
hashing_threads,
|
||||
#else
|
||||
deprecated14,
|
||||
#endif
|
||||
|
||||
// the number of blocks to keep outstanding at any given time when
|
||||
// checking torrents. Higher numbers give faster re-checks but uses
|
||||
|
|
|
@ -669,14 +669,16 @@ namespace libtorrent
|
|||
void get_peer_info(std::vector<peer_info>* v);
|
||||
void get_download_queue(std::vector<partial_piece_info>* queue) const;
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
void refresh_explicit_cache(int cache_size);
|
||||
#endif
|
||||
|
||||
void add_suggest_piece(int piece);
|
||||
void update_suggest_piece(int index, int change);
|
||||
void update_auto_sequential();
|
||||
|
||||
void refresh_suggest_pieces();
|
||||
void do_refresh_suggest_pieces();
|
||||
void on_cache_info(disk_io_job const* j);
|
||||
|
||||
// --------------------------------------------
|
||||
// TRACKER MANAGEMENT
|
||||
|
|
|
@ -598,7 +598,7 @@ namespace libtorrent
|
|||
// Explicitly sets the upload mode of the torrent. In upload mode, the
|
||||
// torrent will not request any pieces. If the torrent is auto managed,
|
||||
// it will automatically be taken out of upload mode periodically (see
|
||||
// ``session_settings::optimistic_disk_retry``). Torrents are
|
||||
// ``settings_pack::optimistic_disk_retry``). Torrents are
|
||||
// automatically put in upload mode whenever they encounter a disk write
|
||||
// error.
|
||||
//
|
||||
|
@ -1101,7 +1101,7 @@ namespace libtorrent
|
|||
// ``set_download_limit`` works the same way but for download bandwidth
|
||||
// instead of upload bandwidth. Note that setting a higher limit on a
|
||||
// torrent then the global limit
|
||||
// (``session_settings::upload_rate_limit``) will not override the global
|
||||
// (``settings_pack::upload_rate_limit``) will not override the global
|
||||
// rate limit. The torrent can never upload more than the global rate
|
||||
// limit.
|
||||
//
|
||||
|
@ -1170,7 +1170,7 @@ namespace libtorrent
|
|||
// at the same time on this torrent. If you set this to -1, there will be
|
||||
// no limit. This defaults to infinite. The primary setting controlling
|
||||
// this is the global unchoke slots limit, set by unchoke_slots_limit in
|
||||
// session_settings.
|
||||
// settings_pack.
|
||||
//
|
||||
// ``max_uploads()`` returns the current settings.
|
||||
void set_max_uploads(int max_uploads) const;
|
||||
|
@ -1182,7 +1182,7 @@ namespace libtorrent
|
|||
// must be at least 2. The default is unlimited number of connections. If
|
||||
// -1 is given to the function, it means unlimited. There is also a
|
||||
// global limit of the number of connections, set by
|
||||
// ``connections_limit`` in session_settings.
|
||||
// ``connections_limit`` in settings_pack.
|
||||
//
|
||||
// ``max_connections()`` returns the current settings.
|
||||
void set_max_connections(int max_connections) const;
|
||||
|
|
|
@ -363,8 +363,17 @@ TORRENT_TEST(ipv6_support)
|
|||
TEST_EQUAL(v6_announces, 2);
|
||||
}
|
||||
|
||||
template <typename Announce, typename Test1, typename Test2>
|
||||
void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "/announce")
|
||||
// this runs a simulation of a torrent with tracker(s), making sure the request
|
||||
// received by the tracker matches the expectation.
|
||||
// The Setup function is run first, giving the test an opportunity to add
|
||||
// trackers to the torrent. It's expected to return the number of seconds to
|
||||
// wait until test2 is called.
|
||||
// The Announce function is called on http requests. Test1 is run on the session
|
||||
// 5 seconds after startup. The tracker is running at 10.0.0.2 (or tracker.com)
|
||||
// port 8080.
|
||||
template <typename Setup, typename Announce, typename Test1, typename Test2>
|
||||
void tracker_test(Setup setup, Announce a, Test1 test1, Test2 test2
|
||||
, char const* url_path = "/announce")
|
||||
{
|
||||
using sim::asio::ip::address_v4;
|
||||
sim_config network_cfg;
|
||||
|
@ -390,7 +399,7 @@ void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "
|
|||
p.name = "test-torrent";
|
||||
p.save_path = ".";
|
||||
p.info_hash.assign("abababababababababab");
|
||||
p.trackers.push_back("http://tracker.com:8080/announce");
|
||||
int const delay = setup(p);
|
||||
ses->async_add_torrent(p);
|
||||
|
||||
// run the test 5 seconds in
|
||||
|
@ -405,7 +414,7 @@ void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "
|
|||
});
|
||||
|
||||
asio::high_resolution_timer t2(ios);
|
||||
t2.expires_from_now(chrono::seconds(9));
|
||||
t2.expires_from_now(chrono::seconds(5 + delay));
|
||||
t2.async_wait([&ses,&test2](boost::system::error_code const& ec)
|
||||
{
|
||||
std::vector<lt::torrent_handle> torrents = ses->get_torrents();
|
||||
|
@ -416,7 +425,7 @@ void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "
|
|||
|
||||
// then shut down 10 seconds in
|
||||
asio::high_resolution_timer t3(ios);
|
||||
t3.expires_from_now(chrono::seconds(10));
|
||||
t3.expires_from_now(chrono::seconds(10 + delay));
|
||||
t3.async_wait([&ses,&zombie](boost::system::error_code const& ec)
|
||||
{
|
||||
zombie = ses->abort();
|
||||
|
@ -427,6 +436,16 @@ void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "
|
|||
sim.run();
|
||||
}
|
||||
|
||||
template <typename Announce, typename Test1, typename Test2>
|
||||
void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "/announce")
|
||||
{
|
||||
tracker_test([](lt::add_torrent_params& p) {
|
||||
p.trackers.push_back("http://tracker.com:8080/announce");
|
||||
return 5;
|
||||
},
|
||||
a, test1, test2, url_path);
|
||||
}
|
||||
|
||||
template <typename Announce, typename Test>
|
||||
void announce_entry_test(Announce a, Test t, char const* url_path = "/announce")
|
||||
{
|
||||
|
@ -609,6 +628,74 @@ TORRENT_TEST(test_invalid_bencoding)
|
|||
});
|
||||
}
|
||||
|
||||
TORRENT_TEST(try_next)
|
||||
{
|
||||
// test that we move on to try the next tier if the first one fails
|
||||
|
||||
bool got_announce = false;
|
||||
tracker_test(
|
||||
[](lt::add_torrent_params& p)
|
||||
{
|
||||
// TODO: 3 use tracker_tiers here to put the trackers in different tiers
|
||||
p.trackers.push_back("udp://failing-tracker.com/announce");
|
||||
p.trackers.push_back("http://failing-tracker.com/announce");
|
||||
|
||||
// this is the working tracker
|
||||
p.trackers.push_back("http://tracker.com:8080/announce");
|
||||
return 60;
|
||||
},
|
||||
[&](std::string method, std::string req
|
||||
, std::map<std::string, std::string>& headers)
|
||||
{
|
||||
got_announce = true;
|
||||
TEST_EQUAL(method, "GET");
|
||||
|
||||
char response[500];
|
||||
// respond with an empty peer list
|
||||
int size = snprintf(response, sizeof(response), "d5:peers0:e");
|
||||
return sim::send_response(200, "OK", size) + response;
|
||||
}
|
||||
, [](torrent_handle h) {}
|
||||
, [](torrent_handle h)
|
||||
{
|
||||
torrent_status st = h.status();
|
||||
TEST_EQUAL(st.current_tracker, "http://tracker.com:8080/announce");
|
||||
|
||||
std::vector<announce_entry> tr = h.trackers();
|
||||
|
||||
TEST_EQUAL(tr.size(), 3);
|
||||
|
||||
for (int i = 0; i < tr.size(); ++i)
|
||||
{
|
||||
fprintf(stderr, "tracker \"%s\"\n", tr[i].url.c_str());
|
||||
if (tr[i].url == "http://tracker.com:8080/announce")
|
||||
{
|
||||
TEST_EQUAL(tr[i].fails, 0);
|
||||
TEST_EQUAL(tr[i].verified, true);
|
||||
}
|
||||
else if (tr[i].url == "http://failing-tracker.com/announce")
|
||||
{
|
||||
TEST_CHECK(tr[i].fails >= 1);
|
||||
TEST_EQUAL(tr[i].verified, false);
|
||||
TEST_EQUAL(tr[i].last_error
|
||||
, error_code(boost::asio::error::host_not_found));
|
||||
}
|
||||
else if (tr[i].url == "udp://failing-tracker.com/announce")
|
||||
{
|
||||
TEST_CHECK(tr[i].fails >= 1);
|
||||
TEST_EQUAL(tr[i].verified, false);
|
||||
TEST_EQUAL(tr[i].last_error
|
||||
, error_code(boost::asio::error::host_not_found));
|
||||
}
|
||||
else
|
||||
{
|
||||
TEST_ERROR(("unexpected tracker URL: " + tr[i].url).c_str());
|
||||
}
|
||||
}
|
||||
});
|
||||
TEST_EQUAL(got_announce, true);
|
||||
}
|
||||
|
||||
// TODO: test external IP
|
||||
// TODO: test with different queuing settings
|
||||
// TODO: test when a torrent transitions from downloading to finished and
|
||||
|
|
|
@ -202,8 +202,8 @@ const char* const job_action_name[] =
|
|||
"check_fastresume",
|
||||
"rename_file",
|
||||
"stop_torrent",
|
||||
"cache_piece",
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
"cache_piece",
|
||||
"finalize_file",
|
||||
#endif
|
||||
"flush_piece",
|
||||
|
@ -217,6 +217,12 @@ const char* const job_action_name[] =
|
|||
"resolve_links"
|
||||
};
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
// make sure the job names array covers all the job IDs
|
||||
static_assert(sizeof(job_action_name)/sizeof(job_action_name[0])
|
||||
== disk_io_job::num_job_ids, "disk-job-action and action-name-array mismatch");
|
||||
#endif
|
||||
|
||||
#if TORRENT_USE_ASSERTS
|
||||
|
||||
char const* const piece_log_t::job_names[7] =
|
||||
|
@ -358,9 +364,6 @@ block_cache::block_cache(int block_size, io_service& ios
|
|||
, m_send_buffer_blocks(0)
|
||||
, m_pinned_blocks(0)
|
||||
{
|
||||
// make sure the job names array covers all the job IDs
|
||||
TORRENT_ASSERT(sizeof(job_action_name)/sizeof(job_action_name[0])
|
||||
== disk_io_job::num_job_ids);
|
||||
}
|
||||
|
||||
// returns:
|
||||
|
|
|
@ -282,7 +282,7 @@ namespace libtorrent
|
|||
|
||||
settings_pack sett;
|
||||
sett.set_int(settings_pack::cache_size, 0);
|
||||
sett.set_int(settings_pack::hashing_threads, 2);
|
||||
sett.set_int(settings_pack::aio_threads, 2);
|
||||
|
||||
// TODO: this should probably be optional
|
||||
alert_manager dummy2(0, 0);
|
||||
|
|
|
@ -1039,8 +1039,8 @@ namespace libtorrent
|
|||
&disk_io_thread::do_check_fastresume,
|
||||
&disk_io_thread::do_rename_file,
|
||||
&disk_io_thread::do_stop_torrent,
|
||||
&disk_io_thread::do_cache_piece,
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
&disk_io_thread::do_cache_piece,
|
||||
&disk_io_thread::do_finalize_file,
|
||||
#endif
|
||||
&disk_io_thread::do_flush_piece,
|
||||
|
@ -1933,6 +1933,7 @@ namespace libtorrent
|
|||
add_completed_jobs(completed_jobs);
|
||||
}
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
void disk_io_thread::async_cache_piece(piece_manager* storage, int piece
|
||||
, boost::function<void(disk_io_job const*)> const& handler)
|
||||
{
|
||||
|
@ -1950,7 +1951,6 @@ namespace libtorrent
|
|||
add_job(j);
|
||||
}
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
void disk_io_thread::async_finalize_file(piece_manager* storage, int file
|
||||
, boost::function<void(disk_io_job const*)> const& handler)
|
||||
{
|
||||
|
@ -1967,7 +1967,7 @@ namespace libtorrent
|
|||
|
||||
add_job(j);
|
||||
}
|
||||
#endif
|
||||
#endif // TORRENT_NO_DEPRECATE
|
||||
|
||||
void disk_io_thread::async_flush_piece(piece_manager* storage, int piece
|
||||
, boost::function<void(disk_io_job const*)> const& handler)
|
||||
|
@ -2584,6 +2584,7 @@ namespace libtorrent
|
|||
return j->error ? -1 : 0;
|
||||
}
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
int disk_io_thread::do_cache_piece(disk_io_job* j, jobqueue_t& /* completed_jobs */ )
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
@ -2685,13 +2686,12 @@ namespace libtorrent
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
int disk_io_thread::do_finalize_file(disk_io_job* j, jobqueue_t& /* completed_jobs */)
|
||||
{
|
||||
j->storage->get_storage_impl()->finalize_file(j->piece, j->error);
|
||||
return j->error ? -1 : 0;
|
||||
}
|
||||
#endif
|
||||
#endif // TORRENT_NO_DEPRECATE
|
||||
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -97,7 +97,6 @@ namespace libtorrent
|
|||
set.set_int(settings_pack::checking_mem_usage, 2);
|
||||
|
||||
// don't use any extra threads to do SHA-1 hashing
|
||||
set.set_int(settings_pack::hashing_threads, 0);
|
||||
set.set_int(settings_pack::network_threads, 0);
|
||||
set.set_int(settings_pack::aio_threads, 1);
|
||||
|
||||
|
@ -227,7 +226,6 @@ namespace libtorrent
|
|||
// download rate
|
||||
set.set_int(settings_pack::max_queued_disk_bytes, 7 * 1024 * 1024);
|
||||
|
||||
set.set_bool(settings_pack::explicit_read_cache, false);
|
||||
// prevent fast pieces to interfere with suggested pieces
|
||||
// since we unchoke everyone, we don't need fast pieces anyway
|
||||
set.set_int(settings_pack::allowed_fast_set_size, 0);
|
||||
|
@ -271,11 +269,6 @@ namespace libtorrent
|
|||
// connect to us if they want to
|
||||
set.set_int(settings_pack::max_failcount, 1);
|
||||
|
||||
// we're likely to have more than 4 cores on a high
|
||||
// performance machine. One core is needed for the
|
||||
// network thread
|
||||
set.set_int(settings_pack::hashing_threads, 4);
|
||||
|
||||
// the number of threads to use to call async_write_some
|
||||
// and read_some on peer sockets
|
||||
// this doesn't work. See comment in settings_pack.cpp
|
||||
|
|
|
@ -1152,7 +1152,7 @@ namespace libtorrent
|
|||
p.set_bool(settings_pack::enable_natpmp, false);
|
||||
apply_settings(p);
|
||||
}
|
||||
#endif // TORRENT_NO_DEPRECATED
|
||||
#endif // TORRENT_NO_DEPRECATE
|
||||
|
||||
int session_handle::add_port_mapping(session::protocol_type t, int external_port, int local_port)
|
||||
{
|
||||
|
|
|
@ -393,8 +393,10 @@ namespace aux {
|
|||
, m_optimistic_unchoke_time_scaler(0)
|
||||
, m_disconnect_time_scaler(90)
|
||||
, m_auto_scrape_time_scaler(180)
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
, m_next_explicit_cache_torrent(0)
|
||||
, m_cache_rotation_timer(0)
|
||||
#endif
|
||||
, m_next_suggest_torrent(0)
|
||||
, m_suggest_timer(0)
|
||||
, m_peak_up_rate(0)
|
||||
|
@ -2107,15 +2109,15 @@ namespace aux {
|
|||
for (std::list<listen_socket_t>::iterator i = m_listen_sockets.begin()
|
||||
, end(m_listen_sockets.end()); i != end; ++i)
|
||||
{
|
||||
listen_succeeded_alert::socket_type_t socket_type = i->ssl
|
||||
listen_succeeded_alert::socket_type_t const socket_type = i->ssl
|
||||
? listen_succeeded_alert::tcp_ssl
|
||||
: listen_succeeded_alert::tcp;
|
||||
|
||||
if (!m_alerts.should_post<listen_succeeded_alert>()) continue;
|
||||
|
||||
error_code err;
|
||||
tcp::endpoint bind_ep = i->sock->local_endpoint(err);
|
||||
if (err) continue;
|
||||
error_code error;
|
||||
tcp::endpoint bind_ep = i->sock->local_endpoint(error);
|
||||
if (error) continue;
|
||||
|
||||
m_alerts.emplace_alert<listen_succeeded_alert>(bind_ep, socket_type);
|
||||
}
|
||||
|
@ -3273,6 +3275,7 @@ namespace aux {
|
|||
++m_next_suggest_torrent;
|
||||
}
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
// --------------------------------------------------------------
|
||||
// refresh explicit disk read cache
|
||||
// --------------------------------------------------------------
|
||||
|
@ -3308,6 +3311,7 @@ namespace aux {
|
|||
least_recently_refreshed->second->refresh_explicit_cache(cache_size);
|
||||
++m_next_explicit_cache_torrent;
|
||||
}
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// connect new peers
|
||||
|
|
|
@ -156,7 +156,7 @@ namespace libtorrent
|
|||
SET(use_read_cache, true, 0),
|
||||
DEPRECATED_SET(use_write_cache, true, 0),
|
||||
SET(dont_flush_write_cache, false, 0),
|
||||
SET(explicit_read_cache, false, 0),
|
||||
DEPRECATED_SET(explicit_read_cache, false, 0),
|
||||
SET(coalesce_reads, false, 0),
|
||||
SET(coalesce_writes, false, 0),
|
||||
SET(auto_manage_prefer_seeds, false, 0),
|
||||
|
@ -255,7 +255,7 @@ namespace libtorrent
|
|||
SET(cache_size, 1024, 0),
|
||||
SET(cache_buffer_chunk_size, 0, &session_impl::update_cache_buffer_chunk_size),
|
||||
SET(cache_expiry, 300, 0),
|
||||
SET(explicit_cache_interval, 30, 0),
|
||||
DEPRECATED_SET(explicit_cache_interval, 30, 0),
|
||||
SET(disk_io_write_mode, settings_pack::enable_os_cache, 0),
|
||||
SET(disk_io_read_mode, settings_pack::enable_os_cache, 0),
|
||||
SET(outgoing_port, 0, 0),
|
||||
|
@ -320,13 +320,13 @@ namespace libtorrent
|
|||
SET(torrent_connect_boost, 10, 0),
|
||||
SET(alert_queue_size, 1000, &session_impl::update_alert_queue_size),
|
||||
SET(max_metadata_size, 3 * 1024 * 10240, 0),
|
||||
SET(hashing_threads, 1, 0),
|
||||
DEPRECATED_SET(hashing_threads, 1, 0),
|
||||
SET(checking_mem_usage, 256, 0),
|
||||
SET(predictive_piece_announce, 0, 0),
|
||||
SET(aio_threads, 4, &session_impl::update_disk_threads),
|
||||
SET(aio_max, 300, 0),
|
||||
SET(network_threads, 0, &session_impl::update_network_threads),
|
||||
DEPRECATED_SET(ssl_listen, 4433, &session_impl::update_ssl_listen),
|
||||
DEPRECATED_SET(ssl_listen, 0, &session_impl::update_ssl_listen),
|
||||
SET(tracker_backoff, 250, 0),
|
||||
SET_NOPREV(share_ratio_limit, 200, 0),
|
||||
SET_NOPREV(seed_time_ratio_limit, 700, 0),
|
||||
|
|
|
@ -10037,6 +10037,7 @@ namespace libtorrent
|
|||
update_want_peers();
|
||||
}
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
// TODO: 2 this should probably be removed
|
||||
void torrent::refresh_explicit_cache(int cache_size)
|
||||
{
|
||||
|
@ -10135,6 +10136,7 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif // TORRENT_NO_DEPRECATE
|
||||
|
||||
void torrent::sent_bytes(int bytes_payload, int bytes_protocol)
|
||||
{
|
||||
|
|
|
@ -694,22 +694,13 @@ void udp_socket::close()
|
|||
TORRENT_ASSERT(m_magic == 0x1337);
|
||||
|
||||
error_code ec;
|
||||
// if we close the socket here, we can't shut down
|
||||
// utp connections or NAT-PMP. We need to cancel the
|
||||
// outstanding operations
|
||||
m_ipv4_sock.cancel(ec);
|
||||
if (ec == error::operation_not_supported)
|
||||
m_ipv4_sock.close(ec);
|
||||
m_ipv4_sock.close(ec);
|
||||
TORRENT_ASSERT_VAL(!ec || ec == error::bad_descriptor, ec);
|
||||
#if TORRENT_USE_IPV6
|
||||
m_ipv6_sock.cancel(ec);
|
||||
if (ec == error::operation_not_supported)
|
||||
m_ipv6_sock.close(ec);
|
||||
m_ipv6_sock.close(ec);
|
||||
TORRENT_ASSERT_VAL(!ec || ec == error::bad_descriptor, ec);
|
||||
#endif
|
||||
m_socks5_sock.cancel(ec);
|
||||
if (ec == error::operation_not_supported)
|
||||
m_socks5_sock.close(ec);
|
||||
m_socks5_sock.close(ec);
|
||||
TORRENT_ASSERT_VAL(!ec || ec == error::bad_descriptor, ec);
|
||||
m_resolver.cancel();
|
||||
m_timer.cancel();
|
||||
|
|
|
@ -48,13 +48,12 @@ void test_swarm(int flags)
|
|||
using namespace libtorrent;
|
||||
namespace lt = libtorrent;
|
||||
|
||||
fprintf(stderr, "\n\n ==== TEST SWARM === %s%s%s%s%s%s ===\n\n\n"
|
||||
fprintf(stderr, "\n\n ==== TEST SWARM === %s%s%s%s%s ===\n\n\n"
|
||||
, (flags & super_seeding) ? "super-seeding ": ""
|
||||
, (flags & strict_super_seeding) ? "strict-super-seeding ": ""
|
||||
, (flags & seed_mode) ? "seed-mode ": ""
|
||||
, (flags & time_critical) ? "time-critical ": ""
|
||||
, (flags & suggest) ? "suggest ": ""
|
||||
, (flags & explicit_cache) ? "explicit-cache ": ""
|
||||
);
|
||||
|
||||
// in case the previous run was terminated
|
||||
|
@ -89,15 +88,6 @@ void test_swarm(int flags)
|
|||
if (flags & suggest)
|
||||
pack.set_int(settings_pack::suggest_mode, settings_pack::suggest_read_cache);
|
||||
|
||||
if (flags & explicit_cache)
|
||||
pack.set_bool(settings_pack::explicit_read_cache, true);
|
||||
|
||||
if (flags & explicit_cache)
|
||||
{
|
||||
pack.set_bool(settings_pack::explicit_read_cache, true);
|
||||
pack.set_int(settings_pack::explicit_cache_interval, 5);
|
||||
}
|
||||
|
||||
// this is to avoid everything finish from a single peer
|
||||
// immediately. To make the swarm actually connect all
|
||||
// three peers before finishing.
|
||||
|
|
|
@ -39,7 +39,6 @@ enum test_flags_t
|
|||
seed_mode = 4,
|
||||
time_critical = 8,
|
||||
suggest = 16,
|
||||
explicit_cache = 32
|
||||
};
|
||||
|
||||
void EXPORT test_swarm(int flags = 0);
|
||||
|
|
|
@ -103,7 +103,8 @@ void test_checking(int flags = read_only_files)
|
|||
, file_sizes, num_files);
|
||||
|
||||
add_files(fs, combine_path("tmp1_checking", "test_torrent_dir"));
|
||||
libtorrent::create_torrent t(fs, piece_size, 0x4000, libtorrent::create_torrent::optimize);
|
||||
libtorrent::create_torrent t(fs, piece_size, 0x4000
|
||||
, libtorrent::create_torrent::optimize_alignment);
|
||||
|
||||
// calculate the hash for all pieces
|
||||
set_piece_hashes(t, "tmp1_checking", ec);
|
||||
|
|
|
@ -410,7 +410,7 @@ void test_remap_files_prio(storage_mode_t storage_mode = storage_mode_sparse)
|
|||
|
||||
add_files(fs1, combine_path("tmp1_remap3", "test_torrent_dir"));
|
||||
libtorrent::create_torrent ct(fs1, piece_size, 0x4000
|
||||
, libtorrent::create_torrent::optimize);
|
||||
, libtorrent::create_torrent::optimize_alignment);
|
||||
|
||||
// calculate the hash for all pieces
|
||||
set_piece_hashes(ct, "tmp1_remap3", ec);
|
||||
|
|
|
@ -387,121 +387,6 @@ TORRENT_TEST(udp_tracker)
|
|||
TEST_EQUAL(num_udp_announces(), prev_udp_announces + 2);
|
||||
}
|
||||
|
||||
TORRENT_TEST(try_next)
|
||||
{
|
||||
// ========================================
|
||||
// test that we move on to try the next tier if the first one fails
|
||||
// ========================================
|
||||
|
||||
int http_port = start_web_server();
|
||||
int udp_port = start_udp_tracker();
|
||||
|
||||
int prev_udp_announces = num_udp_announces();
|
||||
|
||||
settings_pack pack = settings();
|
||||
pack.set_bool(settings_pack::announce_to_all_trackers, true);
|
||||
pack.set_bool(settings_pack::announce_to_all_tiers, false);
|
||||
pack.set_int(settings_pack::tracker_completion_timeout, 2);
|
||||
pack.set_int(settings_pack::tracker_receive_timeout, 1);
|
||||
pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:39775");
|
||||
|
||||
boost::scoped_ptr<lt::session> s(new lt::session(pack));
|
||||
|
||||
error_code ec;
|
||||
remove_all("tmp2_tracker", ec);
|
||||
create_directory("tmp2_tracker", ec);
|
||||
std::ofstream file(combine_path("tmp2_tracker", "temporary").c_str());
|
||||
boost::shared_ptr<torrent_info> t = ::create_torrent(&file, "temporary", 16 * 1024, 13, false);
|
||||
file.close();
|
||||
|
||||
// this should fail
|
||||
char tracker_url[200];
|
||||
snprintf(tracker_url, sizeof(tracker_url), "udp://www1.non-existent.com:80/announce");
|
||||
t->add_tracker(tracker_url, 0);
|
||||
|
||||
// and this should fail
|
||||
snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.2:3/announce");
|
||||
t->add_tracker(tracker_url, 1);
|
||||
|
||||
// this should be announced to
|
||||
// udp trackers are prioritized if they're on the same host as an http one
|
||||
// so this must be before the http one on 127.0.0.1
|
||||
snprintf(tracker_url, sizeof(tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
|
||||
t->add_tracker(tracker_url, 2);
|
||||
|
||||
// and this should not be announced to (since the one before it succeeded)
|
||||
snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.1:%d/announce", http_port);
|
||||
t->add_tracker(tracker_url, 3);
|
||||
|
||||
prev_udp_announces = num_udp_announces();
|
||||
|
||||
add_torrent_params addp;
|
||||
addp.flags &= ~add_torrent_params::flag_paused;
|
||||
addp.flags &= ~add_torrent_params::flag_auto_managed;
|
||||
addp.flags |= add_torrent_params::flag_seed_mode;
|
||||
addp.ti = t;
|
||||
addp.save_path = "tmp2_tracker";
|
||||
torrent_handle h = s->add_torrent(addp);
|
||||
|
||||
for (int i = 0; i < 50; ++i)
|
||||
{
|
||||
print_alerts(*s, "s");
|
||||
if (num_udp_announces() == prev_udp_announces + 1) break;
|
||||
|
||||
fprintf(stderr, "UDP: %d / %d\n", int(num_udp_announces())
|
||||
, int(prev_udp_announces) + 1);
|
||||
test_sleep(100);
|
||||
}
|
||||
|
||||
// we expect the first two trackers to have failed (because the hostname
|
||||
// doesn't exist and the port isn't open),
|
||||
// the second tracker to have succeeded and the third to not have been used
|
||||
std::vector<announce_entry> tr = h.trackers();
|
||||
|
||||
TEST_EQUAL(tr.size(), 4);
|
||||
|
||||
if (tr.size() == 4)
|
||||
{
|
||||
// this tracker may not have failed yet, but just timed out (if the
|
||||
// hostname lookup is slow)
|
||||
if (tr[0].fails == 1)
|
||||
{
|
||||
TEST_EQUAL(tr[0].verified, false);
|
||||
TEST_EQUAL(tr[0].last_error
|
||||
, error_code(boost::asio::error::host_not_found));
|
||||
}
|
||||
|
||||
TEST_EQUAL(tr[1].fails, 1);
|
||||
TEST_EQUAL(tr[1].verified, false);
|
||||
const bool tracker_error = tr[1].last_error == boost::asio::error::timed_out
|
||||
|| tr[1].last_error == boost::system::error_condition(boost::system::errc::connection_refused)
|
||||
#ifdef TORRENT_WINDOWS
|
||||
|| tr[1].last_error == boost::system::error_code(ERROR_CONNECTION_REFUSED, boost::system::system_category())
|
||||
#endif
|
||||
;
|
||||
TEST_EQUAL(tracker_error, true);
|
||||
|
||||
TEST_EQUAL(tr[2].fails, 0);
|
||||
TEST_EQUAL(tr[2].verified, true);
|
||||
|
||||
TEST_EQUAL(tr[3].fails, 0);
|
||||
TEST_EQUAL(tr[3].verified, false);
|
||||
}
|
||||
test_sleep(1000);
|
||||
|
||||
TEST_EQUAL(num_udp_announces(), prev_udp_announces + 1);
|
||||
|
||||
fprintf(stderr, "destructing session\n");
|
||||
s.reset();
|
||||
fprintf(stderr, "done\n");
|
||||
|
||||
fprintf(stderr, "stop_tracker\n");
|
||||
stop_udp_tracker();
|
||||
fprintf(stderr, "stop_web_server\n");
|
||||
stop_web_server();
|
||||
fprintf(stderr, "done\n");
|
||||
}
|
||||
|
||||
TORRENT_TEST(http_peers)
|
||||
{
|
||||
int http_port = start_web_server();
|
||||
|
|
|
@ -12,7 +12,7 @@ EXTRA_DIST = Jamfile \
|
|||
parse_dht_log.py \
|
||||
parse_dht_rtt.py \
|
||||
parse_dht_stats.py \
|
||||
parse_disk_access.py \
|
||||
parse_access_log.py \
|
||||
parse_disk_buffer_log.py\
|
||||
parse_disk_log.py \
|
||||
parse_memory_log.py \
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os, sys, time
|
||||
|
||||
lines = open(sys.argv[1], 'rb').readlines()
|
||||
|
||||
# logfile format:
|
||||
# <time(us)> <key>: <value>
|
||||
# example:
|
||||
# 16434 read cache: 17
|
||||
|
||||
keys = ['read', 'write', 'head movement', 'seek per read byte', 'seek per written byte',
|
||||
'read operations per second', 'write operations per second']
|
||||
colors = ['305030', '503030', '3030f0', '10a010', 'a01010', 'd0d040', 'd040d0']
|
||||
style = ['dots', 'points', 'lines', 'lines', 'lines', 'lines', 'lines']
|
||||
axis = ['x1y1', 'x1y1', 'x1y2', 'x1y2', 'x1y2', 'x1y2', 'x1y2']
|
||||
plot = [True, False, False, False, False, True, False]
|
||||
|
||||
out = open('disk_access_log.dat', 'w+')
|
||||
|
||||
time = 1000000
|
||||
|
||||
last_pos = 0
|
||||
last_t = 0
|
||||
cur_movement = 0
|
||||
cur_read = 0
|
||||
cur_write = 0
|
||||
cur_read_ops = 0
|
||||
cur_write_ops = 0
|
||||
|
||||
for l in lines:
|
||||
try:
|
||||
# strip newline
|
||||
l = l[0:-1].split(' ')
|
||||
t = int(l[0])
|
||||
k = l[1]
|
||||
n = int(l[2])
|
||||
except:
|
||||
print l
|
||||
continue
|
||||
|
||||
read = '-'
|
||||
write = '-'
|
||||
movement = '-'
|
||||
amount_read = '-'
|
||||
amount_write = '-'
|
||||
read_ops = '-'
|
||||
write_ops = '-'
|
||||
if k == 'read':
|
||||
read = '%d' % n
|
||||
cur_read_ops += 1
|
||||
if k == 'write':
|
||||
write = '%d' % n
|
||||
cur_write_ops += 1
|
||||
if k == 'read_end': cur_read += n - last_pos
|
||||
if k == 'write_end': cur_write += n - last_pos
|
||||
|
||||
cur_movement += abs(last_pos - n)
|
||||
last_pos = n
|
||||
|
||||
if last_t + time <= t:
|
||||
movement = '%d' % cur_movement
|
||||
if cur_read > 0:
|
||||
amount_read = '%d' % (cur_movement / cur_read)
|
||||
if cur_write > 0:
|
||||
amount_write = '%d' % (cur_movement / cur_write)
|
||||
read_ops = '%d' % cur_read_ops
|
||||
write_ops = '%d' % cur_write_ops
|
||||
cur_movement = 0
|
||||
cur_read = 0
|
||||
cur_write = 0
|
||||
last_t = t
|
||||
cur_read_ops = 0
|
||||
cur_write_ops = 0
|
||||
|
||||
print >>out, '%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s' % (t, read, write, movement, amount_read, amount_write, read_ops, write_ops)
|
||||
|
||||
out.close()
|
||||
|
||||
out = open('disk_access.gnuplot', 'wb')
|
||||
print >>out, "set term png size 1200,700"
|
||||
print >>out, 'set output "disk_access.png"'
|
||||
print >>out, 'set xrange [*:*]'
|
||||
#print >>out, 'set y2range [0:*]'
|
||||
print >>out, 'set xlabel "time (us)"'
|
||||
print >>out, 'set ylabel "drive offset"'
|
||||
#print >>out, 'set y2label "bytes / %d second(s)"' % (time / 1000)
|
||||
print >>out, "set key box"
|
||||
print >>out, "set tics nomirror"
|
||||
print >>out, "set y2tics auto"
|
||||
print >>out, 'plot',
|
||||
count = 1
|
||||
for k in keys:
|
||||
count += 1
|
||||
if not plot[count-2]: continue
|
||||
print >>out, ' "disk_access_log.dat" using 1:%d title "%s" with %s lt rgb "#%s" axis %s,' \
|
||||
% (count, k, style[count-2], colors[count-2], axis[count-2]),
|
||||
print >>out, 'x=0'
|
||||
out.close()
|
||||
|
||||
os.system('gnuplot disk_access.gnuplot')
|
||||
|