premiere-libtorrent/docs/libtorrent_plugins.html

396 lines
18 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.10: http://docutils.sourceforge.net/" />
<title></title>
<meta name="author" content="Arvid Norberg, arvid&#64;rasterbar.com" />
<link rel="stylesheet" type="text/css" href="../../css/base.css" />
<link rel="stylesheet" type="text/css" href="../../css/rst.css" />
<script type="text/javascript">
/* <![CDATA[ */
(function() {
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
s.type = 'text/javascript';
s.async = true;
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
t.parentNode.insertBefore(s, t);
})();
/* ]]> */
</script>
<link rel="stylesheet" href="style.css" type="text/css" />
<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">
<div id="headerNav">
<ul>
<li class="first"><a href="/">Home</a></li>
<li><a href="../../products.html">Products</a></li>
<li><a href="../../contact.html">Contact</a></li>
</ul>
</div>
<div id="header">
<div id="orange"></div>
<div id="logo"></div>
</div>
<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&#64;rasterbar.com">arvid&#64;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="#plugin" id="id4">plugin</a></li>
<li><a class="reference internal" href="#torrent-plugin" id="id5">torrent_plugin</a><ul>
<li><a class="reference internal" href="#new-connection" id="id6">new_connection()</a></li>
<li><a class="reference internal" href="#on-piece-pass-on-piece-fail" id="id7">on_piece_pass() on_piece_fail()</a></li>
<li><a class="reference internal" href="#tick" id="id8">tick()</a></li>
<li><a class="reference internal" href="#on-pause-on-resume" id="id9">on_pause() on_resume()</a></li>
<li><a class="reference internal" href="#on-files-checked" id="id10">on_files_checked()</a></li>
<li><a class="reference internal" href="#on-add-peer" id="id11">on_add_peer()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#peer-plugin" id="id12">peer_plugin</a></li>
<li><a class="reference internal" href="#disk-buffer-holder" id="id13">disk_buffer_holder</a></li>
<li><a class="reference internal" href="#custom-alerts" id="id14">custom alerts</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>
<li>save and restore state via the session state</li>
<li>see all alerts that are posted</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 network 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, it is advised to use an internal queue, and do the actual
sending in <tt class="docutils literal">tick()</tt>.</p>
<p>Since the plugin interface gives you easy access to internal structures, it
is not supported as a stable API. Plugins should be considered spcific to a
specific version of libtorrent. Although, in practice the internals mostly
don't change that dramatically.</p>
</div>
</div>
<div class="section" id="plugin-interface">
<h1>plugin interface</h1>
<p>The plugin interface consists of three base classes that the plugin may
implement. These are called <tt class="docutils literal">plugin</tt>, <tt class="docutils literal">torrent_plugin</tt> and <tt class="docutils literal">peer_plugin</tt>.
They are found in the <tt class="docutils literal">&lt;libtorrent/extensions.hpp&gt;</tt> header.</p>
<p>These plugins are instantiated for each session, torrent and possibly each peer,
respectively.</p>
<p>For plugins that only need per torrent state, it is enough to only implement
<tt class="docutils literal">torrent_plugin</tt> and pass a constructor 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&lt;torrent_plugin&gt; (*)(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&lt;torrent_plugin&gt;</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">torrent_plugin</tt>), it will be associated with this torrent and callbacks
will be made on torrent events.</p>
<p>For more elaborate plugins which require session wide state, you would
implement <tt class="docutils literal">plugin</tt>, construct an object (in a <tt class="docutils literal"><span class="pre">boost::shared_ptr</span></tt>) and pass
it in to <tt class="docutils literal"><span class="pre">session::add_extension()</span></tt>.</p>
</div>
<div class="section" id="plugin">
<h1>plugin</h1>
<pre class="literal-block">
struct plugin
{
virtual ~plugin();
virtual boost::shared_ptr&lt;torrent_plugin&gt; new_torrent(torrent* t, void* user);
virtual void added(boost::weak_ptr&lt;aux::session_impl&gt; s);
virtual void on_alert(alert const* a);
virtual void on_tick();
virtual void save_state(entry&amp; ent) const;
virtual void load_state(lazy_entry const&amp; ent);
};
</pre>
</div>
<div class="section" id="torrent-plugin">
<h1>torrent_plugin</h1>
<p>The synopsis for <tt class="docutils literal">torrent_plugin</tt> follows:</p>
<pre class="literal-block">
struct torrent_plugin
{
virtual ~torrent_plugin();
virtual boost::shared_ptr&lt;peer_plugin&gt; 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();
virtual void on_state(int s);
enum flags_t {
first_time = 1,
filtered = 2
};
virtual void on_add_peer(tcp::endpoint const&amp; ip
, int src, int flags);
};
</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&lt;peer_plugin&gt; 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">shared_ptr</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">peer_plugin</tt> class. Which in
turn will have its hook functions called on event specific to that peer.</p>
<p>The <tt class="docutils literal">peer_connection</tt> will be valid as long as the <tt class="docutils literal">shared_ptr</tt> is being
held by the torrent object. So, it is generally a good idea to not keep a
<tt class="docutils literal">shared_ptr</tt> to your own peer_plugin. If you want to keep references to it,
use <tt class="docutils literal">weak_ptr</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">index</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">torrent</tt> and the <tt class="docutils literal">piece_picker</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">true</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">pause()</tt> or <tt class="docutils literal">resume()</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 class="section" id="on-add-peer">
<h2>on_add_peer()</h2>
<pre class="literal-block">
enum flags_t {
first_time = 1,
filtered = 2
};
virtual void on_add_peer(tcp::endpoint const&amp; ip
, int src, int flags);
</pre>
<p>This function is called whenever we hear about a peer from any peer source,
such as the tracker, PEX, DHT or Local peer discovery.</p>
<p><tt class="docutils literal">src</tt> is a bitmask of <tt class="docutils literal"><span class="pre">peer_info::peer_source_flags</span></tt>:</p>
<pre class="literal-block">
enum peer_source_flags
{
tracker = 0x1,
dht = 0x2,
pex = 0x4,
lsd = 0x8,
resume_data = 0x10,
incoming = 0x20
};
</pre>
<p><tt class="docutils literal">flags</tt> is a bitmask of:</p>
<pre class="literal-block">
enum flags_t {
first_time = 1,
filtered = 2
};
</pre>
<p>If the <tt class="docutils literal">filtered</tt> flag is set, it means the peer wasn't added to the
peer list because of and IP filter, port filter, reserved ports filter.</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&amp;);
virtual bool on_handshake(char const* reserved_bits);
virtual bool on_extension_handshake(lazy_entry const&amp; 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&amp; 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&amp; req);
virtual bool on_piece(peer_request const&amp; piece, disk_buffer_holder&amp; buffer);
virtual bool on_cancel(peer_request const&amp; req);
virtual bool on_reject(peer_request const&amp; 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&amp; 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&amp; s, char* b);
~disk_buffer_holder();
char* release();
char* buffer();
};
</pre>
<p>The disk buffer holder acts like a <tt class="docutils literal">scoped_ptr</tt> that frees a disk buffer
when it's destructed, unless it's released. <tt class="docutils literal">release</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">buffer()</tt> returns the pointer without transferring responsibility. If
this buffer has been released, <tt class="docutils literal">buffer()</tt> will return 0.</p>
</div>
<div class="section" id="custom-alerts">
<h1>custom alerts</h1>
<p>Since plugins are running within internal libtorrent threads, one convenient
way to communicate with the client is to post custom alerts.</p>
<p>The expected interface of any alert, apart from deriving from the <tt class="docutils literal">alert</tt>
base class, looks like this:</p>
<pre class="literal-block">
const static int alert_type = <em>&lt;unique alert ID&gt;</em>;
virtual int type() const { return alert_type; }
virtual std::string message() const;
virtual std::auto_ptr&lt;alert&gt; clone() const
{ return std::auto_ptr&lt;alert&gt;(new name(*this)); }
const static int static_category = <em>&lt;bitmask of alert::category_t flags&gt;</em>;
virtual int category() const { return static_category; }
virtual char const* what() const { return <em>&lt;string literal of the name of this alert&gt;</em>; }
</pre>
<p>The <tt class="docutils literal">alert_type</tt> is used for the type-checking in <tt class="docutils literal">alert_cast</tt>. It must not collide with
any other alert. The built-in alerts in libtorrent will not use alert type IDs greater than
<tt class="docutils literal">user_alert_id</tt>. When defining your own alert, make sure it's greater than this constant.</p>
<p><tt class="docutils literal">type()</tt> is the run-time equivalence of the <tt class="docutils literal">alert_type</tt>.</p>
<p>The <tt class="docutils literal">message()</tt> virtual function is expected to construct a useful string representation
of the alert and the event or data it represents. Something convenient to put in a log file
for instance.</p>
<p><tt class="docutils literal">clone()</tt> is used internally to copy alerts. The suggested implementation of simply
allocating a new instance as a copy of <tt class="docutils literal">*this</tt> is all that's expected.</p>
<p>The static category is required for checking wether or not the category for a specific alert
is enabled or not, without instantiating the alert. The <tt class="docutils literal">category</tt> virtual function is
the run-time equivalence.</p>
<p>The <tt class="docutils literal">what()</tt> virtual function may simply be a string literal of the class name of
your alert.</p>
<p>For more information, see the <a class="reference external" href="reference-Alerts.html">alert section</a>.</p>
</div>
</div>
<div id="footer">
<span>Copyright &copy; 2005-2013 Rasterbar Software.</span>
</div>
</div>
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-1599045-1";
urchinTracker();
</script>
</div>
</body>
</html>