From acbdbfc1efe0de5d0122f018e33481270fb1edd6 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 27 Nov 2008 20:51:59 +0000 Subject: [PATCH] added tracker exchange (tex) extension --- Jamfile | 1 + docs/manual.rst | 6 +- examples/client_test.cpp | 2 +- include/Makefile.am | 1 + include/libtorrent/extensions/lt_trackers.hpp | 55 +++ include/libtorrent/hasher.hpp | 1 + include/libtorrent/torrent_info.hpp | 22 +- src/Makefile.am | 2 +- src/lt_trackers.cpp | 347 ++++++++++++++++++ src/metadata_transfer.cpp | 5 +- src/session.cpp | 3 + src/torrent.cpp | 33 +- src/torrent_info.cpp | 2 + test/Jamfile | 1 + test/test_metadata_extension.cpp | 4 +- test/test_trackers_extension.cpp | 79 ++++ 16 files changed, 554 insertions(+), 10 deletions(-) create mode 100644 include/libtorrent/extensions/lt_trackers.hpp create mode 100644 src/lt_trackers.cpp create mode 100644 test/test_trackers_extension.cpp diff --git a/Jamfile b/Jamfile index 1459e7d52..ba47a0625 100755 --- a/Jamfile +++ b/Jamfile @@ -336,6 +336,7 @@ SOURCES = metadata_transfer ut_pex ut_metadata + lt_trackers smart_ban ; diff --git a/docs/manual.rst b/docs/manual.rst index 03629c279..e432b896f 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -1480,9 +1480,13 @@ ones with lower tier will always be tried before the one with higher tier number { announce_entry(std::string const& url); std::string url; - int tier; + boost::uint8_t tier; + boost::uint8_t fail_limit; }; +``fail_limit`` is the max number of failures to announce to this tracker in +a row, before this tracker is not used anymore. + total_size() piece_length() piece_size() num_pieces() ----------------------------------------------------- diff --git a/examples/client_test.cpp b/examples/client_test.cpp index d619bbca5..b8c300c8f 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -1348,7 +1348,7 @@ int main(int ac, char* av[]) << std::hex << s.seed_rank << std::dec << " " << s.last_scrape << "\n" << esc("0"); - if (torrent_index != active_torrent) continue; + if (torrent_index != active_torrent && s.state != torrent_status::seeding) continue; char const* progress_bar_color = "33"; // yellow if (s.state == torrent_status::checking_files || s.state == torrent_status::downloading_metadata) diff --git a/include/Makefile.am b/include/Makefile.am index 6d807cff9..5b7f59276 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -84,6 +84,7 @@ libtorrent/aux_/session_impl.hpp \ libtorrent/extensions/metadata_transfer.hpp \ libtorrent/extensions/ut_pex.hpp \ libtorrent/extensions/ut_metadata.hpp \ +libtorrent/extensions/lt_trackers.hpp \ libtorrent/extensions/logger.hpp \ libtorrent/extensions/smart_ban.hpp \ \ diff --git a/include/libtorrent/extensions/lt_trackers.hpp b/include/libtorrent/extensions/lt_trackers.hpp new file mode 100644 index 000000000..72dc941e3 --- /dev/null +++ b/include/libtorrent/extensions/lt_trackers.hpp @@ -0,0 +1,55 @@ +/* + +Copyright (c) 2008, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_LT_TRACKERS_HPP_INCLUDED +#define TORRENT_LT_TRACKERS_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include "libtorrent/config.hpp" + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace libtorrent +{ + struct torrent_plugin; + class torrent; + TORRENT_EXPORT boost::shared_ptr create_lt_trackers_plugin(torrent*, void*); +} + +#endif // TORRENT_LT_TRACKERS_HPP_INCLUDED + diff --git a/include/libtorrent/hasher.hpp b/include/libtorrent/hasher.hpp index f1dba7d1a..f4f0a6c0c 100644 --- a/include/libtorrent/hasher.hpp +++ b/include/libtorrent/hasher.hpp @@ -95,6 +95,7 @@ namespace libtorrent TORRENT_ASSERT(len > 0); SHA1_Update(&m_context, reinterpret_cast(data), len); } + void update(std::string const& data) { update(&data[0], data.size()); } void update(const char* data, int len) { TORRENT_ASSERT(data != 0); diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index d3c74803e..63a7a60d3 100644 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -68,9 +68,27 @@ namespace libtorrent struct TORRENT_EXPORT announce_entry { - announce_entry(std::string const& u): url(u), tier(0) {} + announce_entry(std::string const& u) + : url(u), tier(0) + , fail_limit(3), fails(0) + , verified(false) + {} + std::string url; - int tier; + boost::uint8_t tier; + // the number of times this tracker can fail + // in a row before it's removed. 0 means unlimited + boost::uint8_t fail_limit; + + // the number of times in a row this tracker has failed + boost::uint8_t fails; + + // is set to true if we have ever received a response from + // this tracker + bool verified:1; + + bool can_announce() const + { return fails < fail_limit || fail_limit == 0; } }; #ifndef BOOST_NO_EXCEPTIONS diff --git a/src/Makefile.am b/src/Makefile.am index f48883b02..63ca76a42 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,7 +22,7 @@ http_tracker_connection.cpp udp_tracker_connection.cpp \ alert.cpp identify_client.cpp ip_filter.cpp file.cpp metadata_transfer.cpp \ logger.cpp file_pool.cpp ut_pex.cpp lsd.cpp upnp.cpp instantiate_connection.cpp \ socks5_stream.cpp socks4_stream.cpp http_stream.cpp connection_queue.cpp \ -disk_io_thread.cpp ut_metadata.cpp magnet_uri.cpp udp_socket.cpp smart_ban.cpp \ +disk_io_thread.cpp ut_metadata.cpp lt_trackers.cpp magnet_uri.cpp udp_socket.cpp smart_ban.cpp \ http_parser.cpp gzip.cpp disk_buffer_holder.cpp create_torrent.cpp GeoIP.c \ parse_url.cpp file_storage.cpp error_code.cpp ConvertUTF.cpp $(kademlia_sources) # mapped_storage.cpp diff --git a/src/lt_trackers.cpp b/src/lt_trackers.cpp new file mode 100644 index 000000000..46408b572 --- /dev/null +++ b/src/lt_trackers.cpp @@ -0,0 +1,347 @@ +/* + +Copyright (c) 2008, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "libtorrent/pch.hpp" + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include +#include +#include +#include + +#include "libtorrent/peer_connection.hpp" +#include "libtorrent/bt_peer_connection.hpp" +#include "libtorrent/hasher.hpp" +#include "libtorrent/bencode.hpp" +#include "libtorrent/torrent.hpp" +#include "libtorrent/extensions.hpp" +#include "libtorrent/extensions/ut_metadata.hpp" +#include "libtorrent/alert_types.hpp" +#ifdef TORRENT_STATS +#include "libtorrent/aux_/session_impl.hpp" +#endif + +namespace libtorrent { namespace +{ + + bool send_tracker(announce_entry const& e) + { + // max_fails == 0 means that it's one + // of the trackers from the trackers + // from the torrent file + return e.fail_limit == 0 || e.verified; + } + + struct lt_tracker_plugin : torrent_plugin + { + lt_tracker_plugin(torrent& t) + : m_torrent(t) + , m_updates(0) + , m_2_minutes(110) + { + m_old_trackers = t.trackers(); + update_list_hash(); + } + + virtual boost::shared_ptr new_connection( + peer_connection* pc); + + virtual void tick() + { + if (m_2_minutes++ < 120) return; + m_2_minutes = 0; + + // build tracker diff + entry tex; + entry::list_type& added = tex["added"].list(); + std::vector const& trackers = m_torrent.trackers(); + for (std::vector::const_iterator i = trackers.begin() + , end(trackers.end()); i != end; ++i) + { + std::vector::const_iterator k = std::find_if( + m_old_trackers.begin(), m_old_trackers.end() + , boost::bind(&announce_entry::url, _1) == i->url); + if (k != m_old_trackers.end()) continue; + if (!send_tracker(*i)) continue; + m_old_trackers.push_back(*i); + ++m_updates; + added.push_back(i->url); + } + m_lt_trackers_msg.clear(); + bencode(std::back_inserter(m_lt_trackers_msg), tex); + if (m_updates > 0) update_list_hash(); + } + + void update_list_hash() + { + std::vector canonical_list; + std::transform(m_old_trackers.begin(), m_old_trackers.end(), back_inserter(canonical_list) + , boost::bind(&announce_entry::url, _1)); + std::sort(canonical_list.begin(), canonical_list.end()); + + hasher h; + std::for_each(canonical_list.begin(), canonical_list.end() + , boost::bind(&hasher::update, &h, _1)); + m_list_hash = h.final(); + } + + int num_updates() const { return m_updates; } + + std::vector const& get_lt_tex_msg() const { return m_lt_trackers_msg; } + + sha1_hash const& list_hash() const { return m_list_hash; } + + std::vector const& trackers() const { return m_old_trackers; } + + private: + torrent& m_torrent; + std::vector m_old_trackers; + int m_updates; + int m_2_minutes; + std::vector m_lt_trackers_msg; + sha1_hash m_list_hash; + }; + + + struct lt_tracker_peer_plugin : peer_plugin + { + lt_tracker_peer_plugin(torrent& t, bt_peer_connection& pc, lt_tracker_plugin& tp) + : m_message_index(0) + , m_torrent(t) + , m_pc(pc) + , m_tp(tp) + , m_2_minutes(115) + , m_full_list(true) + {} + + // can add entries to the extension handshake + virtual void add_handshake(entry& h) + { + entry& messages = h["m"]; + messages["lt_tex"] = 3; + h["tr"] = m_tp.list_hash().to_string(); + } + + // called when the extension handshake from the other end is received + virtual bool on_extension_handshake(lazy_entry const& h) + { + m_message_index = 0; + if (h.type() != lazy_entry::dict_t) return false; + lazy_entry const* messages = h.dict_find("m"); + if (!messages || messages->type() != lazy_entry::dict_t) return false; + + int index = messages->dict_find_int_value("lt_tex", -1); + if (index == -1) return false; + m_message_index = index; + + // if we have the same tracker list, don't bother sending the + // full list. Just send deltas + std::string tracker_list_hash = h.dict_find_string_value("tr"); + if (tracker_list_hash.size() == 20 + && sha1_hash(tracker_list_hash) == m_tp.list_hash()) + { + m_full_list = false; + } + return true; + } + + virtual bool on_extended(int length + , int extended_msg, buffer::const_interval body) + { + if (extended_msg != 3) return false; + if (m_message_index == 0) return false; + if (!m_pc.packet_finished()) return true; + + lazy_entry msg; + int ret = lazy_bdecode(body.begin, body.end, msg); + if (ret != 0 || msg.type() != lazy_entry::dict_t) + { + m_pc.disconnect("invalid bencoding in lt_tracker message", 2); + return true; + } + + lazy_entry const* added = msg.dict_find_list("added"); + +#ifdef TORRENT_VERBOSE_LOGGING + std::stringstream log_line; + log_line << time_now_string() << " <== LT_TEX [ " + "added: "; +#endif + + // invalid tex message + if (added == 0) + { +#ifdef TORRENT_VERBOSE_LOGGING + (*m_pc.m_logger) << time_now_string() << " <== LT_TEX [ NOT A DICTIONARY ]\n"; +#endif + return true; + } + + for (int i = 0; i < added->list_size(); ++i) + { + announce_entry e(added->list_string_value_at(i)); + if (e.url.empty()) continue; + e.fail_limit = 3; + m_torrent.add_tracker(e); +#ifdef TORRENT_VERBOSE_LOGGING + log_line << e.url << " "; +#endif + } +#ifdef TORRENT_VERBOSE_LOGGING + log_line << "]\n"; + (*m_pc.m_logger) << log_line.str(); +#endif + return true; + } + + virtual void tick() + { + if (!m_message_index) return; // no handshake yet + if (++m_2_minutes <= 120) return; + m_2_minutes = 0; + + if (m_full_list) + { + send_full_tex_list(); + m_full_list = false; + } + else + { + send_lt_tex_diff(); + } + } + + private: + + void send_lt_tex_diff() + { + // if there's no change in out tracker set, don't send anything + if (m_tp.num_updates() == 0) return; + + std::vector const& tex_msg = m_tp.get_lt_tex_msg(); + + buffer::interval i = m_pc.allocate_send_buffer(6 + tex_msg.size()); + + detail::write_uint32(1 + 1 + tex_msg.size(), i.begin); + detail::write_uint8(bt_peer_connection::msg_extended, i.begin); + detail::write_uint8(m_message_index, i.begin); + std::copy(tex_msg.begin(), tex_msg.end(), i.begin); + i.begin += tex_msg.size(); + + TORRENT_ASSERT(i.begin == i.end); + m_pc.setup_send(); + } + + void send_full_tex_list() const + { + if (m_tp.trackers().empty()) return; + +#ifdef TORRENT_VERBOSE_LOGGING + std::stringstream log_line; + log_line << time_now_string() << " ==> LT_TEX [ " + "added: "; +#endif + entry tex; + entry::list_type& added = tex["added"].list(); + for (std::vector::const_iterator i = m_tp.trackers().begin() + , end(m_tp.trackers().end()); i != end; ++i) + { + if (!send_tracker(*i)) continue; + added.push_back(i->url); +#ifdef TORRENT_VERBOSE_LOGGING + log_line << i->url << " "; +#endif + } + std::vector tex_msg; + bencode(std::back_inserter(tex_msg), tex); + +#ifdef TORRENT_VERBOSE_LOGGING + log_line << "]\n"; + (*m_pc.m_logger) << log_line.str(); +#endif + + buffer::interval i = m_pc.allocate_send_buffer(6 + tex_msg.size()); + + detail::write_uint32(1 + 1 + tex_msg.size(), i.begin); + detail::write_uint8(bt_peer_connection::msg_extended, i.begin); + detail::write_uint8(m_message_index, i.begin); + std::copy(tex_msg.begin(), tex_msg.end(), i.begin); + i.begin += tex_msg.size(); + + TORRENT_ASSERT(i.begin == i.end); + m_pc.setup_send(); + } + + // this is the message index the remote peer uses + // for metadata extension messages. + int m_message_index; + + torrent& m_torrent; + bt_peer_connection& m_pc; + lt_tracker_plugin& m_tp; + + int m_2_minutes; + bool m_full_list; + }; + + boost::shared_ptr lt_tracker_plugin::new_connection( + peer_connection* pc) + { + bt_peer_connection* c = dynamic_cast(pc); + if (!c) return boost::shared_ptr(); + return boost::shared_ptr(new lt_tracker_peer_plugin(m_torrent, *c, *this)); + } + +} } + +namespace libtorrent +{ + + boost::shared_ptr create_lt_trackers_plugin(torrent* t, void*) + { + if (t->valid_metadata() && t->torrent_file().priv()) return boost::shared_ptr(); + return boost::shared_ptr(new lt_tracker_plugin(*t)); + } + +} + + diff --git a/src/metadata_transfer.cpp b/src/metadata_transfer.cpp index 99857f9bd..17f143c50 100644 --- a/src/metadata_transfer.cpp +++ b/src/metadata_transfer.cpp @@ -310,8 +310,7 @@ namespace libtorrent { namespace // abort if the peer doesn't support the metadata extension if (m_message_index == 0) return; - // only send metadata if the torrent is non-private - if (m_torrent.valid_metadata() && !m_torrent.torrent_file().priv()) + if (m_torrent.valid_metadata()) { std::pair offset = req_to_offset(req, (int)m_tp.metadata().left()); @@ -595,6 +594,8 @@ namespace libtorrent boost::shared_ptr create_metadata_plugin(torrent* t, void*) { + // don't add this extension if the torrent is private + if (t->valid_metadata() && t->torrent_file().priv()) return boost::shared_ptr(); return boost::shared_ptr(new metadata_plugin(*t)); } diff --git a/src/session.cpp b/src/session.cpp index 8a5a87b8e..cb8ad948b 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -58,6 +58,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/extensions/ut_pex.hpp" #include "libtorrent/extensions/ut_metadata.hpp" +#include "libtorrent/extensions/lt_trackers.hpp" #include "libtorrent/extensions/smart_ban.hpp" #include "libtorrent/peer_id.hpp" #include "libtorrent/torrent_info.hpp" @@ -148,6 +149,7 @@ namespace libtorrent { add_extension(create_ut_pex_plugin); add_extension(create_ut_metadata_plugin); + add_extension(create_lt_trackers_plugin); add_extension(create_smart_ban_plugin); } #endif @@ -188,6 +190,7 @@ namespace libtorrent { add_extension(create_ut_pex_plugin); add_extension(create_ut_metadata_plugin); + add_extension(create_lt_trackers_plugin); add_extension(create_smart_ban_plugin); } #endif diff --git a/src/torrent.cpp b/src/torrent.cpp index 605587fad..eda4420a7 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -303,6 +303,7 @@ namespace libtorrent if (tracker_url) { m_trackers.push_back(announce_entry(tracker_url)); + m_trackers.back().fail_limit = 0; m_torrent_file->add_tracker(tracker_url); } } @@ -945,6 +946,7 @@ namespace libtorrent TORRENT_ASSERT(m_currently_trying_tracker >= 0); TORRENT_ASSERT(m_currently_trying_tracker < int(m_trackers.size())); req.url = m_trackers[m_currently_trying_tracker].url; + TORRENT_ASSERT(m_trackers[m_currently_trying_tracker].can_announce()); // if we are aborting. we don't want any new peers req.num_want = (req.event == tracker_request::stopped) ?0:m_settings.num_want; @@ -1051,6 +1053,8 @@ namespace libtorrent TORRENT_ASSERT(m_currently_trying_tracker < int(m_trackers.size())); TORRENT_ASSERT(m_trackers[m_currently_trying_tracker].url == r.url); + m_trackers[m_currently_trying_tracker].verified = true; + m_last_working_tracker = prioritize_tracker(m_currently_trying_tracker); m_currently_trying_tracker = 0; @@ -1113,6 +1117,16 @@ namespace libtorrent get_handle(), peer_list.size(), r.url)); } m_got_tracker_response = true; + + // when the tracker succeeds, reset the fails-in-a-row counter + if (m_currently_trying_tracker != -1) + { + TORRENT_ASSERT(m_currently_trying_tracker >= 0); + TORRENT_ASSERT(m_currently_trying_tracker < int(m_trackers.size())); + TORRENT_ASSERT(m_trackers[m_currently_trying_tracker].url == r.url); + + m_trackers[m_currently_trying_tracker].fails = 0; + } } void torrent::on_peer_name_lookup(error_code const& e, tcp::resolver::iterator host @@ -3477,7 +3491,8 @@ namespace libtorrent do { ++m_currently_trying_tracker; - } while (m_currently_trying_tracker < m_trackers.size()); + } while (m_currently_trying_tracker < m_trackers.size() + && !m_trackers[m_currently_trying_tracker].can_announce()); if (m_currently_trying_tracker < int(m_trackers.size())) { @@ -4787,6 +4802,14 @@ namespace libtorrent m_ses.m_alerts.post_alert(tracker_error_alert(get_handle() , m_failed_trackers + 1, 0, r.url, "tracker timed out")); } + if (m_currently_trying_tracker != -1) + { + TORRENT_ASSERT(m_currently_trying_tracker >= 0); + TORRENT_ASSERT(m_currently_trying_tracker < int(m_trackers.size())); + TORRENT_ASSERT(m_trackers[m_currently_trying_tracker].url == r.url); + + ++m_trackers[m_currently_trying_tracker].fails; + } } else if (r.kind == tracker_request::scrape_request) { @@ -4821,6 +4844,14 @@ namespace libtorrent m_ses.m_alerts.post_alert(tracker_error_alert(get_handle() , m_failed_trackers + 1, response_code, r.url, str)); } + if (m_currently_trying_tracker != -1) + { + TORRENT_ASSERT(m_currently_trying_tracker >= 0); + TORRENT_ASSERT(m_currently_trying_tracker < int(m_trackers.size())); + TORRENT_ASSERT(m_trackers[m_currently_trying_tracker].url == r.url); + + ++m_trackers[m_currently_trying_tracker].fails; + } } else if (r.kind == tracker_request::scrape_request) { diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 8bba9241e..4afd344a9 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -539,6 +539,7 @@ namespace libtorrent announce_entry e(tier->list_string_value_at(k)); if (e.url.empty()) continue; e.tier = j; + e.fail_limit = 0; m_urls.push_back(e); } } @@ -563,6 +564,7 @@ namespace libtorrent if (m_urls.empty()) { announce_entry e(torrent_file.dict_find_string_value("announce")); + e.fail_limit = 0; if (!e.url.empty()) m_urls.push_back(e); } diff --git a/test/Jamfile b/test/Jamfile index 9fbabe4ab..0017de7cf 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -45,6 +45,7 @@ test-suite libtorrent : [ run test_ip_filter.cpp ] [ run test_hasher.cpp ] [ run test_metadata_extension.cpp ] + [ run test_trackers_extension.cpp ] [ run test_swarm.cpp ] [ run test_lsd.cpp ] [ run test_pex.cpp ] diff --git a/test/test_metadata_extension.cpp b/test/test_metadata_extension.cpp index 1c42ead74..3ef2dfee4 100644 --- a/test/test_metadata_extension.cpp +++ b/test/test_metadata_extension.cpp @@ -50,8 +50,8 @@ void test_transfer(bool clear_files, bool disconnect { using namespace libtorrent; - session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48100, 49000)); - session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49100, 50000)); + session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48100, 49000), "0.0.0.0", 0); + session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49100, 50000), "0.0.0.0", 0); ses1.add_extension(constructor); ses2.add_extension(constructor); torrent_handle tor1; diff --git a/test/test_trackers_extension.cpp b/test/test_trackers_extension.cpp new file mode 100644 index 000000000..455b75080 --- /dev/null +++ b/test/test_trackers_extension.cpp @@ -0,0 +1,79 @@ +/* + +Copyright (c) 2008, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "libtorrent/session.hpp" +#include "libtorrent/hasher.hpp" +#include +#include +#include +#include + +#include "test.hpp" +#include "setup_transfer.hpp" +#include "libtorrent/extensions/metadata_transfer.hpp" +#include "libtorrent/extensions/ut_metadata.hpp" +#include "libtorrent/extensions/lt_trackers.hpp" + +using boost::filesystem::remove_all; +using boost::tuples::ignore; + +void test_main() +{ + using namespace libtorrent; + + session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48130, 49000), "0.0.0.0", 0); + session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49130, 50000), "0.0.0.0", 0); + ses1.add_extension(create_lt_trackers_plugin); + ses2.add_extension(create_lt_trackers_plugin); + + add_torrent_params atp; + atp.info_hash = sha1_hash("12345678901234567890"); + atp.save_path = "./"; + torrent_handle tor1 = ses1.add_torrent(atp); + atp.tracker_url = "http://test.non-existent.com/announce"; + torrent_handle tor2 = ses2.add_torrent(atp); + tor2.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), ses1.listen_port())); + + for (int i = 0; i < 130; ++i) + { + // make sure this function can be called on + // torrents without metadata + print_alerts(ses1, "ses1", false, true); + print_alerts(ses2, "ses2", false, true); + + if (tor1.trackers().size() == 1) break; + test_sleep(1000); + } + + TEST_CHECK(tor1.trackers().size() == 1); +} +