243 lines
12 KiB
HTML
243 lines
12 KiB
HTML
<?xml version="1.0" encoding="utf-8" ?>
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" />
|
|
<title></title>
|
|
<meta name="author" content="Arvid Norberg, arvid@rasterbar.com" />
|
|
<link rel="stylesheet" href="style.css" type="text/css" />
|
|
</head>
|
|
<body>
|
|
<div class="document">
|
|
|
|
<table class="docinfo" frame="void" rules="none">
|
|
<col class="docinfo-name" />
|
|
<col class="docinfo-content" />
|
|
<tbody valign="top">
|
|
<tr><th class="docinfo-name">Author:</th>
|
|
<td>Arvid Norberg, <a class="last reference external" href="mailto:arvid@rasterbar.com">arvid@rasterbar.com</a></td></tr>
|
|
</tbody>
|
|
</table>
|
|
<div class="section" id="libtorrent-plugins">
|
|
<h1>libtorrent plugins</h1>
|
|
<div class="contents topic" id="contents">
|
|
<p class="topic-title first">Contents</p>
|
|
<ul class="simple">
|
|
<li><a class="reference internal" href="#libtorrent-plugins" id="id1">libtorrent plugins</a><ul>
|
|
<li><a class="reference internal" href="#a-word-of-caution" id="id2">a word of caution</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="reference internal" href="#plugin-interface" id="id3">plugin interface</a></li>
|
|
<li><a class="reference internal" href="#torrent-plugin" id="id4">torrent_plugin</a><ul>
|
|
<li><a class="reference internal" href="#new-connection" id="id5">new_connection()</a></li>
|
|
<li><a class="reference internal" href="#on-piece-pass-on-piece-fail" id="id6">on_piece_pass() on_piece_fail()</a></li>
|
|
<li><a class="reference internal" href="#tick" id="id7">tick()</a></li>
|
|
<li><a class="reference internal" href="#on-pause-on-resume" id="id8">on_pause() on_resume()</a></li>
|
|
<li><a class="reference internal" href="#on-files-checked" id="id9">on_files_checked()</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="reference internal" href="#peer-plugin" id="id10">peer_plugin</a></li>
|
|
<li><a class="reference internal" href="#disk-buffer-holder" id="id11">disk_buffer_holder</a></li>
|
|
</ul>
|
|
</div>
|
|
<p>libtorrent has a plugin interface for implementing extensions to the protocol.
|
|
These can be general extensions for transferring metadata or peer exchange
|
|
extensions, or it could be used to provide a way to customize the protocol
|
|
to fit a particular (closed) network.</p>
|
|
<p>In short, the plugin interface makes it possible to:</p>
|
|
<ul class="simple">
|
|
<li>register extension messages (sent in the extension handshake), see
|
|
<a class="reference external" href="extension_protocol.html">extensions</a>.</li>
|
|
<li>add data and parse data from the extension handshake.</li>
|
|
<li>send extension messages and standard bittorrent messages.</li>
|
|
<li>override or block the handling of standard bittorrent messages.</li>
|
|
</ul>
|
|
<div class="section" id="a-word-of-caution">
|
|
<h2>a word of caution</h2>
|
|
<p>Writing your own plugin is a very easy way to introduce serious bugs such as
|
|
dead locks and race conditions. Since a plugin has access to internal
|
|
structures it is also quite easy to sabotage libtorrent's operation.</p>
|
|
<p>All the callbacks in this interface are called with the main libtorrent thread
|
|
mutex locked. And they are always called from the libtorrent main thread. In
|
|
case portions of your plugin are called from other threads, typically the main
|
|
thread, you cannot use any of the member functions on the internal structures
|
|
in libtorrent, since those require the mutex to be locked. Futhermore, you would
|
|
also need to have a mutex on your own shared data within the plugin, to make
|
|
sure it is not accessed at the same time from the libtorrent thread (through a
|
|
callback). See <a class="reference external" href="http://www.boost.org/doc/html/mutex.html">boost thread's mutex</a>. If you need to send out a message from
|
|
another thread, use an internal queue, and do the actual sending in <tt class="docutils literal"><span class="pre">tick()</span></tt>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="plugin-interface">
|
|
<h1>plugin interface</h1>
|
|
<p>The plugin interface consists of two base classes that the plugin may
|
|
implement. These are called <tt class="docutils literal"><span class="pre">torrent_plugin</span></tt> and <tt class="docutils literal"><span class="pre">peer_plugin</span></tt>. They are
|
|
both found in the <tt class="docutils literal"><span class="pre"><libtorrent/extensions.hpp></span></tt> header.</p>
|
|
<p>These plugins are instantiated for each torrent and possibly each peer,
|
|
respectively.</p>
|
|
<p>This is done by passing in a function or function object to
|
|
<tt class="docutils literal"><span class="pre">session::add_extension()</span></tt> or <tt class="docutils literal"><span class="pre">torrent_handle::add_extension()</span></tt> (if the
|
|
torrent has already been started and you want to hook in the extension at
|
|
run-time).</p>
|
|
<p>The signature of the function is:</p>
|
|
<pre class="literal-block">
|
|
boost::shared_ptr<torrent_plugin> (*)(torrent*, void*);
|
|
</pre>
|
|
<p>The first argument is the internal torrent object, the second argument
|
|
is the userdata passed to <tt class="docutils literal"><span class="pre">session::add_torrent()</span></tt> or
|
|
<tt class="docutils literal"><span class="pre">torrent_handle::add_extension()</span></tt>.</p>
|
|
<p>The function should return a <tt class="docutils literal"><span class="pre">boost::shared_ptr<torrent_plugin></span></tt> which
|
|
may or may not be 0. If it is a null pointer, the extension is simply ignored
|
|
for this torrent. If it is a valid pointer (to a class inheriting
|
|
<tt class="docutils literal"><span class="pre">torrent_plugin</span></tt>), it will be associated with this torrent and callbacks
|
|
will be made on torrent events.</p>
|
|
</div>
|
|
<div class="section" id="torrent-plugin">
|
|
<h1>torrent_plugin</h1>
|
|
<p>The synopsis for <tt class="docutils literal"><span class="pre">torrent_plugin</span></tt> follows:</p>
|
|
<pre class="literal-block">
|
|
struct torrent_plugin
|
|
{
|
|
virtual ~torrent_plugin();
|
|
virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection*);
|
|
|
|
virtual void on_piece_pass(int index);
|
|
virtual void on_piece_failed(int index);
|
|
|
|
virtual void tick();
|
|
|
|
virtual bool on_pause();
|
|
virtual bool on_resume();
|
|
|
|
virtual void on_files_checked();
|
|
};
|
|
</pre>
|
|
<p>This is the base class for a torrent_plugin. Your derived class is (if added
|
|
as an extension) instantiated for each torrent in the session. The callback
|
|
hook functions are defined as follows.</p>
|
|
<div class="section" id="new-connection">
|
|
<h2>new_connection()</h2>
|
|
<pre class="literal-block">
|
|
boost::shared_ptr<peer_plugin> new_connection(peer_connection*);
|
|
</pre>
|
|
<p>This function is called each time a new peer is connected to the torrent. You
|
|
may choose to ignore this by just returning a default constructed
|
|
<tt class="docutils literal"><span class="pre">shared_ptr</span></tt> (in which case you don't need to override this member
|
|
function).</p>
|
|
<p>If you need an extension to the peer connection (which most plugins do) you
|
|
are supposed to return an instance of your <tt class="docutils literal"><span class="pre">peer_plugin</span></tt> class. Which in
|
|
turn will have its hook functions called on event specific to that peer.</p>
|
|
<p>The <tt class="docutils literal"><span class="pre">peer_connection</span></tt> will be valid as long as the <tt class="docutils literal"><span class="pre">shared_ptr</span></tt> is being
|
|
held by the torrent object. So, it is generally a good idea to not keep a
|
|
<tt class="docutils literal"><span class="pre">shared_ptr</span></tt> to your own peer_plugin. If you want to keep references to it,
|
|
use <tt class="docutils literal"><span class="pre">weak_ptr</span></tt>.</p>
|
|
<p>If this function throws an exception, the connection will be closed.</p>
|
|
</div>
|
|
<div class="section" id="on-piece-pass-on-piece-fail">
|
|
<h2>on_piece_pass() on_piece_fail()</h2>
|
|
<pre class="literal-block">
|
|
void on_piece_pass(int index);
|
|
void on_piece_failed(int index);
|
|
</pre>
|
|
<p>These hooks are called when a piece passes the hash check or fails the hash
|
|
check, respectively. The <tt class="docutils literal"><span class="pre">index</span></tt> is the piece index that was downloaded.
|
|
It is possible to access the list of peers that participated in sending the
|
|
piece through the <tt class="docutils literal"><span class="pre">torrent</span></tt> and the <tt class="docutils literal"><span class="pre">piece_picker</span></tt>.</p>
|
|
</div>
|
|
<div class="section" id="tick">
|
|
<h2>tick()</h2>
|
|
<pre class="literal-block">
|
|
void tick();
|
|
</pre>
|
|
<p>This hook is called approximately once per second. It is a way of making it
|
|
easy for plugins to do timed events, for sending messages or whatever.</p>
|
|
</div>
|
|
<div class="section" id="on-pause-on-resume">
|
|
<h2>on_pause() on_resume()</h2>
|
|
<pre class="literal-block">
|
|
bool on_pause();
|
|
bool on_resume();
|
|
</pre>
|
|
<p>These hooks are called when the torrent is paused and unpaused respectively.
|
|
The return value indicates if the event was handled. A return value of
|
|
<tt class="docutils literal"><span class="pre">true</span></tt> indicates that it was handled, and no other plugin after this one
|
|
will have this hook function called, and the standard handler will also not be
|
|
invoked. So, returning true effectively overrides the standard behavior of
|
|
pause or unpause.</p>
|
|
<p>Note that if you call <tt class="docutils literal"><span class="pre">pause()</span></tt> or <tt class="docutils literal"><span class="pre">resume()</span></tt> on the torrent from your
|
|
handler it will recurse back into your handler, so in order to invoke the
|
|
standard handler, you have to keep your own state on whether you want standard
|
|
behavior or overridden behavior.</p>
|
|
</div>
|
|
<div class="section" id="on-files-checked">
|
|
<h2>on_files_checked()</h2>
|
|
<pre class="literal-block">
|
|
void on_files_checked();
|
|
</pre>
|
|
<p>This function is called when the initial files of the torrent have been
|
|
checked. If there are no files to check, this function is called immediately.</p>
|
|
<p>i.e. This function is always called when the torrent is in a state where it
|
|
can start downloading.</p>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="peer-plugin">
|
|
<h1>peer_plugin</h1>
|
|
<pre class="literal-block">
|
|
struct peer_plugin
|
|
{
|
|
virtual ~peer_plugin();
|
|
|
|
virtual void add_handshake(entry&);
|
|
virtual bool on_handshake(char const* reserved_bits);
|
|
virtual bool on_extension_handshake(entry const& h);
|
|
|
|
virtual bool on_choke();
|
|
virtual bool on_unchoke();
|
|
virtual bool on_interested();
|
|
virtual bool on_not_interested();
|
|
virtual bool on_have(int index);
|
|
virtual bool on_bitfield(bitfield const& bits);
|
|
virtual bool on_have_all();
|
|
virtual bool on_have_none();
|
|
virtual bool on_allowed_fast(int index);
|
|
virtual bool on_request(peer_request const& req);
|
|
virtual bool on_piece(peer_request const& piece, disk_buffer_holder& buffer);
|
|
virtual bool on_cancel(peer_request const& req);
|
|
virtual bool on_reject(peer_request const& req);
|
|
virtual bool on_suggest(int index);
|
|
virtual bool on_extended(int length
|
|
, int msg, buffer::const_interval body);
|
|
virtual bool on_unknown_message(int length, int msg
|
|
, buffer::const_interval body);
|
|
virtual void on_piece_pass(int index);
|
|
virtual void on_piece_failed(int index);
|
|
|
|
virtual void tick();
|
|
|
|
virtual bool write_request(peer_request const& r);
|
|
};
|
|
</pre>
|
|
</div>
|
|
<div class="section" id="disk-buffer-holder">
|
|
<h1>disk_buffer_holder</h1>
|
|
<pre class="literal-block">
|
|
struct disk_buffer_holder
|
|
{
|
|
disk_buffer_holder(aux::session_impl& s, char* b);
|
|
~disk_buffer_holder();
|
|
char* release();
|
|
char* buffer();
|
|
};
|
|
</pre>
|
|
<p>The disk buffer holder acts like a <tt class="docutils literal"><span class="pre">scoped_ptr</span></tt> that frees a disk buffer
|
|
when it's destructed, unless it's released. <tt class="docutils literal"><span class="pre">release</span></tt> returns the disk
|
|
buffer and transferres ownership and responsibility to free it to the caller.</p>
|
|
<p>A disk buffer is freed by passing it to <tt class="docutils literal"><span class="pre">session_impl::free_disk_buffer()</span></tt>.</p>
|
|
<p><tt class="docutils literal"><span class="pre">buffer()</span></tt> returns the pointer without transferring responsibility. If
|
|
this buffer has been released, <tt class="docutils literal"><span class="pre">buffer()</span></tt> will return 0.</p>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|