diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index 86e527efd..b4b3fd791 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -101,6 +101,7 @@ namespace libtorrent , ignore_limits_on_local_network(true) , connection_speed(20) , send_redundant_have(false) + , lazy_bitfields(true) #ifndef TORRENT_DISABLE_DHT , use_dht_as_fallback(true) #endif @@ -219,6 +220,12 @@ namespace libtorrent // for collecting statistics in some cases. Default is false. bool send_redundant_have; + // if this is true, outgoing bitfields will never be fuil. If the + // client is seed, a few bits will be set to 0, and later filled + // in with have messages. This is to prevent certain ISPs + // from stopping people from seeding. + bool lazy_bitfields; + #ifndef TORRENT_DISABLE_DHT // while this is true, the dht will note be used unless the // tracker is online diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 1a59eeab2..e38f8fe4d 100755 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -775,19 +775,46 @@ namespace libtorrent assert(m_sent_bitfield == false); assert(t->valid_metadata()); + int num_pieces = bitfield.size(); + int lazy_pieces[50]; + int num_lazy_pieces = 0; + int lazy_piece = 0; + + assert(t->is_seed() == (std::count(bitfield.begin(), bitfield.end(), true) == num_pieces)); + if (t->is_seed() && m_ses.settings().lazy_bitfields) + { + num_lazy_pieces = std::min(50, num_pieces / 10); + if (num_lazy_pieces < 1) num_lazy_pieces = 1; + for (int i = 0; i < num_pieces; ++i) + { + if (rand() % (num_pieces - i) >= num_lazy_pieces - lazy_piece) continue; + lazy_pieces[lazy_piece++] = i; + } + assert(lazy_piece == num_lazy_pieces); + lazy_piece = 0; + } + #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << time_now_string() << " ==> BITFIELD "; std::stringstream bitfield_string; for (int i = 0; i < (int)get_bitfield().size(); ++i) { + if (lazy_piece < num_lazy_pieces + && lazy_pieces[lazy_piece] == i) + { + bitfield_string << "0"; + ++lazy_piece; + continue; + } if (bitfield[i]) bitfield_string << "1"; else bitfield_string << "0"; } bitfield_string << "\n"; (*m_logger) << bitfield_string.str(); + lazy_piece = 0; #endif - const int packet_size = ((int)bitfield.size() + 7) / 8 + 5; + const int packet_size = (num_pieces + 7) / 8 + 5; buffer::interval i = allocate_send_buffer(packet_size); @@ -795,12 +822,31 @@ namespace libtorrent detail::write_uint8(msg_bitfield, i.begin); std::fill(i.begin, i.end, 0); - for (int c = 0; c < (int)bitfield.size(); ++c) + for (int c = 0; c < num_pieces; ++c) { + if (lazy_piece < num_lazy_pieces + && lazy_pieces[lazy_piece]) + { + ++lazy_piece; + continue; + } if (bitfield[c]) i.begin[c >> 3] |= 1 << (7 - (c & 7)); } - assert(i.end - i.begin == ((int)bitfield.size() + 7) / 8); + assert(i.end - i.begin == (num_pieces + 7) / 8); + + if (num_lazy_pieces > 0) + { + for (int i = 0; i < num_lazy_pieces; ++i) + { + write_have(lazy_pieces[i]); +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << time_now_string() + << " ==> HAVE [ piece: " << lazy_pieces[i] << "]\n"; +#endif + } + } + #ifndef NDEBUG m_sent_bitfield = true; #endif diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 03ac9057d..e70ad8571 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -2581,6 +2581,10 @@ namespace libtorrent d = time_now() - m_last_receive; if (d > seconds(m_timeout)) return true; + // TODO: as long as we have less than 95% of the + // global (or local) connection limit, connections should + // never time out for another reason + // if the peer hasn't become interested and we haven't // become interested in the peer for 10 minutes, it // has also timed out. @@ -2636,7 +2640,7 @@ namespace libtorrent bool peer_connection::is_seed() const { INVARIANT_CHECK; - // if m_num_pieces == 0, we probably doesn't have the + // if m_num_pieces == 0, we probably don't have the // metadata yet. return m_num_pieces == (int)m_have_piece.size() && m_num_pieces > 0; }