From cf5c9344abfd69383509d19cfa6e6d3e23075e74 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 28 Feb 2008 03:09:34 +0000 Subject: [PATCH] made peer connection order depend on ones external IP or be random (if we don't know our external IP). Should fix #281 --- include/libtorrent/aux_/session_impl.hpp | 2 + include/libtorrent/broadcast_socket.hpp | 4 ++ src/broadcast_socket.cpp | 38 +++++++++++++++++++ src/bt_peer_connection.cpp | 21 +++++++++++ src/policy.cpp | 47 ++++++++++++++++++------ test/test_primitives.cpp | 11 ++++++ 6 files changed, 112 insertions(+), 11 deletions(-) diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 0d8fc76a2..4a75687a7 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -382,6 +382,8 @@ namespace libtorrent void free_buffer(char* buf, int size); void free_disk_buffer(char* buf); + address m_external_address; + // private: void on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih); diff --git a/include/libtorrent/broadcast_socket.hpp b/include/libtorrent/broadcast_socket.hpp index d899cb614..85f0c0c7e 100644 --- a/include/libtorrent/broadcast_socket.hpp +++ b/include/libtorrent/broadcast_socket.hpp @@ -45,6 +45,10 @@ namespace libtorrent bool is_loopback(address const& addr); bool is_multicast(address const& addr); bool is_any(address const& addr); + int cidr_distance(address const& a1, address const& a2); + + int common_bits(unsigned char const* b1 + , unsigned char const* b2, int n); address guess_local_address(asio::io_service&); diff --git a/src/broadcast_socket.cpp b/src/broadcast_socket.cpp index 6800d2c8a..64f41b7e2 100644 --- a/src/broadcast_socket.cpp +++ b/src/broadcast_socket.cpp @@ -99,6 +99,44 @@ namespace libtorrent return ret; } + // count the length of the common bit prefix + int common_bits(unsigned char const* b1 + , unsigned char const* b2, int n) + { + for (int i = 0; i < n; ++i, ++b1, ++b2) + { + unsigned char a = *b1 ^ *b2; + if (a == 0) continue; + int ret = i * 8 + 8; + for (; a > 0; a >>= 1) --ret; + return ret; + } + return n * 8; + } + + // returns the number of bits in that differ from the right + // between the addresses. + int cidr_distance(address const& a1, address const& a2) + { + if (a1.is_v4() == a2.is_v4()) + { + // both are v4 + address_v4::bytes_type b1 = a1.to_v4().to_bytes(); + address_v4::bytes_type b2 = a2.to_v4().to_bytes(); + return address_v4::bytes_type::static_size * 8 + - common_bits(b1.c_array(), b2.c_array(), b1.size()); + } + + address_v6::bytes_type b1; + address_v6::bytes_type b2; + if (a1.is_v4()) b1 = address_v6::v4_mapped(a1.to_v4()).to_bytes(); + else b1 = a1.to_v6().to_bytes(); + if (a2.is_v4()) b2 = address_v6::v4_mapped(a2.to_v4()).to_bytes(); + else b2 = a2.to_v6().to_bytes(); + return address_v6::bytes_type::static_size * 8 + - common_bits(b1.c_array(), b2.c_array(), b1.size()); + } + broadcast_socket::broadcast_socket(asio::io_service& ios , udp::endpoint const& multicast_endpoint , receive_handler_t const& handler diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 5e70b181c..90c421d3e 100755 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -1285,6 +1285,27 @@ namespace libtorrent if (m_max_out_request_queue < 1) m_max_out_request_queue = 1; } + + if (entry* myip = root.find_key("yourip")) + { + // TODO: don't trust this blindly + if (myip->type() == entry::string_t) + { + std::string const& my_ip = myip->string().c_str(); + if (my_ip.size() == address_v4::bytes_type::static_size) + { + address_v4::bytes_type bytes; + std::copy(my_ip.begin(), my_ip.end(), bytes.begin()); + m_ses.m_external_address = address_v4(bytes); + } + else if (my_ip.size() == address_v6::bytes_type::static_size) + { + address_v6::bytes_type bytes; + std::copy(my_ip.begin(), my_ip.end(), bytes.begin()); + m_ses.m_external_address = address_v6(bytes); + } + } + } } bool bt_peer_connection::dispatch_message(int received) diff --git a/src/policy.cpp b/src/policy.cpp index d910f7216..1023b5388 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -528,7 +528,18 @@ namespace libtorrent int max_failcount = m_torrent->settings().max_failcount; int min_reconnect_time = m_torrent->settings().min_reconnect_time; + int min_cidr_distance = (std::numeric_limits::max)(); bool finished = m_torrent->is_finished(); + address external_ip = m_torrent->session().m_external_address; + + if (external_ip == address()) + { + // set external_ip to a random value, to + // radomize which peers we prefer + address_v4::bytes_type bytes; + std::generate(bytes.begin(), bytes.end(), &std::rand); + external_ip = address_v4(bytes); + } aux::session_impl& ses = m_torrent->session(); @@ -560,15 +571,29 @@ namespace libtorrent && !is_local(i->second.ip.address())) continue; - if (i->second.connected <= min_connect_time) - { - min_connect_time = i->second.connected; - candidate = i; - } + 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; + min_connect_time = i->second.connected; + candidate = i; } TORRENT_ASSERT(min_connect_time <= now); +#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING + if (candidate != m_peers.end()) + { + (*m_torrent->session().m_logger) << "*** FOUND CONNECTION CANDIDATE [" + " ip: " << candidate->second.ip << + " d: " << min_cidr_distance << + " external: " << external_ip << + " t: " << total_seconds(time_now() - min_connect_time) << + " ]\n"; + } +#endif + return candidate; } /* @@ -943,7 +968,7 @@ namespace libtorrent return false; } -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING if (c.remote().address() == m_torrent->current_tracker().address()) { m_torrent->debug_log("overriding connection limit for tracker NAT-check"); @@ -985,7 +1010,7 @@ namespace libtorrent } else { -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING m_torrent->debug_log("duplicate connection. existing connection" " is connecting and this connection is incoming. closing existing " "connection in favour of this one"); @@ -1153,7 +1178,7 @@ namespace libtorrent // so we don't have to trust this source if ((flags & 0x02) && !i->second.connection) i->second.seed = true; -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING if (i->second.connection) { // this means we're already connected @@ -1249,7 +1274,7 @@ namespace libtorrent { m_torrent->session().unchoke_peer(c); } -#if defined(TORRENT_VERBOSE_LOGGING) +#if defined TORRENT_VERBOSE_LOGGING else if (c.is_choked()) { std::string reason; @@ -1362,7 +1387,7 @@ namespace libtorrent } catch (std::exception& e) { -#if defined(TORRENT_VERBOSE_LOGGING) +#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING (*m_torrent->session().m_logger) << "*** CONNECTION FAILED '" << e.what() << "'\n"; #endif @@ -1377,7 +1402,7 @@ namespace libtorrent iterator p = find_disconnect_candidate(); if (p == m_peers.end()) return false; -#if defined(TORRENT_VERBOSE_LOGGING) +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING (*p->second.connection->m_logger) << "*** CLOSING CONNECTION 'too many connections'\n"; #endif diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index 147f548d2..776fb3885 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -7,6 +7,7 @@ #include "libtorrent/torrent_info.hpp" #include "libtorrent/escape_string.hpp" #include "libtorrent/kademlia/node_id.hpp" +#include "libtorrent/broadcast_socket.hpp" #include #include @@ -367,6 +368,16 @@ int test_main() h2 = sha1_hash(" "); TEST_CHECK(h2 == boost::lexical_cast("2020202020202020202020202020202020202020")); + // CIDR distance test + h1 = boost::lexical_cast("0123456789abcdef01232456789abcdef0123456"); + h2 = boost::lexical_cast("0123456789abcdef01232456789abcdef0123456"); + TEST_CHECK(common_bits(&h1[0], &h2[0], 20) == 160); + h2 = boost::lexical_cast("0120456789abcdef01232456789abcdef0123456"); + TEST_CHECK(common_bits(&h1[0], &h2[0], 20) == 14); + h2 = boost::lexical_cast("012f456789abcdef01232456789abcdef0123456"); + TEST_CHECK(common_bits(&h1[0], &h2[0], 20) == 12); + h2 = boost::lexical_cast("0123456789abcdef11232456789abcdef0123456"); + TEST_CHECK(common_bits(&h1[0], &h2[0], 20) == 16 * 4 + 3); return 0; }