diff --git a/libtorrent/include/libtorrent/aux_/session_impl.hpp b/libtorrent/include/libtorrent/aux_/session_impl.hpp index c9b6cb218..03e9cb619 100644 --- a/libtorrent/include/libtorrent/aux_/session_impl.hpp +++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp @@ -372,6 +372,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/libtorrent/include/libtorrent/bandwidth_manager.hpp b/libtorrent/include/libtorrent/bandwidth_manager.hpp index c3b4f5942..19f0cc790 100644 --- a/libtorrent/include/libtorrent/bandwidth_manager.hpp +++ b/libtorrent/include/libtorrent/bandwidth_manager.hpp @@ -117,6 +117,9 @@ struct bandwidth_manager void close() { m_abort = true; + m_queue.clear(); + m_history.clear(); + m_current_quota = 0; m_history_timer.cancel(); } @@ -153,6 +156,7 @@ struct bandwidth_manager { mutex_t::scoped_lock l(m_mutex); INVARIANT_CHECK; + if (m_abort) return; TORRENT_ASSERT(blk > 0); TORRENT_ASSERT(!peer->ignore_bandwidth_limits()); diff --git a/libtorrent/include/libtorrent/broadcast_socket.hpp b/libtorrent/include/libtorrent/broadcast_socket.hpp index df656f4ea..a4c448d82 100644 --- a/libtorrent/include/libtorrent/broadcast_socket.hpp +++ b/libtorrent/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/libtorrent/include/libtorrent/disk_io_thread.hpp b/libtorrent/include/libtorrent/disk_io_thread.hpp index 1d9d88534..9db30a58c 100644 --- a/libtorrent/include/libtorrent/disk_io_thread.hpp +++ b/libtorrent/include/libtorrent/disk_io_thread.hpp @@ -44,6 +44,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "libtorrent/config.hpp" namespace libtorrent @@ -133,7 +134,7 @@ namespace libtorrent mutable mutex_t m_mutex; boost::condition m_signal; bool m_abort; - std::deque m_jobs; + std::list m_jobs; size_type m_queue_buffer_size; // memory pool for read and write operations diff --git a/libtorrent/src/broadcast_socket.cpp b/libtorrent/src/broadcast_socket.cpp index 16f0a0728..c7b7e71c8 100644 --- a/libtorrent/src/broadcast_socket.cpp +++ b/libtorrent/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/libtorrent/src/bt_peer_connection.cpp b/libtorrent/src/bt_peer_connection.cpp index 1fbc3b8fa..b1884496b 100755 --- a/libtorrent/src/bt_peer_connection.cpp +++ b/libtorrent/src/bt_peer_connection.cpp @@ -1228,6 +1228,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/libtorrent/src/disk_io_thread.cpp b/libtorrent/src/disk_io_thread.cpp index e1cfbfe5f..4c44ca307 100644 --- a/libtorrent/src/disk_io_thread.cpp +++ b/libtorrent/src/disk_io_thread.cpp @@ -70,7 +70,7 @@ namespace libtorrent , int action, int piece) const { mutex_t::scoped_lock l(m_mutex); - for (std::deque::const_iterator i = m_jobs.begin(); + for (std::list::const_iterator i = m_jobs.begin(); i != m_jobs.end(); ++i) { if (i->storage != s) @@ -105,7 +105,7 @@ namespace libtorrent { mutex_t::scoped_lock l(m_mutex); // read jobs are aborted, write and move jobs are syncronized - for (std::deque::iterator i = m_jobs.begin(); + for (std::list::iterator i = m_jobs.begin(); i != m_jobs.end();) { if (i->storage != s) @@ -158,7 +158,7 @@ namespace libtorrent TORRENT_ASSERT(j.storage); mutex_t::scoped_lock l(m_mutex); - std::deque::reverse_iterator i = m_jobs.rbegin(); + std::list::reverse_iterator i = m_jobs.rbegin(); if (j.action == disk_io_job::read) { // when we're reading, we may not skip @@ -201,7 +201,7 @@ namespace libtorrent if (i == m_jobs.rend() && (m_jobs.empty() || j.priority <= m_jobs.back().priority)) i = m_jobs.rbegin(); - std::deque::iterator k = m_jobs.insert(i.base(), j); + std::list::iterator k = m_jobs.insert(i.base(), j); k->callback.swap(const_cast&>(f)); if (j.action == disk_io_job::write) m_queue_buffer_size += j.buffer_size; diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index 8afc894de..1f977f4fb 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -1393,6 +1393,8 @@ namespace libtorrent #ifndef NDEBUG t->check_invariant(); #endif + request_a_block(*t, *this); + send_block_requests(); } void peer_connection::on_disk_write_complete(int ret, disk_io_job const& j @@ -2485,7 +2487,7 @@ namespace libtorrent if (m_bandwidth_limit[upload_channel].max_assignable() > 0) { #ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << "req bandwidth [ " << upload_channel << " ]\n"; + (*m_logger) << time_now_string() << " *** REQUEST_BANDWIDTH [ upload ]\n"; #endif TORRENT_ASSERT(!m_writing); @@ -2497,7 +2499,18 @@ namespace libtorrent return; } - if (!can_write()) return; + if (!can_write()) + { +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << time_now_string() << " *** CANNOT WRITE [" + " quota: " << m_bandwidth_limit[download_channel].quota_left() << + " ignore: " << (m_ignore_bandwidth_limits?"yes":"no") << + " buf: " << m_send_buffer.size() << + " connecting: " << (m_connecting?"yes":"no") << + " ]\n"; +#endif + return; + } TORRENT_ASSERT(!m_writing); @@ -2512,7 +2525,7 @@ namespace libtorrent TORRENT_ASSERT(amount_to_send > 0); #ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << "async_write " << amount_to_send << " bytes\n"; + (*m_logger) << time_now_string() << " *** ASYNC_WRITE [ bytes: " << amount_to_send << " ]\n"; #endif std::list const& vec = m_send_buffer.build_iovec(amount_to_send); m_socket->async_write_some(vec, bind(&peer_connection::on_send_data, self(), _1, _2)); @@ -2528,7 +2541,7 @@ namespace libtorrent INVARIANT_CHECK; #ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << "setup_receive: reading = " << m_reading << "\n"; + (*m_logger) << time_now_string() << " *** SETUP_RECEIVE [ reading: " << (m_reading?"yes":"no") << "]\n"; #endif if (m_reading) return; @@ -2542,7 +2555,7 @@ namespace libtorrent if (m_bandwidth_limit[download_channel].max_assignable() > 0) { #ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << "req bandwidth [ " << download_channel << " ]\n"; + (*m_logger) << time_now_string() << " *** REQUEST_BANDWIDTH [ download ]\n"; #endif m_reading = true; t->request_bandwidth(download_channel, self(), m_priority); @@ -2550,7 +2563,18 @@ namespace libtorrent return; } - if (!can_read()) return; + if (!can_read()) + { +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << time_now_string() << " *** CANNOT READ [" + " quota: " << m_bandwidth_limit[download_channel].quota_left() << + " ignore: " << (m_ignore_bandwidth_limits?"yes":"no") << + " outstanding: " << m_outstanding_writing_bytes << + " outstanding-limit: " << m_ses.settings().max_outstanding_disk_bytes_per_connection << + " ]\n"; +#endif + return; + } TORRENT_ASSERT(m_packet_size > 0); int max_receive = m_packet_size - m_recv_pos; @@ -2565,7 +2589,7 @@ namespace libtorrent TORRENT_ASSERT(can_read()); #ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << "async_read " << max_receive << " bytes\n"; + (*m_logger) << time_now_string() << " *** ASYNC_READ [ max: " << max_receive << " bytes ]\n"; #endif m_socket->async_read_some(asio::buffer(&m_recv_buffer[m_recv_pos] , max_receive), bind(&peer_connection::on_receive_data, self(), _1, _2)); @@ -2782,7 +2806,7 @@ namespace libtorrent m_ses.settings().max_outstanding_disk_bytes_per_connection; #if defined(TORRENT_VERBOSE_LOGGING) - (*m_logger) << "*** can_read() " << ret << " reading: " << m_reading << "\n"; + (*m_logger) << time_now_string() << " *** can_read() " << (ret?"yes":"no") << " reading: " << m_reading << "\n"; #endif return ret; diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index 0599096d5..4f3f8cfa4 100755 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -525,7 +525,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(); @@ -549,15 +560,29 @@ namespace libtorrent TORRENT_ASSERT(i->second.connected <= now); - 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; } /*