twisterp2pnetworkbittorrentblockchainipv6microbloggingsocial-networkdhtdecentralizedtwister-servertwister-ipv6twister-coretwisterarmyp2p-network
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
395 lines
18 KiB
395 lines
18 KiB
<?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@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"> |
|
<h1><span>Rasterbar Software</span></h1> |
|
<h2><span>Software developement and consulting</span></h2> |
|
</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@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="#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"><libtorrent/extensions.hpp></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<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">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<torrent_plugin> new_torrent(torrent* t, void* user); |
|
|
|
virtual void added(boost::weak_ptr<aux::session_impl> s); |
|
virtual void on_alert(alert const* a); |
|
virtual void on_tick(); |
|
virtual void save_state(entry& ent) const; |
|
virtual void load_state(lazy_entry const& 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<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(); |
|
|
|
virtual void on_state(int s); |
|
|
|
enum flags_t { |
|
first_time = 1, |
|
filtered = 2 |
|
}; |
|
|
|
virtual void on_add_peer(tcp::endpoint const& 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<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">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& 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&); |
|
virtual bool on_handshake(char const* reserved_bits); |
|
virtual bool on_extension_handshake(lazy_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">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><unique alert ID></em>; |
|
virtual int type() const { return alert_type; } |
|
|
|
virtual std::string message() const; |
|
|
|
virtual std::auto_ptr<alert> clone() const |
|
{ return std::auto_ptr<alert>(new name(*this)); } |
|
|
|
const static int static_category = <em><bitmask of alert::category_t flags></em>; |
|
virtual int category() const { return static_category; } |
|
|
|
virtual char const* what() const { return <em><string literal of the name of this alert></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 alert section in the <a class="reference external" href="manual.html">main manual</a>.</p> |
|
</div> |
|
</div> |
|
<div id="footer"> |
|
<span>Copyright © 2005 Rasterbar Software.</span> |
|
</div> |
|
</div> |
|
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript"> |
|
</script> |
|
<script type="text/javascript"> |
|
_uacct = "UA-1599045-1"; |
|
urchinTracker(); |
|
</script> |
|
</div> |
|
</body> |
|
</html>
|
|
|