initial support for GeoIP (only AS mappings for now)

This commit is contained in:
Arvid Norberg 2008-04-05 04:53:22 +00:00
parent 0fcb204128
commit 57d75e120a
20 changed files with 2336 additions and 623 deletions

13
Jamfile
View File

@ -49,6 +49,11 @@ rule linking ( properties * )
}
}
if <geoip>shared in $(properties)
{
result += <library>GeoIP ;
}
# socket functions on windows require winsock libraries
if <target-os>windows in $(properties)
|| <target-os>cygwin in $(properties)
@ -120,6 +125,11 @@ rule building ( properties * )
result += <source>src/assert.cpp ;
}
if <geoip>static in $(properties)
{
result += <source>src/GeoIP.c ;
}
if <openssl>off in $(properties)
{
result += <source>src/sha1.cpp ;
@ -149,6 +159,9 @@ rule building ( properties * )
return $(result) ;
}
feature geoip : off static shared : composite propagated link-incompatible ;
feature.compose <geoip>off : <define>TORRENT_DISABLE_GEO_IP ;
feature bandwidth-limit-logging : off on : composite propagated link-incompatible ;
feature.compose <bandwidth-limit-logging>on : <define>TORRENT_VERBOSE_BANDWIDTH_LIMIT ;

View File

@ -68,6 +68,10 @@ void bind_peer_info()
.def_readonly("num_hashfails", &peer_info::num_hashfails)
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
.add_property("country", get_country)
#endif
#ifndef TORRENT_DISABLE_GEO_IP
.def_readonly("inet_as_name", &peer_info::inet_as_name)
.def_readonly("inet_as", &peer_info::inet_as)
#endif
.def_readonly("load_balancing", &peer_info::load_balancing)
.def_readonly("download_queue_length", &peer_info::download_queue_length)

View File

@ -250,6 +250,11 @@ void bind_session()
.def("set_pe_settings", allow_threads(&session::set_pe_settings), session_set_pe_settings_doc)
.def("get_pe_settings", allow_threads(&session::get_pe_settings), return_value_policy<copy_const_reference>())
#endif
#ifndef TORRENT_DISABLE_GEO_IP
.def("load_asnum_db", allow_threads(&session::load_asnum_db))
#endif
.def("load_state", allow_threads(&session::load_state))
.def("state", allow_threads(&session::state))
.def(
"set_severity_level", allow_threads(&session::set_severity_level)
, session_set_severity_level_doc

View File

@ -240,6 +240,18 @@ with the libtorrent package.</li>
</ul>
</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">geoip</span></tt></td>
<td><ul class="first last simple">
<li><tt class="docutils literal"><span class="pre">off</span></tt> - geo ip lookups disabled</li>
<li><tt class="docutils literal"><span class="pre">static</span></tt> - <a class="reference external" href="http://www.maxmind.com/app/api">MaxMind</a> geo ip lookup code linked
in statically. Note that this code is under
LGPL license.</li>
<li><tt class="docutils literal"><span class="pre">shared</span></tt> - The <a class="reference external" href="http://www.maxmind.com/app/api">MaxMind</a> geo ip lookup library
is expected to be installed on the system and
it will be used.</li>
</ul>
</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">upnp-logging</span></tt></td>
<td><ul class="first last simple">
<li><tt class="docutils literal"><span class="pre">off</span></tt> - default. Does not log UPnP traffic.</li>
@ -349,7 +361,7 @@ character-set=ansi character-set=unicode
<h2>building with autotools</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
unix/linux systems comes with these preinstalled.</p>
<p>The prerequisites for building libtorrent is boost.thread, boost.date_time
<p>The prerequisites for building libtorrent are boost.thread, boost.date_time
and boost.filesystem. Those are the <em>compiled</em> boost libraries needed. The
headers-only libraries needed include (but is not necessarily limited to)
boost.bind, boost.ref, boost.multi_index, boost.optional, boost.lexical_cast,
@ -505,6 +517,11 @@ structs and class layouts and sizes.</td>
events, such as tracker announces and incoming
connections (as well as blocked connections).</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">TORRENT_DISABLE_GEO_IP</span></tt></td>
<td>This is defined by default by the Jamfile. It
disables the GeoIP features, and avoids linking
against LGPL:ed code.</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">TORRENT_VERBOSE_LOGGING</span></tt></td>
<td>If you define this macro, every peer connection
will log its traffic to a log file as well as

View File

@ -235,6 +235,14 @@ Build features:
| | * ``shipped`` - links against the zlib bundled |
| | with the libtorrent package. |
+------------------------+----------------------------------------------------+
| ``geoip`` | * ``off`` - geo ip lookups disabled |
| | * ``static`` - MaxMind_ geo ip lookup code linked |
| | in statically. Note that this code is under |
| | LGPL license. |
| | * ``shared`` - The MaxMind_ geo ip lookup library |
| | is expected to be installed on the system and |
| | it will be used. |
+------------------------+----------------------------------------------------+
| ``upnp-logging`` | * ``off`` - default. Does not log UPnP traffic. |
| | * ``on`` - creates "upnp.log" with the messages |
| | sent to and received from UPnP devices. |
@ -290,6 +298,8 @@ Build features:
| | * ``off`` - default for release builds. |
+------------------------+----------------------------------------------------+
.. _MaxMind: http://www.maxmind.com/app/api
The ``variant`` feature is *implicit*, which means you don't need to specify
the name of the feature, just the value.
@ -320,7 +330,7 @@ building with autotools
First of all, you need to install ``automake`` and ``autoconf``. Many
unix/linux systems comes with these preinstalled.
The prerequisites for building libtorrent is boost.thread, boost.date_time
The prerequisites for building libtorrent are 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,
@ -483,6 +493,10 @@ defines you can use to control the build.
| | events, such as tracker announces and incoming |
| | connections (as well as blocked connections). |
+---------------------------------------+-------------------------------------------------+
| ``TORRENT_DISABLE_GEO_IP`` | This is defined by default by the Jamfile. It |
| | disables the GeoIP features, and avoids linking |
| | against LGPL:ed code. |
+---------------------------------------+-------------------------------------------------+
| ``TORRENT_VERBOSE_LOGGING`` | If you define this macro, every peer connection |
| | will log its traffic to a log file as well as |
| | the session log. |

File diff suppressed because it is too large Load Diff

View File

@ -130,6 +130,11 @@ The ``session`` class has the following synopsis::
int num_uploads() const;
int num_connections() const;
bool load_asnum_db(char const* file);
void load_state(entry const& ses_state);
entry state() const;
void set_ip_filter(ip_filter const& f);
session_status status() const;
@ -404,7 +409,31 @@ their turn to get connected.
``max_half_open_connections()`` returns the set limit. This limit defaults
to 8 on windows.
load_asnum_db()
---------------
::
bool load_asnum_db(char const* file);
This function is not available if ``TORRENT_DISABLE_GEO_IP`` is defined. This
expects a path to the `MaxMind ASN database`_. This will be used to look up
which AS peers belong to.
.. _`MaxMind ASN database`: http://www.maxmind.com/app/asnum
load_state() state()
--------------------
::
void load_state(entry const& ses_state);
entry state() const;
These functions loads and save session state. Currently, the only state
that's stored is peak download rates for ASes. This map is used to
determine which order to connect to peers.
set_ip_filter()
---------------
@ -2336,6 +2365,9 @@ It contains the following fields::
char country[2];
std::string inet_as_name;
int inet_as;
size_type load_balancing;
int download_queue_length;
@ -2523,6 +2555,11 @@ remain set to 0 unless the torrent is set to resolve countries, see `resolve_cou
__ http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html
``inet_as_name`` is the name of the AS this peer is located in. This might be
an empty string if there is no name in the geo ip database.
``inet_as`` is the AS number the peer is located in.
``load_balancing`` is a measurement of the balancing of free download (that we get)
and free upload that we give. Every peer gets a certain amount of free upload, but
this member says how much *extra* free upload this peer has got. If it is a negative

View File

@ -16,18 +16,18 @@
<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>
<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="contents topic" id="table-of-contents">
<p class="topic-title first"><a name="table-of-contents">Table of contents</a></p>
<p class="topic-title first">Table of contents</p>
<ul class="simple">
<li><a class="reference" href="#building" id="id1" name="id1">building</a></li>
<li><a class="reference" href="#using" id="id2" name="id2">using</a></li>
<li><a class="reference internal" href="#building" id="id1">building</a></li>
<li><a class="reference internal" href="#using-libtorrent-in-python" id="id2">using libtorrent in python</a></li>
</ul>
</div>
<div class="section">
<h1><a id="building" name="building">building</a></h1>
<div class="section" id="building">
<h1>building</h1>
<p>Building the libtorrent python bindings will produce a shared library (DLL)
which is a python module that can be imported in a python program.</p>
<p>The only supported build system for the bindings are currently boost build. To
@ -45,10 +45,10 @@ using python : 2.3 : /usr ;
</pre>
<p>The bindings require <em>at least</em> python version 2.2.</p>
<p>For more information on how to install and set up boost-build, see the
<a class="reference" href="building.html#step-2-setup-bbv2">building libtorrent</a> section.</p>
<a class="reference external" href="building.html#step-2-setup-bbv2">building libtorrent</a> section.</p>
<p>Once you have boost-build set up, you cd to the <tt class="docutils literal"><span class="pre">bindings/python</span></tt>
directory and invoke <tt class="docutils literal"><span class="pre">bjam</span></tt> with the apropriate settings. For the available
build variants, see <a class="reference" href="building.html#step-3-building-libtorrent">libtorrent build options</a>.</p>
build variants, see <a class="reference external" href="building.html#step-3-building-libtorrent">libtorrent build options</a>.</p>
<p>For example:</p>
<pre class="literal-block">
$ bjam dht-support=on boost=source release link=static
@ -58,10 +58,26 @@ $ bjam dht-support=on boost=source release link=static
bin/darwin-4.0/release/dht-support-on/link-static/logging-none/threading-multi/libtorrent.so
</pre>
</div>
<div class="section">
<h1><a id="using" name="using">using</a></h1>
<div class="section" id="using-libtorrent-in-python">
<h1>using libtorrent in python</h1>
<p>The python interface is nearly identical to the C++ interface. Please refer to
the <a class="reference" href="manual.html">main library reference</a>.</p>
the <a class="reference external" href="manual.html">main library reference</a>. The main differences are:</p>
<dl class="docutils">
<dt>asio::tcp::endpoint</dt>
<dd>The endpoint type is represented as a tuple of a string (as the address) and an int for
the port number. E.g. <tt class="docutils literal"><span class="pre">('127.0.0.1',</span> <span class="pre">6881)</span></tt> represents the localhost port 6881.</dd>
<dt>libtorrent::time_duration</dt>
<dd>The time duration is represented as a number of seconds in a regular integer.</dd>
</dl>
<p>The following functions takes a reference to a container that is filled with
entries by the function. The python equivalent of these functions instead returns
a list of entries.</p>
<ul class="simple">
<li>torrent_handle::get_peer_info</li>
<li>torrent_handle::file_progress</li>
<li>torrent_handle::get_download_queue</li>
<li>torrent_handle::piece_availability</li>
</ul>
<p>For an example python program, see <tt class="docutils literal"><span class="pre">client.py</span></tt> in the <tt class="docutils literal"><span class="pre">bindings/python</span></tt>
directory.</p>
<p>A very simple example usage of the module would be something like this:</p>

View File

@ -152,6 +152,21 @@ void clear_home()
#endif
bool print_peers = false;
bool print_log = false;
bool print_downloads = false;
bool print_piece_bar = false;
bool print_file_progress = false;
bool sequential_download = false;
bool print_ip = true;
bool print_as = false;
bool print_timers = false;
bool print_block = false;
bool print_peer_rate = false;
bool print_fails = false;
bool print_send_bufs = true;
char const* esc(char const* code)
{
#ifdef ANSI_TERMINAL_COLORS
@ -327,11 +342,21 @@ int peer_index(libtorrent::tcp::endpoint addr, std::vector<libtorrent::peer_info
void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const& peers)
{
using namespace libtorrent;
out << "IP down (total) up (total) sent-req recv flags source fail hshf sndb inactive wait disk quota rtt block-progress "
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
"country "
if (print_ip) out << "IP ";
#ifndef TORRENT_DISABLE_GEO_IP
if (print_as) out << "AS ";
#endif
"peer-rate client \n";
out << "down (total | peak ) up (total | peak ) sent-req recv flags source ";
if (print_fails) out << "fail hshf ";
if (print_send_bufs) out << "sndb quota ";
if (print_timers) out << "inactive wait ";
out << "disk rtt ";
if (print_block) out << "block-progress ";
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
out << "country ";
#endif
if (print_peer_rate) out << "peer-rate ";
out << "client \n";
for (std::vector<peer_info>::const_iterator i = peers.begin();
i != peers.end(); ++i)
@ -340,15 +365,30 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
continue;
out.fill(' ');
std::stringstream ip;
ip << i->ip.address().to_string() << ":" << i->ip.port();
out.width(22);
out << ip.str() << " ";
if (print_ip)
{
std::stringstream ip;
ip << i->ip.address().to_string() << ":" << i->ip.port();
out.width(22);
out << ip.str() << " ";
}
#ifndef TORRENT_DISABLE_GEO_IP
if (print_as)
{
std::string as_name = i->inet_as_name;
if (as_name.size() > 42) as_name.resize(42);
out.width(42);
out << as_name << " ";
}
#endif
out.width(2);
out << esc("32") << (i->down_speed > 0 ? add_suffix(i->down_speed) + "/s " : " ")
<< "(" << add_suffix(i->total_download) << ") " << esc("0")
<< "(" << (i->total_download > 0 ? add_suffix(i->total_download) : " ") << "|"
<< (i->download_rate_peak > 0 ? add_suffix(i->download_rate_peak) + "/s" : " ") << ") " << esc("0")
<< esc("31") << (i->up_speed > 0 ? add_suffix(i->up_speed) + "/s ": " ")
<< "(" << add_suffix(i->total_upload) << ") " << esc("0")
<< "(" << (i->total_upload > 0 ? add_suffix(i->total_upload) : " ") << "|"
<< (i->upload_rate_peak > 0 ? add_suffix(i->upload_rate_peak) + "/s" : " ") << ") " << esc("0")
<< to_string(i->download_queue_length, 3) << " ("
<< to_string(i->target_dl_queue_length, 3) << ") "
<< to_string(i->upload_queue_length, 3) << " "
@ -378,24 +418,36 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
<< ((i->source & peer_info::pex)?"P":"_")
<< ((i->source & peer_info::dht)?"D":"_")
<< ((i->source & peer_info::lsd)?"L":"_")
<< ((i->source & peer_info::resume_data)?"R":"_") << " "
<< to_string(i->failcount, 2) << " "
<< to_string(i->num_hashfails, 2) << " "
<< to_string(i->used_send_buffer, 6) << " ("<< add_suffix(i->send_buffer_size) << ") "
<< to_string(total_seconds(i->last_active), 8) << " "
<< to_string(total_seconds(i->last_request), 4) << " "
<< add_suffix(i->pending_disk_bytes) << " "
<< to_string(i->send_quota, 5) << " "
<< ((i->source & peer_info::resume_data)?"R":"_") << " ";
if (print_fails)
{
out << to_string(i->failcount, 3) << " "
<< to_string(i->num_hashfails, 3) << " ";
}
if (print_send_bufs)
{
out << to_string(i->used_send_buffer, 6) << " ("<< add_suffix(i->send_buffer_size) << ") "
<< to_string(i->send_quota, 5) << " ";
}
if (print_timers)
{
out << to_string(total_seconds(i->last_active), 8) << " "
<< to_string(total_seconds(i->last_request), 4) << " ";
}
out << add_suffix(i->pending_disk_bytes) << " "
<< to_string(i->rtt, 4) << " ";
if (i->downloading_piece_index >= 0)
if (print_block)
{
out << progress_bar(
i->downloading_progress / float(i->downloading_total), 14);
}
else
{
out << progress_bar(0.f, 14);
if (i->downloading_piece_index >= 0)
{
out << progress_bar(
i->downloading_progress / float(i->downloading_total), 14);
}
else
{
out << progress_bar(0.f, 14);
}
}
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
@ -408,7 +460,8 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
out << " " << i->country[0] << i->country[1];
}
#endif
out << " " << (i->remote_dl_rate > 0 ? add_suffix(i->remote_dl_rate) + "/s ": " ") << " ";
if (print_peer_rate) out << " " << (i->remote_dl_rate > 0 ? add_suffix(i->remote_dl_rate) + "/s ": " ");
out << " ";
if (i->flags & peer_info::handshake)
{
@ -754,6 +807,9 @@ int main(int ac, char* av[])
// monitor when they're not in the directory anymore.
handles_t handles;
session ses;
#ifndef TORRENT_DISABLE_GEO_IP
ses.load_asnum_db("GeoIPASNum.dat");
#endif
// UPnP port mapping
ses.start_upnp();
// NAT-PMP port mapping
@ -785,6 +841,17 @@ int main(int ac, char* av[])
else
ses.set_severity_level(alert::info);
try
{
boost::filesystem::ifstream ses_state_file(".ses_state"
, std::ios_base::binary);
ses_state_file.unsetf(std::ios_base::skipws);
ses.load_state(bdecode(
std::istream_iterator<char>(ses_state_file)
, std::istream_iterator<char>()));
}
catch (std::exception&) {}
#ifndef TORRENT_DISABLE_DHT
settings.use_dht_as_fallback = false;
@ -912,14 +979,6 @@ int main(int ac, char* av[])
std::vector<peer_info> peers;
std::vector<partial_piece_info> queue;
bool print_peers = false;
bool print_cache = false;
bool print_log = false;
bool print_downloads = false;
bool print_piece_bar = false;
bool print_file_progress = false;
bool sequential_download = false;
for (;;)
{
char c;
@ -979,12 +1038,20 @@ int main(int ac, char* av[])
, bind(&handles_t::value_type::second, _1)));
}
// toggle displays
if (c == 'i') print_peers = !print_peers;
if (c == 'c') print_cache = !print_cache;
if (c == 'l') print_log = !print_log;
if (c == 'd') print_downloads = !print_downloads;
if (c == 'f') print_file_progress = !print_file_progress;
if (c == 'a') print_piece_bar = !print_piece_bar;
// toggle columns
if (c == '1') print_ip = !print_ip;
if (c == '2') print_as = !print_as;
if (c == '3') print_timers = !print_timers;
if (c == '4') print_block = !print_block;
if (c == '5') print_peer_rate = !print_peer_rate;
if (c == '6') print_fails = !print_fails;
if (c == '7') print_send_bufs = !print_send_bufs;
}
int terminal_width = 80;
@ -1260,13 +1327,17 @@ int main(int ac, char* av[])
" cache size: " << add_suffix(cs.cache_size * 16 * 1024)
<< " (" << add_suffix(cs.read_cache_size * 16 * 1024) << ")"
" ====" << std::endl;
out << "[q] quit [i] toggle peers [d] toggle downloading pieces [p] pause all "
"[u] unpause all [a] toggle piece bar [s] toggle download sequential [f] toggle files\n"
"[1] toggle IP [2] toggle AS [3] toggle timers [4] toggle block progress "
"[5] toggle peer rate [6] toggle failures [7] toggle send buffers";
if (print_log)
{
for (std::deque<std::string>::iterator i = events.begin();
i != events.end(); ++i)
{
out << *i << "\n";
out << "\n" << *i;
}
}
@ -1283,6 +1354,14 @@ int main(int ac, char* av[])
}
}
{
entry session_state = ses.state();
boost::filesystem::ofstream out(".ses_state"
, std::ios_base::binary);
out.unsetf(std::ios_base::skipws);
bencode(std::ostream_iterator<char>(out), session_state);
}
#ifndef TORRENT_DISABLE_DHT
dht_state = ses.dht_state();
boost::filesystem::ofstream out(".dht_state"

184
include/libtorrent/GeoIP.h Normal file
View File

@ -0,0 +1,184 @@
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
/* GeoIP.h
*
* Copyright (C) 2006 MaxMind LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef GEOIP_H
#define GEOIP_H
#ifdef __cplusplus
extern "C" {
#endif
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <sys/types.h> /* for fstat */
#include <sys/stat.h> /* for fstat */
#define SEGMENT_RECORD_LENGTH 3
#define STANDARD_RECORD_LENGTH 3
#define ORG_RECORD_LENGTH 4
#define MAX_RECORD_LENGTH 4
#define NUM_DB_TYPES 20
typedef struct GeoIPTag {
FILE *GeoIPDatabase;
char *file_path;
unsigned char *cache;
unsigned char *index_cache;
unsigned int *databaseSegments;
char databaseType;
time_t mtime;
int flags;
off_t size;
char record_length;
int charset; /* 0 iso-8859-1 1 utf8 */
int record_iter; /* used in GeoIP_next_record */
int netmask; /* netmask of last lookup - set using depth in _GeoIP_seek_record */
} GeoIP;
typedef enum {
GEOIP_CHARSET_ISO_8859_1 = 0,
GEOIP_CHARSET_UTF8 = 1
} GeoIPCharset;
typedef struct GeoIPRegionTag {
char country_code[3];
char region[3];
} GeoIPRegion;
typedef enum {
GEOIP_STANDARD = 0,
GEOIP_MEMORY_CACHE = 1,
GEOIP_CHECK_CACHE = 2,
GEOIP_INDEX_CACHE = 4,
GEOIP_MMAP_CACHE = 8,
} GeoIPOptions;
typedef enum {
GEOIP_COUNTRY_EDITION = 1,
GEOIP_REGION_EDITION_REV0 = 7,
GEOIP_CITY_EDITION_REV0 = 6,
GEOIP_ORG_EDITION = 5,
GEOIP_ISP_EDITION = 4,
GEOIP_CITY_EDITION_REV1 = 2,
GEOIP_REGION_EDITION_REV1 = 3,
GEOIP_PROXY_EDITION = 8,
GEOIP_ASNUM_EDITION = 9,
GEOIP_NETSPEED_EDITION = 10,
GEOIP_DOMAIN_EDITION = 11
} GeoIPDBTypes;
typedef enum {
GEOIP_ANON_PROXY = 1,
GEOIP_HTTP_X_FORWARDED_FOR_PROXY = 2,
GEOIP_HTTP_CLIENT_IP_PROXY = 3,
} GeoIPProxyTypes;
typedef enum {
GEOIP_UNKNOWN_SPEED = 0,
GEOIP_DIALUP_SPEED = 1,
GEOIP_CABLEDSL_SPEED = 2,
GEOIP_CORPORATE_SPEED = 3,
} GeoIPNetspeedValues;
extern char **GeoIPDBFileName;
extern const char * GeoIPDBDescription[NUM_DB_TYPES];
extern const char *GeoIPCountryDBFileName;
extern const char *GeoIPRegionDBFileName;
extern const char *GeoIPCityDBFileName;
extern const char *GeoIPOrgDBFileName;
extern const char *GeoIPISPDBFileName;
extern const char GeoIP_country_code[253][3];
extern const char GeoIP_country_code3[253][4];
extern const char * GeoIP_country_name[253];
extern const char GeoIP_country_continent[253][3];
#ifdef DLL
#define GEOIP_API __declspec(dllexport)
#else
#define GEOIP_API
#endif /* DLL */
GEOIP_API void GeoIP_setup_custom_directory(char *dir);
GEOIP_API GeoIP* GeoIP_open_type (int type, int flags);
GEOIP_API GeoIP* GeoIP_new(int flags);
GEOIP_API GeoIP* GeoIP_open(const char * filename, int flags);
GEOIP_API int GeoIP_db_avail(int type);
GEOIP_API void GeoIP_delete(GeoIP* gi);
GEOIP_API const char *GeoIP_country_code_by_addr (GeoIP* gi, const char *addr);
GEOIP_API const char *GeoIP_country_code_by_name (GeoIP* gi, const char *host);
GEOIP_API const char *GeoIP_country_code3_by_addr (GeoIP* gi, const char *addr);
GEOIP_API const char *GeoIP_country_code3_by_name (GeoIP* gi, const char *host);
GEOIP_API const char *GeoIP_country_name_by_addr (GeoIP* gi, const char *addr);
GEOIP_API const char *GeoIP_country_name_by_name (GeoIP* gi, const char *host);
GEOIP_API const char *GeoIP_country_name_by_ipnum (GeoIP* gi, unsigned long ipnum);
GEOIP_API const char *GeoIP_country_code_by_ipnum (GeoIP* gi, unsigned long ipnum);
GEOIP_API const char *GeoIP_country_code3_by_ipnum (GeoIP* gi, unsigned long ipnum);
/* Deprecated - for backwards compatibility only */
GEOIP_API int GeoIP_country_id_by_addr (GeoIP* gi, const char *addr);
GEOIP_API int GeoIP_country_id_by_name (GeoIP* gi, const char *host);
GEOIP_API char *GeoIP_org_by_addr (GeoIP* gi, const char *addr);
GEOIP_API char *GeoIP_org_by_name (GeoIP* gi, const char *host);
/* End deprecated */
GEOIP_API int GeoIP_id_by_addr (GeoIP* gi, const char *addr);
GEOIP_API int GeoIP_id_by_name (GeoIP* gi, const char *host);
GEOIP_API int GeoIP_id_by_ipnum (GeoIP* gi, unsigned long ipnum);
GEOIP_API GeoIPRegion * GeoIP_region_by_addr (GeoIP* gi, const char *addr);
GEOIP_API GeoIPRegion * GeoIP_region_by_name (GeoIP* gi, const char *host);
GEOIP_API GeoIPRegion * GeoIP_region_by_ipnum (GeoIP *gi, unsigned long ipnum);
/* Warning - don't call this after GeoIP_assign_region_by_inetaddr calls */
GEOIP_API void GeoIPRegion_delete (GeoIPRegion *gir);
GEOIP_API void GeoIP_assign_region_by_inetaddr(GeoIP* gi, unsigned long inetaddr, GeoIPRegion *gir);
/* Used to query GeoIP Organization, ISP and AS Number databases */
GEOIP_API char *GeoIP_name_by_ipnum (GeoIP* gi, unsigned long ipnum);
GEOIP_API char *GeoIP_name_by_addr (GeoIP* gi, const char *addr);
GEOIP_API char *GeoIP_name_by_name (GeoIP* gi, const char *host);
GEOIP_API char *GeoIP_database_info (GeoIP* gi);
GEOIP_API unsigned char GeoIP_database_edition (GeoIP* gi);
GEOIP_API int GeoIP_charset (GeoIP* gi);
GEOIP_API int GeoIP_set_charset (GeoIP* gi, int charset);
GEOIP_API int GeoIP_last_netmask (GeoIP* gi);
/* Convert region code to region name */
GEOIP_API const char * GeoIP_region_name_by_code(const char *country_code, const char *region_code);
/* Get timezone from country and region code */
GEOIP_API const char * GeoIP_time_zone_by_country_and_region(const char *country_code, const char *region_code);
#ifdef BSD
#define memcpy(dest, src, n) bcopy(src, dest, n)
#endif
#ifdef __cplusplus
}
#endif
#endif /* GEOIP_H */

View File

@ -40,6 +40,10 @@ POSSIBILITY OF SUCH DAMAGE.
#include <list>
#include <deque>
#ifndef TORRENT_DISABLE_GEO_IP
#include "libtorrent/GeoIP.h"
#endif
#ifdef _MSC_VER
#pragma warning(push, 1)
#endif
@ -285,6 +289,17 @@ namespace libtorrent
{ return m_dht_proxy; }
#endif
#ifndef TORRENT_DISABLE_GEO_IP
std::string as_name_for_ip(address const& a);
int as_for_ip(address const& a);
std::pair<const int, int>* lookup_as(int as);
bool load_asnum_db(char const* file);
bool has_asnum_db() const { return m_geoip_db; }
#endif
void load_state(entry const& ses_state);
entry state() const;
#ifdef TORRENT_STATS
void log_buffer_usage()
{
@ -566,6 +581,16 @@ namespace libtorrent
extension_list_t m_extensions;
#endif
#ifndef TORRENT_DISABLE_GEO_IP
GeoIP* m_geoip_db;
// maps AS number to the peak download rate
// we've seen from it. Entries are never removed
// from this map. Pointers to its elements
// are kept in the policy::peer structures.
std::map<int, int> m_as_peak;
#endif
// the main working thread
boost::scoped_ptr<boost::thread> m_thread;
};

View File

@ -781,11 +781,14 @@ namespace libtorrent
// they sent us
size_type m_downloaded_at_last_unchoke;
#ifndef TORRENT_DISABLE_GEO_IP
std::string m_inet_as_name;
#endif
// max transfer rates seen on this peer
int m_download_rate_peak;
int m_upload_rate_peak;
#ifndef NDEBUG
public:
bool m_in_constructor;

View File

@ -122,6 +122,12 @@ namespace libtorrent
char country[2];
#endif
#ifndef TORRENT_DISABLE_GEO_IP
// atonomous system this peer belongs to
std::string inet_as_name;
int inet_as;
#endif
size_type load_balancing;
// this is the number of requests

View File

@ -126,18 +126,23 @@ namespace libtorrent
struct peer
{
enum connection_type { not_connectable, connectable };
peer(tcp::endpoint const& ip, connection_type t, int src);
size_type total_download() const;
size_type total_upload() const;
// the ip/port pair this peer is or was connected on
// if it was a remote (incoming) connection, type is
// set thereafter. If it was a peer we got from the
// tracker, type is set to local_connection.
tcp::endpoint ip;
connection_type type;
#ifndef TORRENT_DISABLE_GEO_IP
#ifndef NDEBUG
// only used in debug mode to assert that
// the first entry in the AS pair keeps the same
boost::uint16_t inet_as_num;
#endif
// The AS this peer belongs to
std::pair<const int, int>* inet_as;
#endif
// the number of failed connection attempts
// this peer has
@ -159,9 +164,14 @@ namespace libtorrent
// part of a piece that failed the hash check
boost::uint8_t hashfails;
// type specifies if the connection was incoming
// or outgoing. If we ever saw this peer as connectable
// it will remain as connectable
unsigned type:4;
// the number of times we have allowed a fast
// reconnect for this peer.
boost::uint8_t fast_reconnects:4;
unsigned fast_reconnects:4;
#ifndef TORRENT_DISABLE_ENCRYPTION
// Hints encryption support of peer. Only effective

View File

@ -200,6 +200,13 @@ namespace libtorrent
void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> ext);
#endif
#ifndef TORRENT_DISABLE_GEO_IP
bool load_asnum_db(char const* file);
#endif
void load_state(entry const& ses_state);
entry state() const;
void set_ip_filter(ip_filter const& f);
void set_port_filter(port_filter const& f);
void set_peer_id(peer_id const& pid);

1031
src/GeoIP.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -141,6 +141,9 @@ namespace libtorrent
#ifndef NDEBUG
piece_failed = false;
#endif
#ifndef TORRENT_DISABLE_GEO_IP
m_inet_as_name = m_ses.as_name_for_ip(m_remote.address());
#endif
std::fill(m_peer_id.begin(), m_peer_id.end(), 0);
}
@ -237,6 +240,9 @@ namespace libtorrent
if (m_remote.address().is_v4())
m_socket->set_option(type_of_service(ses.settings().peer_tos), ec);
#ifndef TORRENT_DISABLE_GEO_IP
m_inet_as_name = m_ses.as_name_for_ip(m_remote.address());
#endif
#ifndef NDEBUG
piece_failed = false;
#endif
@ -2218,6 +2224,9 @@ namespace libtorrent
p.pending_disk_bytes = m_outstanding_writing_bytes;
p.send_quota = m_bandwidth_limit[upload_channel].quota_left();
p.receive_quota = m_bandwidth_limit[download_channel].quota_left();
#ifndef TORRENT_DISABLE_GEO_IP
p.inet_as_name = m_inet_as_name;
#endif
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
p.country[0] = m_country[0];
@ -2270,12 +2279,15 @@ namespace libtorrent
p.flags |= is_seed() ? peer_info::seed : 0;
if (peer_info_struct())
{
p.source = peer_info_struct()->source;
p.failcount = peer_info_struct()->failcount;
p.num_hashfails = peer_info_struct()->hashfails;
p.flags |= peer_info_struct()->on_parole ? peer_info::on_parole : 0;
p.flags |= peer_info_struct()->optimistically_unchoked ? peer_info::optimistic_unchoke : 0;
p.remote_dl_rate = m_remote_dl_rate;
policy::peer* pi = peer_info_struct();
p.source = pi->source;
p.failcount = pi->failcount;
p.num_hashfails = pi->hashfails;
p.flags |= pi->on_parole ? peer_info::on_parole : 0;
p.flags |= pi->optimistically_unchoked ? peer_info::optimistic_unchoke : 0;
#ifndef TORRENT_DISABLE_GEO_IP
p.inet_as = pi->inet_as->first;
#endif
}
else
{
@ -2283,8 +2295,12 @@ namespace libtorrent
p.failcount = 0;
p.num_hashfails = 0;
p.remote_dl_rate = 0;
#ifndef TORRENT_DISABLE_GEO_IP
p.inet_as = 0xffff;
#endif
}
p.remote_dl_rate = m_remote_dl_rate;
p.send_buffer_size = m_send_buffer.capacity();
p.used_send_buffer = m_send_buffer.size();
p.write_state = m_channel_state[upload_channel];
@ -2347,6 +2363,14 @@ namespace libtorrent
if (m_statistics.download_payload_rate() > m_download_rate_peak)
{
m_download_rate_peak = m_statistics.download_payload_rate();
#ifndef TORRENT_DISABLE_GEO_IP
if (peer_info_struct())
{
std::pair<const int, int>* as_stats = peer_info_struct()->inet_as;
if (as_stats && as_stats->second < m_download_rate_peak)
as_stats->second = m_download_rate_peak;
}
#endif
}
if (!t->valid_metadata()) return;

View File

@ -458,11 +458,13 @@ namespace libtorrent
iterator candidate = m_peers.end();
int min_reconnect_time = m_torrent->settings().min_reconnect_time;
int min_cidr_distance = (std::numeric_limits<int>::max)();
bool finished = m_torrent->is_finished();
int min_cidr_distance = (std::numeric_limits<int>::max)();
address external_ip = m_torrent->session().external_address();
if (external_ip == address())
// don't bias any particular peers when seeding
if (finished || external_ip == address())
{
// set external_ip to a random value, to
// radomize which peers we prefer
@ -471,6 +473,11 @@ namespace libtorrent
external_ip = address_v4(bytes);
}
#ifndef TORRENT_DISABLE_GEO_IP
int max_inet_as_rate = -1;
bool has_db = m_torrent->session().has_asnum_db();
#endif
int connect_candidates = 0;
int seeds = 0;
for (iterator i = m_peers.begin(); i != m_peers.end(); ++i)
@ -498,10 +505,26 @@ namespace libtorrent
continue;
if (i->second.connected > min_connect_time) continue;
int distance = cidr_distance(external_ip, i->second.ip.address());
if (distance > min_cidr_distance) continue;
min_cidr_distance = distance;
#ifndef TORRENT_DISABLE_GEO_IP
if (!finished && has_db)
{
// don't bias fast peers when seeding
std::pair<const int, int>* inet_as = i->second.inet_as;
int peak_rate = inet_as ? inet_as->second : 0;
if (peak_rate <= max_inet_as_rate) continue;
max_inet_as_rate = peak_rate;
}
if (max_inet_as_rate <= 0)
#endif
{
int distance = cidr_distance(external_ip, i->second.ip.address());
if (distance > min_cidr_distance) continue;
min_cidr_distance = distance;
}
min_connect_time = i->second.connected;
candidate = i;
}
@ -684,8 +707,10 @@ namespace libtorrent
asio::error_code ec;
TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || ec);
aux::session_impl& ses = m_torrent->session();
if (m_torrent->num_peers() >= m_torrent->max_connections()
&& m_torrent->session().num_connections() >= m_torrent->session().max_connections()
&& ses.num_connections() >= ses.max_connections()
&& c.remote().address() != m_torrent->current_tracker().address())
{
c.disconnect("too many connections, refusing incoming connection");
@ -753,6 +778,13 @@ namespace libtorrent
peer p(c.remote(), peer::not_connectable, 0);
i = m_peers.insert(std::make_pair(c.remote().address(), p));
#ifndef TORRENT_DISABLE_GEO_IP
int as = ses.as_for_ip(c.remote().address());
#ifndef NDEBUG
i->second.inet_as_num = as;
#endif
i->second.inet_as = ses.lookup_as(as);
#endif
}
c.set_peer_info(&i->second);
@ -879,6 +911,14 @@ namespace libtorrent
i->second.seed = true;
++m_num_seeds;
}
#ifndef TORRENT_DISABLE_GEO_IP
int as = ses.as_for_ip(remote.address());
#ifndef NDEBUG
i->second.inet_as_num = as;
#endif
i->second.inet_as = ses.lookup_as(as);
#endif
}
else
{
@ -985,6 +1025,8 @@ namespace libtorrent
, boost::bind<bool>(std::equal_to<peer_connection*>(), bind(&peer::connection
, bind(&iterator::value_type::second, _1)), &c)) != m_peers.end());
aux::session_impl& ses = m_torrent->session();
// if the peer is choked and we have upload slots left,
// then unchoke it. Another condition that has to be met
// is that the torrent doesn't keep track of the individual
@ -996,23 +1038,23 @@ namespace libtorrent
// In that case we don't care if people are leeching, they
// can't pay for their downloads anyway.
if (c.is_choked()
&& m_torrent->session().num_uploads() < m_torrent->session().max_uploads()
&& ses.num_uploads() < ses.max_uploads()
&& (m_torrent->ratio() == 0
|| c.share_diff() >= -free_upload_amount
|| m_torrent->is_finished()))
{
m_torrent->session().unchoke_peer(c);
ses.unchoke_peer(c);
}
#if defined TORRENT_VERBOSE_LOGGING
else if (c.is_choked())
{
std::string reason;
if (m_torrent->session().num_uploads() >= m_torrent->session().max_uploads())
if (ses.num_uploads() >= ses.max_uploads())
{
reason = "the number of uploads ("
+ boost::lexical_cast<std::string>(m_torrent->session().num_uploads())
+ boost::lexical_cast<std::string>(ses.num_uploads())
+ ") is more than or equal to the limit ("
+ boost::lexical_cast<std::string>(m_torrent->session().max_uploads())
+ boost::lexical_cast<std::string>(ses.max_uploads())
+ ")";
}
else
@ -1231,6 +1273,9 @@ namespace libtorrent
i != m_peers.end(); ++i)
{
peer const& p = i->second;
#ifndef TORRENT_DISABLE_GEO_IP
TORRENT_ASSERT(p.inet_as == 0 || p.inet_as->first == p.inet_as_num);
#endif
if (!m_torrent->settings().allow_multiple_connections_per_ip)
{
TORRENT_ASSERT(m_peers.count(p.ip.address()) == 1);
@ -1316,11 +1361,14 @@ namespace libtorrent
policy::peer::peer(const tcp::endpoint& ip_, peer::connection_type t, int src)
: ip(ip_)
, type(t)
#ifndef TORRENT_DISABLE_GEO_IP
, inet_as(0)
#endif
, failcount(0)
, trust_points(0)
, source(src)
, hashfails(0)
, type(t)
, fast_reconnects(0)
#ifndef TORRENT_DISABLE_ENCRYPTION
, pe_support(true)

View File

@ -175,6 +175,23 @@ namespace libtorrent
m_impl->add_extension(ext);
}
#ifndef TORRENT_DISABLE_GEO_IP
bool session::load_asnum_db(char const* file)
{
return m_impl->load_asnum_db(file);
}
#endif
void session::load_state(entry const& ses_state)
{
m_impl->load_state(ses_state);
}
entry session::state() const
{
return m_impl->state();
}
void session::set_ip_filter(ip_filter const& f)
{
m_impl->set_ip_filter(f);

View File

@ -169,6 +169,9 @@ namespace aux {
, m_next_connect_torrent(0)
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
, m_logpath(logpath)
#endif
#ifndef TORRENT_DISABLE_GEO_IP
, m_geoip_db(0)
#endif
{
#ifdef WIN32
@ -243,6 +246,99 @@ namespace aux {
m_thread.reset(new boost::thread(boost::ref(*this)));
}
#ifndef TORRENT_DISABLE_GEO_IP
namespace
{
struct free_ptr
{
void* ptr_;
free_ptr(void* p): ptr_(p) {}
~free_ptr() { free(ptr_); }
};
}
int session_impl::as_for_ip(address const& a)
{
if (!a.is_v4() || m_geoip_db == 0) return 0;
char* name = GeoIP_name_by_ipnum(m_geoip_db, a.to_v4().to_ulong());
if (name == 0) return 0;
free_ptr p(name);
// GeoIP returns the name as AS??? where ? is the AS-number
return atoi(name + 2);
}
std::string session_impl::as_name_for_ip(address const& a)
{
if (!a.is_v4() || m_geoip_db == 0) return std::string();
char* name = GeoIP_name_by_ipnum(m_geoip_db, a.to_v4().to_ulong());
if (name == 0) return std::string();
free_ptr p(name);
char* tmp = std::strchr(name, ' ');
if (tmp == 0) return std::string();
return tmp + 1;
}
std::pair<const int, int>* session_impl::lookup_as(int as)
{
std::map<int, int>::iterator i = m_as_peak.lower_bound(as);
if (i == m_as_peak.end() || i->first != as)
{
// we don't have any data for this AS, insert a new entry
i = m_as_peak.insert(i, std::pair<int, int>(as, 0));
}
return &(*i);
}
bool session_impl::load_asnum_db(char const* file)
{
mutex_t::scoped_lock l(m_mutex);
if (m_geoip_db) GeoIP_delete(m_geoip_db);
m_geoip_db = GeoIP_open(file, GEOIP_STANDARD);
return m_geoip_db;
}
#endif
void session_impl::load_state(entry const& ses_state)
{
if (ses_state.type() != entry::dictionary_t) return;
mutex_t::scoped_lock l(m_mutex);
#ifndef TORRENT_DISABLE_GEO_IP
entry const* as_map = ses_state.find_key("AS map");
if (as_map && as_map->type() == entry::dictionary_t)
{
entry::dictionary_type const& as_peak = as_map->dict();
for (entry::dictionary_type::const_iterator i = as_peak.begin()
, end(as_peak.end()); i != end; ++i)
{
int as_num = atoi(i->first.c_str());
if (i->second.type() != entry::int_t || i->second.integer() == 0) continue;
int& peak = m_as_peak[as_num];
if (peak < i->second.integer()) peak = i->second.integer();
}
}
#endif
}
entry session_impl::state() const
{
mutex_t::scoped_lock l(m_mutex);
entry ret;
#ifndef TORRENT_DISABLE_GEO_IP
entry::dictionary_type& as_map = ret["AS map"].dict();
char buf[10];
for (std::map<int, int>::const_iterator i = m_as_peak.begin()
, end(m_as_peak.end()); i != end; ++i)
{
if (i->second == 0) continue;
sprintf(buf, "%05d", i->first);
as_map[buf] = i->second;
}
#endif
return ret;
}
#ifndef TORRENT_DISABLE_EXTENSIONS
void session_impl::add_extension(
boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> ext)
@ -1825,6 +1921,9 @@ namespace aux {
#endif
abort();
#ifndef TORRENT_DISABLE_GEO_IP
if (m_geoip_db) GeoIP_delete(m_geoip_db);
#endif
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_logger) << time_now_string() << " waiting for main thread\n";
#endif