completed IPv6 support in ip_filter and updated test_ip_filter and documentation. Documented recently added extensions to DHT.

This commit is contained in:
Arvid Norberg 2006-09-23 21:24:28 +00:00
parent a42189af62
commit fe0d570f05
16 changed files with 473 additions and 221 deletions

View File

@ -1,3 +1,6 @@
* added an extension to the DHT network protocol to support the
exchange of nodes with IPv6 addresses.
* modified the ip_filter api slightly to support IPv6
* modified the api slightly to make sequenced download threshold * modified the api slightly to make sequenced download threshold
a per torrent-setting. a per torrent-setting.
* changed the address type to support IPv6 * changed the address type to support IPv6

View File

@ -242,6 +242,14 @@ logging=none dht-support=on dht-support=logging dht-support=off
<h2><a name="building-with-autotools">building with autotools</a></h2> <h2><a name="building-with-autotools">building with autotools</a></h2>
<p>First of all, you need to install <tt class="docutils literal"><span class="pre">automake</span></tt> and <tt class="docutils literal"><span class="pre">autoconf</span></tt>. Many <p>First of all, you need to install <tt class="docutils literal"><span class="pre">automake</span></tt> and <tt class="docutils literal"><span class="pre">autoconf</span></tt>. Many
unix/linux systems comes with these preinstalled.</p> unix/linux systems comes with these preinstalled.</p>
<p>The prerequisites for building libtorrent is 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"><span class="pre">client_test</span></tt> example, you'll also need boost.regex
and boost.program_options.</p>
<div class="section" id="step-1-generating-the-build-system"> <div class="section" id="step-1-generating-the-build-system">
<h3><a name="step-1-generating-the-build-system">Step 1: Generating the build system</a></h3> <h3><a name="step-1-generating-the-build-system">Step 1: Generating the build system</a></h3>
<p>No build system is present if libtorrent is checked out from CVS - it <p>No build system is present if libtorrent is checked out from CVS - it

View File

@ -232,6 +232,16 @@ building with autotools
First of all, you need to install ``automake`` and ``autoconf``. Many First of all, you need to install ``automake`` and ``autoconf``. Many
unix/linux systems comes with these preinstalled. unix/linux systems comes with these preinstalled.
The prerequisites for building libtorrent is boost.thread, boost.date_time
and boost.filesystem. Those are the *compiled* 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.
If you want to build the ``client_test`` example, you'll also need boost.regex
and boost.program_options.
Step 1: Generating the build system Step 1: Generating the build system
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

66
docs/dht_extensions.html Normal file
View File

@ -0,0 +1,66 @@
<?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.3.9: http://docutils.sourceforge.net/" />
<title></title>
<meta name="author" content="Arvid Norberg, arvid&#64;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" href="mailto:arvid&#64;rasterbar.com">arvid&#64;rasterbar.com</a></td></tr>
</tbody>
</table>
<div class="section" id="mainline-dht-extensions">
<h1><a name="mainline-dht-extensions">Mainline DHT extensions</a></h1>
<p>libtorrent implements a few extensions to the Mainline DHT protocol.</p>
<div class="section" id="client-identification">
<h2><a name="client-identification">client identification</a></h2>
<p>In each DHT packet, an extra key is inserted named &quot;v&quot;. 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"><span class="pre">UT</span></tt></td>
</tr>
<tr><td>libtorrent</td>
<td><tt class="docutils literal"><span class="pre">LT</span></tt></td>
</tr>
<tr><td>MooPolice</td>
<td><tt class="docutils literal"><span class="pre">MP</span></tt></td>
</tr>
<tr><td>GetRight</td>
<td><tt class="docutils literal"><span class="pre">GR</span></tt></td>
</tr>
</tbody>
</table>
</div>
<div class="section" id="ipv6-support">
<h2><a name="ipv6-support">IPv6 support</a></h2>
<p>The only DHT messages that don't support IPv6 is the <tt class="docutils literal"><span class="pre">nodes</span></tt> reply. It
encodes all the contacts as 6 bytes sequences packed together in sequence in
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"><span class="pre">nodes2</span></tt> which 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>
</div>
</div>
</div>
</body>
</html>

View File

@ -30,10 +30,11 @@ IPv6 support
------------ ------------
The only DHT messages that don't support IPv6 is the ``nodes`` reply. It The only DHT messages that don't support IPv6 is the ``nodes`` reply. It
encodes all the contacts as 6 bytes sequences packet together in sequence in encodes all the contacts as 6 bytes sequences packed together in sequence in
string. The problem is that IPv6 endpoints cannot be encoded as 6 bytes, but string. The problem is that IPv6 endpoints cannot be encoded as 6 bytes, but
18 bytes. The extension libtorrent applies is to add another key, called needs 18 bytes. The extension libtorrent applies is to add another key, called
``nodes2`` which is encoded as a list of strings. Each string represents one ``nodes2`` which 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 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). IP address (6 bytes in IPv4 case and 18 bytes in IPv6 case).

View File

@ -34,7 +34,8 @@
<h1><a name="examples">examples</a></h1> <h1><a name="examples">examples</a></h1>
<p>Except for the example programs in this manual, there's also a bigger example <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"><span class="pre">client_test</span></tt>. There are separate of a (little bit) more complete client, <tt class="docutils literal"><span class="pre">client_test</span></tt>. There are separate
instructions for how to use it <a class="reference" href="client_test.html">here</a> if you'd like to try it.</p> instructions for how to use it <a class="reference" href="client_test.html">here</a> if you'd like to try it. Note that building
<tt class="docutils literal"><span class="pre">client_test</span></tt> also requires boost.regex and boost.program_options library.</p>
<div class="section" id="dump-torrent"> <div class="section" id="dump-torrent">
<h2><a name="dump-torrent">dump_torrent</a></h2> <h2><a name="dump-torrent">dump_torrent</a></h2>
<p>This is an example of a program that will take a torrent-file as a parameter and <p>This is an example of a program that will take a torrent-file as a parameter and

View File

@ -13,7 +13,8 @@ examples
Except for the example programs in this manual, there's also a bigger example Except for the example programs in this manual, there's also a bigger example
of a (little bit) more complete client, ``client_test``. There are separate of a (little bit) more complete client, ``client_test``. There are separate
instructions for how to use it here__ if you'd like to try it. instructions for how to use it here__ if you'd like to try it. Note that building
``client_test`` also requires boost.regex and boost.program_options library.
__ client_test.html __ client_test.html

View File

@ -47,44 +47,47 @@ example client.</p>
project (including this documentation). The current state includes the project (including this documentation). The current state includes the
following features:</p> following features:</p>
<ul class="simple"> <ul class="simple">
<li>Trackerless torrents (using a kademlia DHT)</li> <li>trackerless torrents (using the Mainline kademlia DHT protocol) with
some <a class="reference" href="dht_extensions.html">DHT extensions</a>.</li>
<li>support for IPv6</li>
<li>piece-wise, unordered, incremental file allocation</li>
<li>uses separate threads for checking files and for main downloader, with a
fool-proof thread-safe library interface. (i.e. There's no way for the
user to cause a deadlock). (see <a class="reference" href="manual.html#threads">threads</a>)</li>
<li>adjusts the length of the request queue depending on download rate.</li>
<li>multitracker extension support (as <a class="reference" href="http://home.elp.rr.com/tur/multitracker-spec.txt">specified by John Hoffman</a>)</li> <li>multitracker extension support (as <a class="reference" href="http://home.elp.rr.com/tur/multitracker-spec.txt">specified by John Hoffman</a>)</li>
<li>supports files &gt; 2 gigabytes.</li>
<li>serves multiple torrents on a single port and in a single thread</li> <li>serves multiple torrents on a single port and in a single thread</li>
<li>gzipped tracker-responses</li> <li>fast resume support, a way to get rid of 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 separate fast-resume file.</li>
<li><a class="reference" href="manual.html#http-seeding">HTTP seeding</a>, as <a class="reference" href="http://www.getright.com/seedtorrent.html">specified by Michael Burford of GetRight</a>.</li> <li><a class="reference" href="manual.html#http-seeding">HTTP seeding</a>, as <a class="reference" href="http://www.getright.com/seedtorrent.html">specified by Michael Burford of GetRight</a>.</li>
<li>piece picking on block-level (as opposed to piece-level). <li>piece picking on block-level (as opposed to piece-level).
This means it can download parts of the same piece from different peers. 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 It will also prefer to download whole pieces from single peers if the
download speed is high enough from that particular peer.</li> download speed is high enough from that particular peer.</li>
<li>supports the <a class="reference" href="extension_protocol.html">udp-tracker protocol</a> by Olaf van der Spek.</li>
<li>queues torrents for file check, instead of checking all of them in parallel.</li> <li>queues torrents for file check, instead of checking all of them in parallel.</li>
<li>supports http proxies and proxy authentication</li> <li>supports http proxies and basic proxy authentication</li>
<li>uses separate threads for checking files and for main downloader, with a <li>gzipped tracker-responses</li>
fool-proof thread-safe library interface. (i.e. There's no way for the
user to cause a deadlock). (see <a class="reference" href="manual.html#threads">threads</a>)</li>
<li>can limit the upload and download bandwidth usage and the maximum number of <li>can limit the upload and download bandwidth usage and the maximum number of
unchoked peers</li> unchoked peers</li>
<li>piece-wise, unordered, incremental file allocation</li>
<li>implements fair trade. User settable trade-ratio, must at least be 1:1, <li>implements fair trade. User settable trade-ratio, must at least be 1:1,
but one can choose to trade 1 for 2 or any other ratio that isn't unfair but one can choose to trade 1 for 2 or any other ratio that isn't unfair
to the other party.</li> to the other party.</li>
<li>fast resume support, a way to get rid of the costly piece check at the <li>supports an <a class="reference" href="udp_tracker_protocol.html">extension protocol</a>. See <a class="reference" href="manual.html#extensions">extensions</a>.</li>
start of a resumed torrent. Saves the storage state, piece_picker state
as well as all local peers in a separate fast-resume file.</li>
<li>supports an <a class="reference" href="extension_protocol.html">extension protocol</a>. See <a class="reference" href="manual.html#extensions">extensions</a>.</li>
<li>supports files &gt; 2 gigabytes.</li>
<li>supports the <tt class="docutils literal"><span class="pre">no_peer_id=1</span></tt> extension that will ease the load off trackers.</li> <li>supports the <tt class="docutils literal"><span class="pre">no_peer_id=1</span></tt> extension that will ease the load off trackers.</li>
<li>supports the <a class="reference" href="udp_tracker_protocol.html">udp-tracker protocol</a> by Olaf van der Spek.</li>
<li>possibility to limit the number of connections.</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 <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 doesn't send have messages to peers that already has the piece. This saves
bandwidth.</li> bandwidth.</li>
<li>does not have any requirements on the piece order in a torrent that it <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> resumes. This means it can resume a torrent downloaded by any client.</li>
<li>adjusts the length of the request queue depending on download rate.</li>
<li>supports the <tt class="docutils literal"><span class="pre">compact=1</span></tt> tracker parameter.</li> <li>supports the <tt class="docutils literal"><span class="pre">compact=1</span></tt> tracker parameter.</li>
<li>selective downloading. The ability to select which parts of a torrent you <li>selective downloading. The ability to select which parts of a torrent you
want to download.</li> want to download.</li>
<li>ip filter</li> <li>ip filter to disallow ip addresses and ip ranges from connecting and
being connected</li>
</ul> </ul>
</div> </div>
<div class="section" id="portability"> <div class="section" id="portability">

View File

@ -29,45 +29,49 @@ libtorrent is still being developed, however it is stable. It is an ongoing
project (including this documentation). The current state includes the project (including this documentation). The current state includes the
following features: following features:
* Trackerless torrents (using a kademlia DHT) * trackerless torrents (using the Mainline kademlia DHT protocol) with
some `DHT extensions`_.
* support for IPv6
* piece-wise, unordered, incremental file allocation
* uses separate threads for checking files and for main downloader, with a
fool-proof thread-safe library interface. (i.e. There's no way for the
user to cause a deadlock). (see threads_)
* adjusts the length of the request queue depending on download rate.
* multitracker extension support (as `specified by John Hoffman`__) * multitracker extension support (as `specified by John Hoffman`__)
* supports files > 2 gigabytes.
* serves multiple torrents on a single port and in a single thread * serves multiple torrents on a single port and in a single thread
* gzipped tracker-responses * fast resume support, a way to get rid of 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 separate fast-resume file.
* `HTTP seeding`_, as `specified by Michael Burford of GetRight`__. * `HTTP seeding`_, as `specified by Michael Burford of GetRight`__.
* piece picking on block-level (as opposed to piece-level). * piece picking on block-level (as opposed to piece-level).
This means it can download parts of the same piece from different peers. 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 It will also prefer to download whole pieces from single peers if the
download speed is high enough from that particular peer. download speed is high enough from that particular peer.
* supports the `udp-tracker protocol`__ by Olaf van der Spek.
* queues torrents for file check, instead of checking all of them in parallel. * queues torrents for file check, instead of checking all of them in parallel.
* supports http proxies and proxy authentication * supports http proxies and basic proxy authentication
* uses separate threads for checking files and for main downloader, with a * gzipped tracker-responses
fool-proof thread-safe library interface. (i.e. There's no way for the
user to cause a deadlock). (see threads_)
* can limit the upload and download bandwidth usage and the maximum number of * can limit the upload and download bandwidth usage and the maximum number of
unchoked peers unchoked peers
* piece-wise, unordered, incremental file allocation
* implements fair trade. User settable trade-ratio, must at least be 1:1, * implements fair trade. User settable trade-ratio, must at least be 1:1,
but one can choose to trade 1 for 2 or any other ratio that isn't unfair but one can choose to trade 1 for 2 or any other ratio that isn't unfair
to the other party. to the other party.
* fast resume support, a way to get rid of 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 separate fast-resume file.
* supports an `extension protocol`__. See extensions_. * supports an `extension protocol`__. See extensions_.
* supports files > 2 gigabytes.
* supports the ``no_peer_id=1`` extension that will ease the load off trackers. * supports the ``no_peer_id=1`` extension that will ease the load off trackers.
* supports the `udp-tracker protocol`__ by Olaf van der Spek.
* possibility to limit the number of connections. * possibility to limit the number of connections.
* delays have messages if there's no other outgoing traffic to the peer, and * 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 doesn't send have messages to peers that already has the piece. This saves
bandwidth. bandwidth.
* does not have any requirements on the piece order in a torrent that it * 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. resumes. This means it can resume a torrent downloaded by any client.
* adjusts the length of the request queue depending on download rate.
* supports the ``compact=1`` tracker parameter. * supports the ``compact=1`` tracker parameter.
* selective downloading. The ability to select which parts of a torrent you * selective downloading. The ability to select which parts of a torrent you
want to download. want to download.
* ip filter * ip filter to disallow ip addresses and ip ranges from connecting and
being connected
.. _`DHT extensions`: dht_extensions.html
__ http://home.elp.rr.com/tur/multitracker-spec.txt __ http://home.elp.rr.com/tur/multitracker-spec.txt
__ http://www.getright.com/seedtorrent.html __ http://www.getright.com/seedtorrent.html
__ extension_protocol.html __ extension_protocol.html

View File

@ -10,6 +10,7 @@
<body> <body>
<div class="document"> <div class="document">
<div id="librarySidebar"><ul class="simple"> <div id="librarySidebar"><ul class="simple">
<li><a class="reference" href="http://sourceforge.net/project/showfiles.php?group_id=79942">download</a></li>
<li><a class="reference" href="features.html">features</a></li> <li><a class="reference" href="features.html">features</a></li>
<li><a class="reference" href="building.html">building libtorrent</a></li> <li><a class="reference" href="building.html">building libtorrent</a></li>
<li><a class="reference" href="examples.html">examples</a></li> <li><a class="reference" href="examples.html">examples</a></li>

View File

@ -2,7 +2,7 @@
<div id="librarySidebar"> <div id="librarySidebar">
* download_
* features_ * features_
* `building libtorrent`_ * `building libtorrent`_
* examples_ * examples_
@ -22,6 +22,7 @@
libtorrent libtorrent
========== ==========
.. _download: http://sourceforge.net/project/showfiles.php?group_id=79942
.. _features: features.html .. _features: features.html
.. _`building libtorrent`: building.html .. _`building libtorrent`: building.html
.. _examples: examples.html .. _examples: examples.html

View File

@ -1939,28 +1939,32 @@ the number of outstanding requests to use with url-seeds. Default is 5.</p>
<h1><a name="ip-filter">ip_filter</a></h1> <h1><a name="ip-filter">ip_filter</a></h1>
<p>The <tt class="docutils literal"><span class="pre">ip_filter</span></tt> class is a set of rules that uniquely categorizes all <p>The <tt class="docutils literal"><span class="pre">ip_filter</span></tt> class is a set of rules that uniquely categorizes all
ip addresses as allowed or disallowed. The default constructor creates ip addresses as allowed or disallowed. The default constructor creates
a single rule that allows all addresses (0.0.0.0 - 255.255.255.255). a single rule that allows all addresses (0.0.0.0 - 255.255.255.255 for
The <tt class="docutils literal"><span class="pre">address</span></tt> type here is <tt class="docutils literal"><span class="pre">asio::ip::address_v4</span></tt>. It can also be the IPv4 range, and the equivalent range covering all addresses for the
accessed as <tt class="docutils literal"><span class="pre">libtorrent::address</span></tt>.</p> IPv6 range).</p>
<blockquote> <blockquote>
<pre class="literal-block"> <pre class="literal-block">
template &lt;class Addr&gt;
struct ip_range
{
Addr first;
Addr last;
int flags;
};
class ip_filter class ip_filter
{ {
public: public:
enum access_flags { blocked = 1 }; enum access_flags { blocked = 1 };
ip_filter(); ip_filter();
void add_rule(address_v4 first, address_v4 last, int flags); void add_rule(address first, address last, int flags);
int access(address_v4 const&amp; addr) const; int access(address const&amp; addr) const;
struct ip_range typedef boost::tuple&lt;std::vector&lt;ip_range&lt;address_v4&gt; &gt;
{ , std::vector&lt;ip_range&lt;address_v6&gt; &gt; &gt; filter_tuple_t;
address_v4 first;
address_v4 last;
int flags;
};
std::vector&lt;ip_range&gt; export_filter() const; filter_tuple_t export_filter() const;
}; };
</pre> </pre>
</blockquote> </blockquote>
@ -1979,13 +1983,15 @@ ip_filter()
<h2><a name="add-rule">add_rule()</a></h2> <h2><a name="add-rule">add_rule()</a></h2>
<blockquote> <blockquote>
<pre class="literal-block"> <pre class="literal-block">
void add_rule(address_v4 first, address_v4 last, int flags); void add_rule(address first, address last, int flags);
</pre> </pre>
</blockquote> </blockquote>
<p>Adds a rule to the filter. <tt class="docutils literal"><span class="pre">first</span></tt> and <tt class="docutils literal"><span class="pre">last</span></tt> defines a range of <p>Adds a rule to the filter. <tt class="docutils literal"><span class="pre">first</span></tt> and <tt class="docutils literal"><span class="pre">last</span></tt> defines a range of
ip addresses that will be marked with the given flags. The <tt class="docutils literal"><span class="pre">flags</span></tt> ip addresses that will be marked with the given flags. The <tt class="docutils literal"><span class="pre">flags</span></tt>
can currently be 0, which means allowed, or <tt class="docutils literal"><span class="pre">ip_filter::blocked</span></tt>, which can currently be 0, which means allowed, or <tt class="docutils literal"><span class="pre">ip_filter::blocked</span></tt>, which
means disallowed.</p> means disallowed.</p>
<p>precondition:
<tt class="docutils literal"><span class="pre">first.is_v4()</span> <span class="pre">==</span> <span class="pre">last.is_v4()</span> <span class="pre">&amp;&amp;</span> <span class="pre">first.is_v6()</span> <span class="pre">==</span> <span class="pre">last.is_v6()</span></tt></p>
<p>postcondition: <p>postcondition:
<tt class="docutils literal"><span class="pre">access(x)</span> <span class="pre">==</span> <span class="pre">flags</span></tt> for every <tt class="docutils literal"><span class="pre">x</span></tt> in the range [<tt class="docutils literal"><span class="pre">first</span></tt>, <tt class="docutils literal"><span class="pre">last</span></tt>]</p> <tt class="docutils literal"><span class="pre">access(x)</span> <span class="pre">==</span> <span class="pre">flags</span></tt> for every <tt class="docutils literal"><span class="pre">x</span></tt> in the range [<tt class="docutils literal"><span class="pre">first</span></tt>, <tt class="docutils literal"><span class="pre">last</span></tt>]</p>
<p>This means that in a case of overlapping ranges, the last one applied takes <p>This means that in a case of overlapping ranges, the last one applied takes
@ -1995,7 +2001,7 @@ precedence.</p>
<h2><a name="access">access()</a></h2> <h2><a name="access">access()</a></h2>
<blockquote> <blockquote>
<pre class="literal-block"> <pre class="literal-block">
int access(address_v4 const&amp; addr) const; int access(address const&amp; addr) const;
</pre> </pre>
</blockquote> </blockquote>
<p>Returns the access permissions for the given address (<tt class="docutils literal"><span class="pre">addr</span></tt>). The permission <p>Returns the access permissions for the given address (<tt class="docutils literal"><span class="pre">addr</span></tt>). The permission
@ -2007,13 +2013,16 @@ the current filter.</p>
<h2><a name="export-filter">export_filter()</a></h2> <h2><a name="export-filter">export_filter()</a></h2>
<blockquote> <blockquote>
<pre class="literal-block"> <pre class="literal-block">
std::vector&lt;ip_range&gt; export_filter() const; boost::tuple&lt;std::vector&lt;ip_range&lt;address_v4&gt; &gt;
, std::vector&lt;ip_range&lt;address_v6&gt; &gt; &gt; export_filter() const;
</pre> </pre>
</blockquote> </blockquote>
<p>This function will return the current state of the filter in the minimum number of <p>This function will return the current state of the filter in the minimum number of
ranges possible. They are sorted from ranges in low addresses to high addresses. Each ranges possible. They are sorted from ranges in low addresses to high addresses. Each
entry in the returned vector is a range with the access control specified in its entry in the returned vector is a range with the access control specified in its
<tt class="docutils literal"><span class="pre">flags</span></tt> field.</p> <tt class="docutils literal"><span class="pre">flags</span></tt> field.</p>
<p>The return value is a tuple containing two range-lists. One for IPv4 addresses
and one for IPv6 addresses.</p>
</div> </div>
</div> </div>
<div class="section" id="big-number"> <div class="section" id="big-number">

View File

@ -1935,29 +1935,33 @@ ip_filter
The ``ip_filter`` class is a set of rules that uniquely categorizes all The ``ip_filter`` class is a set of rules that uniquely categorizes all
ip addresses as allowed or disallowed. The default constructor creates ip addresses as allowed or disallowed. The default constructor creates
a single rule that allows all addresses (0.0.0.0 - 255.255.255.255). a single rule that allows all addresses (0.0.0.0 - 255.255.255.255 for
The ``address`` type here is ``asio::ip::address_v4``. It can also be the IPv4 range, and the equivalent range covering all addresses for the
accessed as ``libtorrent::address``. IPv6 range).
:: ::
template <class Addr>
struct ip_range
{
Addr first;
Addr last;
int flags;
};
class ip_filter class ip_filter
{ {
public: public:
enum access_flags { blocked = 1 }; enum access_flags { blocked = 1 };
ip_filter(); ip_filter();
void add_rule(address_v4 first, address_v4 last, int flags); void add_rule(address first, address last, int flags);
int access(address_v4 const& addr) const; int access(address const& addr) const;
struct ip_range typedef boost::tuple<std::vector<ip_range<address_v4> >
{ , std::vector<ip_range<address_v6> > > filter_tuple_t;
address_v4 first;
address_v4 last;
int flags;
};
std::vector<ip_range> export_filter() const; filter_tuple_t export_filter() const;
}; };
@ -1979,13 +1983,16 @@ add_rule()
:: ::
void add_rule(address_v4 first, address_v4 last, int flags); void add_rule(address first, address last, int flags);
Adds a rule to the filter. ``first`` and ``last`` defines a range of Adds a rule to the filter. ``first`` and ``last`` defines a range of
ip addresses that will be marked with the given flags. The ``flags`` ip addresses that will be marked with the given flags. The ``flags``
can currently be 0, which means allowed, or ``ip_filter::blocked``, which can currently be 0, which means allowed, or ``ip_filter::blocked``, which
means disallowed. means disallowed.
precondition:
``first.is_v4() == last.is_v4() && first.is_v6() == last.is_v6()``
postcondition: postcondition:
``access(x) == flags`` for every ``x`` in the range [``first``, ``last``] ``access(x) == flags`` for every ``x`` in the range [``first``, ``last``]
@ -1998,7 +2005,7 @@ access()
:: ::
int access(address_v4 const& addr) const; int access(address const& addr) const;
Returns the access permissions for the given address (``addr``). The permission Returns the access permissions for the given address (``addr``). The permission
can currently be 0 or ``ip_filter::blocked``. The complexity of this operation can currently be 0 or ``ip_filter::blocked``. The complexity of this operation
@ -2011,13 +2018,17 @@ export_filter()
:: ::
std::vector<ip_range> export_filter() const; boost::tuple<std::vector<ip_range<address_v4> >
, std::vector<ip_range<address_v6> > > export_filter() const;
This function will return the current state of the filter in the minimum number of This function will return the current state of the filter in the minimum number of
ranges possible. They are sorted from ranges in low addresses to high addresses. Each ranges possible. They are sorted from ranges in low addresses to high addresses. Each
entry in the returned vector is a range with the access control specified in its entry in the returned vector is a range with the access control specified in its
``flags`` field. ``flags`` field.
The return value is a tuple containing two range-lists. One for IPv4 addresses
and one for IPv6 addresses.
big_number big_number
========== ==========

View File

@ -33,6 +33,19 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef TORRENT_IP_FILTER_HPP #ifndef TORRENT_IP_FILTER_HPP
#define TORRENT_IP_FILTER_HPP #define TORRENT_IP_FILTER_HPP
#ifdef _MSC_VER
#pragma warning(push, 1)
#endif
#include <boost/limits.hpp>
#include <boost/utility.hpp>
#include <boost/tuple/tuple.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
#include <set> #include <set>
@ -47,6 +60,189 @@ inline bool operator<=(address const& lhs
return lhs < rhs || lhs == rhs; return lhs < rhs || lhs == rhs;
} }
template <class Addr>
struct ip_range
{
Addr first;
Addr last;
int flags;
};
namespace detail
{
// this is the generic implementation of
// a filter for a specific address type.
// it works with IPv4 and IPv6
template<class Addr>
class filter_impl
{
public:
filter_impl()
{
typename Addr::bytes_type zero;
std::fill(zero.begin(), zero.end(), 0);
// make the entire ip-range non-blocked
m_access_list.insert(range(Addr(zero), 0));
}
void add_rule(Addr first, Addr last, int flags)
{
using boost::next;
using boost::prior;
assert(!m_access_list.empty());
assert(first < last || first == last);
typename range_t::iterator i = m_access_list.upper_bound(first);
typename range_t::iterator j = m_access_list.upper_bound(last);
if (i != m_access_list.begin()) --i;
assert(j != m_access_list.begin());
assert(j != i);
int first_access = i->access;
int last_access = prior(j)->access;
if (i->start != first && first_access != flags)
{
i = m_access_list.insert(i, range(first, flags));
}
else if (i != m_access_list.begin() && prior(i)->access == flags)
{
--i;
first_access = i->access;
}
assert(!m_access_list.empty());
assert(i != m_access_list.end());
if (i != j) m_access_list.erase(next(i), j);
if (i->start == first)
{
// we can do this const-cast because we know that the new
// start address will keep the set correctly ordered
const_cast<Addr&>(i->start) = first;
const_cast<int&>(i->access) = flags;
}
else if (first_access != flags)
{
m_access_list.insert(i, range(first, flags));
}
if ((j != m_access_list.end()
&& minus_one(j->start) != last)
|| (j == m_access_list.end()
&& last != max_addr()))
{
assert(j == m_access_list.end() || last < minus_one(j->start));
if (last_access != flags)
j = m_access_list.insert(j, range(plus_one(last), last_access));
}
if (j != m_access_list.end() && j->access == flags) m_access_list.erase(j);
assert(!m_access_list.empty());
}
int access(Addr const& addr) const
{
assert(!m_access_list.empty());
typename range_t::const_iterator i = m_access_list.upper_bound(addr);
if (i != m_access_list.begin()) --i;
assert(i != m_access_list.end());
assert(i->start <= addr && (boost::next(i) == m_access_list.end()
|| addr < boost::next(i)->start));
return i->access;
}
std::vector<ip_range<Addr> > export_filter() const
{
std::vector<ip_range<Addr> > ret;
ret.reserve(m_access_list.size());
for (typename range_t::const_iterator i = m_access_list.begin()
, end(m_access_list.end()); i != end;)
{
ip_range<Addr> r;
r.first = i->start;
r.flags = i->access;
++i;
if (i == end)
r.last = max_addr();
else
r.last = minus_one(i->start);
ret.push_back(r);
}
return ret;
}
private:
Addr plus_one(Addr const& a) const
{
typename Addr::bytes_type tmp(a.to_bytes());
typedef typename Addr::bytes_type::reverse_iterator iter;
for (iter i = tmp.rbegin()
, end(tmp.rend()); i != end; ++i)
{
if (*i < std::numeric_limits<typename iter::value_type>::max())
{
*i += 1;
break;
}
*i = 0;
}
return Addr(tmp);
}
Addr minus_one(Addr const& a) const
{
typename Addr::bytes_type tmp(a.to_bytes());
typedef typename Addr::bytes_type::reverse_iterator iter;
for (iter i = tmp.rbegin()
, end(tmp.rend()); i != end; ++i)
{
if (*i > 0)
{
*i -= 1;
break;
}
*i = std::numeric_limits<typename iter::value_type>::max();
}
return Addr(tmp);
}
Addr max_addr() const
{
typename Addr::bytes_type tmp;
std::fill(tmp.begin(), tmp.end()
, std::numeric_limits<typename Addr::bytes_type::value_type>::max());
return Addr(tmp);
}
struct range
{
range(Addr addr, int access = 0): start(addr), access(access) {}
bool operator<(range const& r) const
{ return start < r.start; }
bool operator<(Addr const& a) const
{ return start < a; }
Addr start;
// the end of the range is implicit
// and given by the next entry in the set
int access;
};
typedef std::set<range> range_t;
range_t m_access_list;
};
}
class TORRENT_EXPORT ip_filter class TORRENT_EXPORT ip_filter
{ {
public: public:
@ -55,38 +251,23 @@ public:
{ {
blocked = 1 blocked = 1
}; };
ip_filter();
void add_rule(address_v4 first, address_v4 last, int flags);
int access(address_v4 const& addr) const;
struct ip_range // both addresses MUST be of the same type (i.e. both must
{ // be either IPv4 or both must be IPv6)
address_v4 first; void add_rule(address first, address last, int flags);
address_v4 last; int access(address const& addr) const;
int flags;
}; typedef boost::tuple<std::vector<ip_range<address_v4> >
, std::vector<ip_range<address_v6> > > filter_tuple_t;
std::vector<ip_range> export_filter() const;
filter_tuple_t export_filter() const;
// void print() const; // void print() const;
private: private:
struct range
{
range(address_v4 addr, int access = 0): start(addr), access(access) {}
bool operator<(range const& r) const
{ return start < r.start; }
bool operator<(address const& a) const
{ return start < a; }
address_v4 start;
// the end of the range is implicit
// and given by the next entry in the set
int access;
};
typedef std::set<range> range_t; detail::filter_impl<address_v4> m_filter4;
range_t m_access_list; detail::filter_impl<address_v6> m_filter6;
}; };
} }

View File

@ -37,103 +37,37 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
void ip_filter::add_rule(address first, address last, int flags)
ip_filter::ip_filter()
{ {
// make the entire ip-range non-blocked if (first.is_v4())
m_access_list.insert(range(address_v4(0UL), 0)); {
assert(last.is_v4());
m_filter4.add_rule(first.to_v4(), last.to_v4(), flags);
}
else if (first.is_v6())
{
assert(last.is_v6());
m_filter6.add_rule(first.to_v6(), last.to_v6(), flags);
}
else
assert(false);
} }
void ip_filter::add_rule(address_v4 first, address_v4 last, int flags) int ip_filter::access(address const& addr) const
{ {
using boost::next; if (addr.is_v4())
using boost::prior; return m_filter4.access(addr.to_v4());
else if (addr.is_v6())
assert(!m_access_list.empty()); return m_filter6.access(addr.to_v6());
assert(first <= last); else
range_t::iterator i = m_access_list.upper_bound(first); assert(false);
range_t::iterator j = m_access_list.upper_bound(last);
if (i != m_access_list.begin()) --i;
assert(j != m_access_list.begin());
assert(j != i);
int first_access = i->access;
int last_access = prior(j)->access;
if (i->start != first && first_access != flags)
{
i = m_access_list.insert(i, range(first, flags));
}
else if (i != m_access_list.begin() && prior(i)->access == flags)
{
--i;
first_access = i->access;
}
assert(!m_access_list.empty());
assert(i != m_access_list.end());
if (i != j)
m_access_list.erase(next(i), j);
if (i->start == first)
{
// we can do this const-cast because we know that the new
// start address will keep the set correctly ordered
const_cast<address_v4&>(i->start) = first;
const_cast<int&>(i->access) = flags;
}
else if (first_access != flags)
{
m_access_list.insert(i, range(first, flags));
}
if ((j != m_access_list.end() && j->start.to_ulong() - 1 != last.to_ulong())
|| (j == m_access_list.end() && last.to_ulong() != 0xffffffff))
{
assert(j == m_access_list.end() || last.to_ulong() < j->start.to_ulong() - 1);
if (last_access != flags)
j = m_access_list.insert(j, range(address_v4(last.to_ulong() + 1), last_access));
}
if (j != m_access_list.end() && j->access == flags) m_access_list.erase(j);
assert(!m_access_list.empty());
} }
int ip_filter::access(address_v4 const& addr) const ip_filter::filter_tuple_t ip_filter::export_filter() const
{ {
assert(!m_access_list.empty()); return boost::make_tuple(m_filter4.export_filter()
range_t::const_iterator i = m_access_list.upper_bound(addr); , m_filter6.export_filter());
if (i != m_access_list.begin()) --i;
assert(i != m_access_list.end());
assert(i->start <= addr && (boost::next(i) == m_access_list.end()
|| addr < boost::next(i)->start));
return i->access;
} }
std::vector<ip_filter::ip_range> ip_filter::export_filter() const
{
std::vector<ip_range> ret;
ret.reserve(m_access_list.size());
for (range_t::const_iterator i = m_access_list.begin()
, end(m_access_list.end()); i != end;)
{
ip_range r;
r.first = i->start;
r.flags = i->access;
++i;
if (i == end)
r.last = address_v4(0xffffffff);
else
r.last = address_v4(i->start.to_ulong() - 1);
ret.push_back(r);
}
return ret;
}
/* /*
void ip_filter::print() const void ip_filter::print() const

View File

@ -3,24 +3,35 @@
#include "test.hpp" #include "test.hpp"
/*
Currently this test only tests that the filter can handle
IPv4 addresses. Maybe it should be extended to IPv6 as well,
but the actual code is just a template, so it is probably
pretty safe to assume that as long as it works for IPv4 it
also works for IPv6.
*/
using namespace libtorrent; using namespace libtorrent;
bool compare(ip_filter::ip_range const& lhs template <class Addr>
, ip_filter::ip_range const& rhs) bool compare(ip_range<Addr> const& lhs
, ip_range<Addr> const& rhs)
{ {
return lhs.first == rhs.first return lhs.first == rhs.first
&& lhs.last == rhs.last && lhs.last == rhs.last
&& lhs.flags == rhs.flags; && lhs.flags == rhs.flags;
} }
void test_rules_invariant(std::vector<ip_filter::ip_range> const& r, ip_filter const& f) void test_rules_invariant(std::vector<ip_range<address_v4> > const& r, ip_filter const& f)
{ {
typedef std::vector<ip_filter::ip_range>::const_iterator iterator; typedef std::vector<ip_range<address_v4> >::const_iterator iterator;
TEST_CHECK(!r.empty()); TEST_CHECK(!r.empty());
if (r.empty()) return; if (r.empty()) return;
TEST_CHECK(r.front().first == address_v4::from_string("0.0.0.0")); TEST_CHECK(r.front().first == address::from_string("0.0.0.0"));
TEST_CHECK(r.back().last == address_v4::from_string("255.255.255.255")); TEST_CHECK(r.back().last == address::from_string("255.255.255.255"));
iterator i = r.begin(); iterator i = r.begin();
iterator j = boost::next(i); iterator j = boost::next(i);
@ -36,10 +47,11 @@ void test_rules_invariant(std::vector<ip_filter::ip_range> const& r, ip_filter c
int test_main() int test_main()
{ {
using namespace libtorrent; using namespace libtorrent;
std::vector<ip_filter::ip_range> range;
std::vector<ip_range<address_v4> > range;
// **** test joining of ranges at the end **** // **** test joining of ranges at the end ****
ip_filter::ip_range expected1[] = ip_range<address_v4> expected1[] =
{ {
{address_v4::from_string("0.0.0.0"), address_v4::from_string("0.255.255.255"), 0} {address_v4::from_string("0.0.0.0"), address_v4::from_string("0.255.255.255"), 0}
, {address_v4::from_string("1.0.0.0"), address_v4::from_string("3.0.0.0"), ip_filter::blocked} , {address_v4::from_string("1.0.0.0"), address_v4::from_string("3.0.0.0"), ip_filter::blocked}
@ -48,28 +60,30 @@ int test_main()
{ {
ip_filter f; ip_filter f;
f.add_rule(address_v4::from_string("1.0.0.0"), address_v4::from_string("2.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("1.0.0.0"), address::from_string("2.0.0.0"), ip_filter::blocked);
f.add_rule(address_v4::from_string("2.0.0.1"), address_v4::from_string("3.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("2.0.0.1"), address::from_string("3.0.0.0"), ip_filter::blocked);
range = f.export_filter(); range = boost::get<0>(f.export_filter());
test_rules_invariant(range, f); test_rules_invariant(range, f);
TEST_CHECK(range.size() == 3); TEST_CHECK(range.size() == 3);
TEST_CHECK(std::equal(range.begin(), range.end(), expected1, &compare)); TEST_CHECK(std::equal(range.begin(), range.end(), expected1, &compare<address_v4>));
} }
// **** test joining of ranges at the start **** // **** test joining of ranges at the start ****
{ {
ip_filter f; ip_filter f;
f.add_rule(address_v4::from_string("2.0.0.1"), address_v4::from_string("3.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("2.0.0.1"), address::from_string("3.0.0.0"), ip_filter::blocked);
f.add_rule(address_v4::from_string("1.0.0.0"), address_v4::from_string("2.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("1.0.0.0"), address::from_string("2.0.0.0"), ip_filter::blocked);
range = f.export_filter(); range = boost::get<0>(f.export_filter());
test_rules_invariant(range, f); test_rules_invariant(range, f);
TEST_CHECK(range.size() == 3); TEST_CHECK(range.size() == 3);
TEST_CHECK(std::equal(range.begin(), range.end(), expected1, &compare)); TEST_CHECK(std::equal(range.begin(), range.end(), expected1, &compare<address_v4>));
} }
@ -77,14 +91,15 @@ int test_main()
{ {
ip_filter f; ip_filter f;
f.add_rule(address_v4::from_string("2.0.0.1"), address_v4::from_string("3.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("2.0.0.1"), address::from_string("3.0.0.0"), ip_filter::blocked);
f.add_rule(address_v4::from_string("1.0.0.0"), address_v4::from_string("2.4.0.0"), ip_filter::blocked); f.add_rule(address::from_string("1.0.0.0"), address::from_string("2.4.0.0"), ip_filter::blocked);
range = f.export_filter(); range = boost::get<0>(f.export_filter());
test_rules_invariant(range, f); test_rules_invariant(range, f);
TEST_CHECK(range.size() == 3); TEST_CHECK(range.size() == 3);
TEST_CHECK(std::equal(range.begin(), range.end(), expected1, &compare)); TEST_CHECK(std::equal(range.begin(), range.end(), expected1, &compare<address_v4>));
} }
@ -92,14 +107,15 @@ int test_main()
{ {
ip_filter f; ip_filter f;
f.add_rule(address_v4::from_string("1.0.0.0"), address_v4::from_string("2.4.0.0"), ip_filter::blocked); f.add_rule(address::from_string("1.0.0.0"), address::from_string("2.4.0.0"), ip_filter::blocked);
f.add_rule(address_v4::from_string("2.0.0.1"), address_v4::from_string("3.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("2.0.0.1"), address::from_string("3.0.0.0"), ip_filter::blocked);
range = f.export_filter(); range = boost::get<0>(f.export_filter());
test_rules_invariant(range, f); test_rules_invariant(range, f);
TEST_CHECK(range.size() == 3); TEST_CHECK(range.size() == 3);
TEST_CHECK(std::equal(range.begin(), range.end(), expected1, &compare)); TEST_CHECK(std::equal(range.begin(), range.end(), expected1, &compare<address_v4>));
} }
@ -107,50 +123,52 @@ int test_main()
{ {
ip_filter f; ip_filter f;
f.add_rule(address_v4::from_string("1.0.0.0"), address_v4::from_string("2.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("1.0.0.0"), address::from_string("2.0.0.0"), ip_filter::blocked);
f.add_rule(address_v4::from_string("3.0.0.0"), address_v4::from_string("4.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("3.0.0.0"), address::from_string("4.0.0.0"), ip_filter::blocked);
f.add_rule(address_v4::from_string("5.0.0.0"), address_v4::from_string("6.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("5.0.0.0"), address::from_string("6.0.0.0"), ip_filter::blocked);
f.add_rule(address_v4::from_string("7.0.0.0"), address_v4::from_string("8.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("7.0.0.0"), address::from_string("8.0.0.0"), ip_filter::blocked);
f.add_rule(address_v4::from_string("1.0.1.0"), address_v4::from_string("9.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("1.0.1.0"), address::from_string("9.0.0.0"), ip_filter::blocked);
range = f.export_filter(); range = boost::get<0>(f.export_filter());
test_rules_invariant(range, f); test_rules_invariant(range, f);
TEST_CHECK(range.size() == 3); TEST_CHECK(range.size() == 3);
ip_filter::ip_range expected[] = ip_range<address_v4> expected[] =
{ {
{address_v4::from_string("0.0.0.0"), address_v4::from_string("0.255.255.255"), 0} {address_v4::from_string("0.0.0.0"), address_v4::from_string("0.255.255.255"), 0}
, {address_v4::from_string("1.0.0.0"), address_v4::from_string("9.0.0.0"), ip_filter::blocked} , {address_v4::from_string("1.0.0.0"), address_v4::from_string("9.0.0.0"), ip_filter::blocked}
, {address_v4::from_string("9.0.0.1"), address_v4::from_string("255.255.255.255"), 0} , {address_v4::from_string("9.0.0.1"), address_v4::from_string("255.255.255.255"), 0}
}; };
TEST_CHECK(std::equal(range.begin(), range.end(), expected, &compare)); TEST_CHECK(std::equal(range.begin(), range.end(), expected, &compare<address_v4>));
} }
// **** test joining of multiple overlapping ranges 2 **** // **** test joining of multiple overlapping ranges 2 ****
{ {
ip_filter f; ip_filter f;
f.add_rule(address_v4::from_string("1.0.0.0"), address_v4::from_string("2.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("1.0.0.0"), address::from_string("2.0.0.0"), ip_filter::blocked);
f.add_rule(address_v4::from_string("3.0.0.0"), address_v4::from_string("4.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("3.0.0.0"), address::from_string("4.0.0.0"), ip_filter::blocked);
f.add_rule(address_v4::from_string("5.0.0.0"), address_v4::from_string("6.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("5.0.0.0"), address::from_string("6.0.0.0"), ip_filter::blocked);
f.add_rule(address_v4::from_string("7.0.0.0"), address_v4::from_string("8.0.0.0"), ip_filter::blocked); f.add_rule(address::from_string("7.0.0.0"), address::from_string("8.0.0.0"), ip_filter::blocked);
f.add_rule(address_v4::from_string("0.0.1.0"), address_v4::from_string("7.0.4.0"), ip_filter::blocked); f.add_rule(address::from_string("0.0.1.0"), address::from_string("7.0.4.0"), ip_filter::blocked);
range = f.export_filter(); range = boost::get<0>(f.export_filter());
test_rules_invariant(range, f); test_rules_invariant(range, f);
TEST_CHECK(range.size() == 3); TEST_CHECK(range.size() == 3);
ip_filter::ip_range expected[] = ip_range<address_v4> expected[] =
{ {
{address_v4::from_string("0.0.0.0"), address_v4::from_string("0.0.0.255"), 0} {address_v4::from_string("0.0.0.0"), address_v4::from_string("0.0.0.255"), 0}
, {address_v4::from_string("0.0.1.0"), address_v4::from_string("8.0.0.0"), ip_filter::blocked} , {address_v4::from_string("0.0.1.0"), address_v4::from_string("8.0.0.0"), ip_filter::blocked}
, {address_v4::from_string("8.0.0.1"), address_v4::from_string("255.255.255.255"), 0} , {address_v4::from_string("8.0.0.1"), address_v4::from_string("255.255.255.255"), 0}
}; };
TEST_CHECK(std::equal(range.begin(), range.end(), expected, &compare)); TEST_CHECK(std::equal(range.begin(), range.end(), expected, &compare<address_v4>));
} }
return 0; return 0;