diff --git a/include/libtorrent/policy.hpp b/include/libtorrent/policy.hpp index 82d04eecc..0dfcc267f 100755 --- a/include/libtorrent/policy.hpp +++ b/include/libtorrent/policy.hpp @@ -86,7 +86,8 @@ namespace libtorrent // this is called once for every peer we get from // the tracker - void peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid); + void peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid + , char flags = 0); // called when an incoming connection is accepted void new_connection(peer_connection& c); @@ -101,7 +102,10 @@ namespace libtorrent // is called when a peer is believed to have // sent invalid data - void ban_peer(const peer_connection& c); + void ban_peer(peer_connection const& c); + + // is called on peers that become seeds + void set_seed(peer_connection const& c); // the peer has got at least one interesting piece void peer_is_interesting(peer_connection& c); @@ -144,6 +148,9 @@ namespace libtorrent tcp::endpoint ip; connection_type type; + // this is true if the peer is a seed + bool seed; + // the time when this peer was optimistically unchoked // the last time. boost::posix_time::ptime last_optimistically_unchoked; diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 31bc81de2..b757ac387 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -678,9 +678,13 @@ namespace libtorrent t->get_policy().peer_is_interesting(*this); } - if (t->is_seed() && is_seed()) + if (is_seed()) { - throw protocol_error("seed to seed connection redundant, disconnecting"); + t->get_policy().set_seed(*this); + if (t->is_seed()) + { + throw protocol_error("seed to seed connection redundant, disconnecting"); + } } } } @@ -751,6 +755,7 @@ namespace libtorrent #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << " *** THIS IS A SEED ***\n"; #endif + t->get_policy().set_seed(*this); // if we're a seed too, disconnect if (t->is_seed()) { diff --git a/src/policy.cpp b/src/policy.cpp index 577061bfd..cb5043c8a 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -512,9 +512,10 @@ namespace libtorrent for (std::vector::iterator i = m_peers.begin(); i != m_peers.end(); ++i) { - if(i->connection) continue; - if(i->banned) continue; - if(i->type == peer::not_connectable) continue; + if (i->connection) continue; + if (i->banned) continue; + if (i->type == peer::not_connectable) continue; + if (i->seed && m_torrent->is_seed()) continue; assert(i->connected <= local_time); @@ -857,7 +858,7 @@ namespace libtorrent } } - void policy::ban_peer(const peer_connection& c) + void policy::ban_peer(peer_connection const& c) { INVARIANT_CHECK; @@ -881,6 +882,21 @@ namespace libtorrent i->banned = true; } + void policy::set_seed(peer_connection const& c) + { + INVARIANT_CHECK; + + std::vector::iterator i = std::find_if( + m_peers.begin() + , m_peers.end() + , match_peer_connection(c)); + + // it might be an http-seed + if (i == m_peers.end()) return; + + i->seed = true; + } + void policy::new_connection(peer_connection& c) { assert(!c.is_local()); @@ -974,7 +990,8 @@ namespace libtorrent m_last_optimistic_disconnect = second_clock::universal_time(); } - void policy::peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid) + void policy::peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid + , char flags) { INVARIANT_CHECK; @@ -1012,6 +1029,7 @@ namespace libtorrent // the iterator is invalid // because of the push_back() i = m_peers.end() - 1; + if (flags & 0x02) p.seed = true; just_added = true; } else @@ -1022,6 +1040,7 @@ namespace libtorrent // not known, so save it. Client may also have changed port // for some reason. i->ip = remote; + if (flags & 0x02) i->seed = true; if (i->connection) { @@ -1386,7 +1405,8 @@ namespace libtorrent #endif policy::peer::peer(const tcp::endpoint& ip_, peer::connection_type t) - : ip(ip_) + : seed(false) + , ip(ip_) , type(t) , last_optimistically_unchoked( boost::gregorian::date(1970,boost::gregorian::Jan,1)) diff --git a/src/torrent.cpp b/src/torrent.cpp index 8ffa88e77..687dce274 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -519,7 +519,7 @@ namespace libtorrent get_handle(), peers.size(), "Got peers from DHT")); } std::for_each(peers.begin(), peers.end(), bind( - &policy::peer_from_tracker, boost::ref(m_policy), _1, peer_id(0))); + &policy::peer_from_tracker, boost::ref(m_policy), _1, peer_id(0), 0)); } #endif diff --git a/src/ut_pex.cpp b/src/ut_pex.cpp index 6006efbdc..19a4a9d13 100644 --- a/src/ut_pex.cpp +++ b/src/ut_pex.cpp @@ -81,7 +81,19 @@ namespace libtorrent { namespace if (++m_1_minute < 60) return; m_1_minute = 0; - std::list cs; + + entry pex; + std::string& pla = pex["added"].string(); + std::string& pld = pex["dropped"].string(); + std::string& plf = pex["added.f"].string(); + std::back_insert_iterator pla_out(pla); + std::back_insert_iterator pld_out(pld); + std::back_insert_iterator plf_out(plf); + + std::set dropped; + m_old_peers.swap(dropped); + + int num_added = 0; for (torrent::peer_iterator i = m_torrent.begin() , end(m_torrent.end()); i != end; ++i) { @@ -90,52 +102,41 @@ namespace libtorrent { namespace if (!i->second->is_local()) continue; // don't send out peers that we haven't successfully connected to if (i->second->is_connecting()) continue; - cs.push_back(i->first); - } - std::list added_peers, dropped_peers; + // ut pex does not support IPv6 + if (!i->first.address().is_v4()) continue; - std::set_difference(cs.begin(), cs.end(), m_old_peers.begin() - , m_old_peers.end(), std::back_inserter(added_peers)); - std::set_difference(m_old_peers.begin(), m_old_peers.end() - , cs.begin(), cs.end(), std::back_inserter(dropped_peers)); - m_old_peers = cs; + m_old_peers.insert(i->first); - unsigned int num_peers = max_peer_entries; + std::set::iterator di = dropped.find(i->first); + if (di == dropped.end()) + { + // don't write too big of a package + if (num_added >= max_peer_entries) continue; - std::string pla, pld, plf; - std::back_insert_iterator pla_out(pla); - std::back_insert_iterator pld_out(pld); - std::back_insert_iterator plf_out(plf); - - // TODO: use random selection in case added_peers.size() > num_peers - for (std::list::const_iterator i = added_peers.begin() - , end(added_peers.end());i != end; ++i) - { - if (!i->address().is_v4()) continue; - detail::write_endpoint(*i, pla_out); - // no supported flags to set yet - // 0x01 - peer supports encryption - detail::write_uint8(0, plf_out); - - if (--num_peers == 0) break; + // i->first was added since the last time + detail::write_endpoint(i->first, pla_out); + // no supported flags to set yet + // 0x01 - peer supports encryption + // 0x02 - peer is a seed + int flags = i->second->is_seed() ? 2 : 0; + detail::write_uint8(flags, plf_out); + ++num_added; + } + else + { + // this was in the previous message + // so, it wasn't dropped + dropped.erase(di); + } } - num_peers = max_peer_entries; - // TODO: use random selection in case dropped_peers.size() > num_peers - for (std::list::const_iterator i = dropped_peers.begin() - , end(dropped_peers.end());i != end; ++i) + for (std::set::const_iterator i = dropped.begin() + , end(dropped.end());i != end; ++i) { if (!i->address().is_v4()) continue; detail::write_endpoint(*i, pld_out); - - if (--num_peers == 0) break; } - entry pex(entry::dictionary_t); - pex["added"] = pla; - pex["dropped"] = pld; - pex["added.f"] = plf; - m_ut_pex_msg.clear(); bencode(std::back_inserter(m_ut_pex_msg), pex); } @@ -143,7 +144,7 @@ namespace libtorrent { namespace private: torrent& m_torrent; - std::list m_old_peers; + std::set m_old_peers; int m_1_minute; std::vector m_ut_pex_msg; }; @@ -182,6 +183,7 @@ namespace libtorrent { namespace } virtual bool on_extended(int length, int msg, buffer::const_interval body) + try { if (msg != extension_index) return false; if (m_message_index == 0) return false; @@ -194,26 +196,32 @@ namespace libtorrent { namespace // in case we are a seed we do not use the peers // from the pex message to prevent us from // overloading ourself - if (m_torrent.is_seed()) return true; - entry Pex = bdecode(body.begin, body.end); - entry* PeerList = Pex.find_key("added"); + entry pex_msg = bdecode(body.begin, body.end); + std::string const& peers = pex_msg["added"].string(); + std::string const& peer_flags = pex_msg["added.f"].string(); - if (!PeerList) return true; - std::string const& peers = PeerList->string(); int num_peers = peers.length() / 6; char const* in = peers.c_str(); + char const* fin = peer_flags.c_str(); - peer_id pid; - pid.clear(); + if (int(peer_flags.size()) != num_peers) + return true; + + peer_id pid(0); policy& p = m_torrent.get_policy(); for (int i = 0; i < num_peers; ++i) { tcp::endpoint adr = detail::read_v4_endpoint(in); - if (!m_torrent.connection_for(adr)) p.peer_from_tracker(adr, pid); + char flags = detail::read_uint8(fin); + p.peer_from_tracker(adr, pid, flags); } return true; } + catch (std::exception&) + { + return true; + } // the peers second tick // every minute we send a pex message