changed how trackers are handled. Implements #297 by setting session_settings::announce_to_all_trackers to true

This commit is contained in:
Arvid Norberg 2008-11-29 08:38:40 +00:00
parent acbdbfc1ef
commit d1a2b774e6
10 changed files with 330 additions and 212 deletions

View File

@ -1482,11 +1482,42 @@ ones with lower tier will always be tried before the one with higher tier number
std::string url; std::string url;
boost::uint8_t tier; boost::uint8_t tier;
boost::uint8_t fail_limit; boost::uint8_t fail_limit;
boost::uint8_t fails;
enum tracker_source
{
source_torrent = 1,
source_client = 2,
source_magnet_link = 4,
source_tex = 8
};
boost::uint8_t source;
bool verified:1;
bool updating:1;
bool start_sent:1;
bool complete_sent:1;
}; };
``fail_limit`` is the max number of failures to announce to this tracker in ``fail_limit`` is the max number of failures to announce to this tracker in
a row, before this tracker is not used anymore. a row, before this tracker is not used anymore.
``fails`` is the number of times in a row we have failed to announce to this
tracker.
``source`` is a bitmask specifying which sources we got this tracker from.
``verified`` is set to true the first time we receive a valid response
from this tracker.
``updating`` is true while we're waiting for a response from the tracker.
``start_sent`` is set to true when we get a valid response from an announce
with event=started. If it is set, we won't send start in the subsequent
announces.
``complete_sent`` is set to true when we send a event=completed.
total_size() piece_length() piece_size() num_pieces() total_size() piece_length() piece_size() num_pieces()
----------------------------------------------------- -----------------------------------------------------
@ -3057,6 +3088,8 @@ that will be sent to the tracker. The user-agent is a good way to identify your
int auto_manage_startup; int auto_manage_startup;
bool rate_limit_ip_overhead; bool rate_limit_ip_overhead;
bool announce_to_all_trackers;
}; };
``user_agent`` this is the client identification to the tracker. ``user_agent`` this is the client identification to the tracker.
@ -3341,6 +3374,14 @@ have a fair chance to start downloading.
If ``rate_limit_ip_overhead`` is set to true, the estimated TCP/IP overhead is If ``rate_limit_ip_overhead`` is set to true, the estimated TCP/IP overhead is
drained from the rate limiters, to avoid exceeding the limits with the total traffic drained from the rate limiters, to avoid exceeding the limits with the total traffic
``announce_to_all_trackers`` controls how multi tracker torrents are
treated. If this is set to true, all trackers in the same tier are
announced to in parallel. If all trackers in tier 0 fails, all trackers
in tier 1 are announced as well. This is the uTorrent behavior. If it's
set to false, the behavior is as defined by the multi tracker
specification. It defaults to false, which is the same behavior previous
versions of libtorrent has had as well.
pe_settings pe_settings
=========== ===========

View File

@ -154,6 +154,7 @@ void clear_home()
#endif #endif
bool print_trackers = false;
bool print_peers = false; bool print_peers = false;
bool print_log = false; bool print_log = false;
bool print_downloads = false; bool print_downloads = false;
@ -849,6 +850,7 @@ int main(int ac, char* av[])
settings.user_agent = "client_test/" LIBTORRENT_VERSION; settings.user_agent = "client_test/" LIBTORRENT_VERSION;
settings.urlseed_wait_retry = wait_retry; settings.urlseed_wait_retry = wait_retry;
settings.announce_to_all_trackers = true;
settings.outgoing_ports.first = bind_port_start; settings.outgoing_ports.first = bind_port_start;
settings.outgoing_ports.second = bind_port_end; settings.outgoing_ports.second = bind_port_end;
@ -1214,6 +1216,7 @@ int main(int ac, char* av[])
} }
// toggle displays // toggle displays
if (c == 't') print_trackers = !print_trackers;
if (c == 'i') print_peers = !print_peers; if (c == 'i') print_peers = !print_peers;
if (c == 'l') print_log = !print_log; if (c == 'l') print_log = !print_log;
if (c == 'd') print_downloads = !print_downloads; if (c == 'd') print_downloads = !print_downloads;
@ -1348,7 +1351,7 @@ int main(int ac, char* av[])
<< std::hex << s.seed_rank << std::dec << " " << std::hex << s.seed_rank << std::dec << " "
<< s.last_scrape << "\n" << esc("0"); << s.last_scrape << "\n" << esc("0");
if (torrent_index != active_torrent && s.state != torrent_status::seeding) continue; if (torrent_index != active_torrent && s.state == torrent_status::seeding) continue;
char const* progress_bar_color = "33"; // yellow char const* progress_bar_color = "33"; // yellow
if (s.state == torrent_status::checking_files if (s.state == torrent_status::checking_files
|| s.state == torrent_status::downloading_metadata) || s.state == torrent_status::downloading_metadata)
@ -1388,6 +1391,7 @@ int main(int ac, char* av[])
<< to_string(t.seconds(), 2) << esc("0") << " "; << to_string(t.seconds(), 2) << esc("0") << " ";
out << "tracker: " << esc("36") << s.current_tracker << esc("0") << "\n"; out << "tracker: " << esc("36") << s.current_tracker << esc("0") << "\n";
if (torrent_index != active_torrent) continue;
active_handle = h; active_handle = h;
} }
@ -1451,6 +1455,23 @@ int main(int ac, char* av[])
if (print_peers && !peers.empty()) if (print_peers && !peers.empty())
print_peer_info(out, peers); print_peer_info(out, peers);
if (print_trackers)
{
std::vector<announce_entry> tr = h.trackers();
ptime now = time_now();
for (std::vector<announce_entry>::iterator i = tr.begin()
, end(tr.end()); i != end; ++i)
{
std::string url = i->url;
url.resize(55, ' ');
out << to_string(i->tier, 2) << " " << url << " "
<< to_string(i->fails, 3) << " " << (i->verified?"OK ":"- ");
if (i->updating) out << "updating";
else out << to_string(total_seconds(i->next_announce - now), 8);
out << "\n";
}
}
if (print_downloads) if (print_downloads)
{ {
h.get_download_queue(queue); h.get_download_queue(queue);

View File

@ -144,6 +144,7 @@ namespace libtorrent
, prioritize_partial_pieces(false) , prioritize_partial_pieces(false)
, auto_manage_startup(120) , auto_manage_startup(120)
, rate_limit_ip_overhead(true) , rate_limit_ip_overhead(true)
, announce_to_all_trackers(false)
{} {}
// this is the user agent that will be sent to the tracker // this is the user agent that will be sent to the tracker
@ -456,6 +457,11 @@ namespace libtorrent
// drained from the rate limiters, to avoid exceeding // drained from the rate limiters, to avoid exceeding
// the limits with the total traffic // the limits with the total traffic
bool rate_limit_ip_overhead; bool rate_limit_ip_overhead;
// if set to true, multi tracker torrents are treated
// the same way uTorrent treats them. It defaults to
// false in order to comply with the extension definition.
bool announce_to_all_trackers;
}; };
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT

View File

@ -81,6 +81,8 @@ namespace libtorrent
class piece_manager; class piece_manager;
struct torrent_plugin; struct torrent_plugin;
struct bitfield; struct bitfield;
struct announce_entry;
struct tracker_request;
namespace aux namespace aux
{ {
@ -409,6 +411,8 @@ namespace libtorrent
// announce ourself at the last time we tried to announce // announce ourself at the last time we tried to announce
const tcp::endpoint& current_tracker() const; const tcp::endpoint& current_tracker() const;
announce_entry* find_tracker(tracker_request const& r);
// -------------------------------------------- // --------------------------------------------
// PIECE MANAGEMENT // PIECE MANAGEMENT
@ -586,7 +590,7 @@ namespace libtorrent
{ return m_trackers; } { return m_trackers; }
void replace_trackers(std::vector<announce_entry> const& urls); void replace_trackers(std::vector<announce_entry> const& urls);
void add_tracker(announce_entry const& urls); void add_tracker(announce_entry const& url);
torrent_handle get_handle(); torrent_handle get_handle();
@ -656,8 +660,9 @@ namespace libtorrent
void on_piece_verified(int ret, disk_io_job const& j void on_piece_verified(int ret, disk_io_job const& j
, boost::function<void(int)> f); , boost::function<void(int)> f);
void try_next_tracker(tracker_request const& req);
int prioritize_tracker(int tracker_index); int prioritize_tracker(int tracker_index);
int deprioritize_tracker(int tracker_index);
void on_country_lookup(error_code const& error, tcp::resolver::iterator i void on_country_lookup(error_code const& error, tcp::resolver::iterator i
, boost::intrusive_ptr<peer_connection> p) const; , boost::intrusive_ptr<peer_connection> p) const;
bool request_bandwidth_from_session(int channel) const; bool request_bandwidth_from_session(int channel) const;
@ -718,9 +723,6 @@ namespace libtorrent
// the object. // the object.
piece_manager* m_storage; piece_manager* m_storage;
// the time of next tracker announce
ptime m_next_tracker_announce;
#ifndef NDEBUG #ifndef NDEBUG
public: public:
#endif #endif
@ -757,7 +759,7 @@ namespace libtorrent
// used for tracker announces // used for tracker announces
deadline_timer m_tracker_timer; deadline_timer m_tracker_timer;
void restart_tracker_timer(ptime announce_at); void update_tracker_timer();
static void on_tracker_announce_disp(boost::weak_ptr<torrent> p static void on_tracker_announce_disp(boost::weak_ptr<torrent> p
, error_code const& e); , error_code const& e);
@ -895,10 +897,6 @@ namespace libtorrent
// torrent object, these points are called connect_points. // torrent object, these points are called connect_points.
int m_deficit_counter; int m_deficit_counter;
// the number number of seconds between requests
// from the tracker
boost::int16_t m_duration;
// the sequence number for this torrent, this is a // the sequence number for this torrent, this is a
// monotonically increasing number for each added torrent // monotonically increasing number for each added torrent
boost::int16_t m_sequence_number; boost::int16_t m_sequence_number;
@ -906,10 +904,6 @@ namespace libtorrent
// the index to the last tracker that worked // the index to the last tracker that worked
boost::int8_t m_last_working_tracker; boost::int8_t m_last_working_tracker;
// the tracker that is currently (or was last)
// tried
boost::int8_t m_currently_trying_tracker;
// the number of connection attempts that has // the number of connection attempts that has
// failed in a row, this is currently used to // failed in a row, this is currently used to
// determine the timeout until next try. // determine the timeout until next try.
@ -979,27 +973,30 @@ namespace libtorrent
// this is true while tracker announcing is enabled // this is true while tracker announcing is enabled
// is is disabled while paused and checking files // is is disabled while paused and checking files
bool m_announcing:1; bool m_announcing:1;
// this is true if event start has been sent to the tracker
bool m_start_sent:1;
// this is true if event completed has been sent to the tracker
bool m_complete_sent:1;
}; };
inline ptime torrent::next_announce() const inline ptime torrent::next_announce() const
{ {
return m_next_tracker_announce; return m_tracker_timer.expires_at();
} }
inline void torrent::force_tracker_request() inline void torrent::force_tracker_request()
{ {
if (!is_paused()) announce_with_tracker(); if (is_paused()) return;
ptime now = time_now();
for (std::vector<announce_entry>::iterator i = m_trackers.begin()
, end(m_trackers.end()); i != end; ++i)
i->next_announce = now;
update_tracker_timer();
} }
inline void torrent::force_tracker_request(ptime t) inline void torrent::force_tracker_request(ptime t)
{ {
if (!is_paused()) restart_tracker_timer(t); if (is_paused()) return;
for (std::vector<announce_entry>::iterator i = m_trackers.begin()
, end(m_trackers.end()); i != end; ++i)
i->next_announce = t;
update_tracker_timer();
} }
inline void torrent::set_tracker_login( inline void torrent::set_tracker_login(

View File

@ -329,7 +329,7 @@ namespace libtorrent
void clear_error() const; void clear_error() const;
std::vector<announce_entry> const& trackers() const; std::vector<announce_entry> trackers() const;
void replace_trackers(std::vector<announce_entry> const&) const; void replace_trackers(std::vector<announce_entry> const&) const;
void add_tracker(announce_entry const&) const; void add_tracker(announce_entry const&) const;

View File

@ -66,15 +66,34 @@ namespace libtorrent
namespace gr = boost::gregorian; namespace gr = boost::gregorian;
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
enum
{
// wait 60 seconds before retrying a failed tracker
tracker_retry_delay_min = 10
// when tracker_failed_max trackers
// has failed, wait 60 minutes instead
, tracker_retry_delay_max = 60 * 60
};
struct TORRENT_EXPORT announce_entry struct TORRENT_EXPORT announce_entry
{ {
announce_entry(std::string const& u) announce_entry(std::string const& u)
: url(u), tier(0) : url(u)
, fail_limit(3), fails(0) , tier(0)
, fail_limit(3)
, fails(0)
, source(0)
, verified(false) , verified(false)
, updating(false)
, start_sent(false)
, complete_sent(false)
{} {}
std::string url; std::string url;
// the time of next tracker announce
ptime next_announce;
boost::uint8_t tier; boost::uint8_t tier;
// the number of times this tracker can fail // the number of times this tracker can fail
// in a row before it's removed. 0 means unlimited // in a row before it's removed. 0 means unlimited
@ -83,12 +102,56 @@ namespace libtorrent
// the number of times in a row this tracker has failed // the number of times in a row this tracker has failed
boost::uint8_t fails; boost::uint8_t fails;
enum tracker_source
{
source_torrent = 1,
source_client = 2,
source_magnet_link = 4,
source_tex = 8
};
// where did we get this tracker from
boost::uint8_t source;
// is set to true if we have ever received a response from // is set to true if we have ever received a response from
// this tracker // this tracker
bool verified:1; bool verified:1;
bool can_announce() const // true if we're currently trying to announce with
{ return fails < fail_limit || fail_limit == 0; } // this tracker
bool updating:1;
// this is true if event start has been sent to the tracker
bool start_sent:1;
// this is true if event completed has been sent to the tracker
bool complete_sent:1;
void reset()
{
start_sent = false;
next_announce = min_time();
}
void failed()
{
++fails;
int delay = (std::min)(tracker_retry_delay_min + int(fails) * int(fails) * tracker_retry_delay_min
, int(tracker_retry_delay_max));
next_announce = time_now() + seconds(delay);
updating = false;
}
bool can_announce(ptime now) const
{
return now >= next_announce
&& (fails < fail_limit || fail_limit == 0)
&& !updating;
}
bool is_working() const
{
return fails == 0;
}
}; };
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS

View File

@ -221,6 +221,7 @@ namespace libtorrent { namespace
announce_entry e(added->list_string_value_at(i)); announce_entry e(added->list_string_value_at(i));
if (e.url.empty()) continue; if (e.url.empty()) continue;
e.fail_limit = 3; e.fail_limit = 3;
e.source = announce_entry::source_tex;
m_torrent.add_tracker(e); m_torrent.add_tracker(e);
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
log_line << e.url << " "; log_line << e.url << " ";

View File

@ -86,16 +86,6 @@ using libtorrent::aux::session_impl;
namespace namespace
{ {
enum
{
// wait 60 seconds before retrying a failed tracker
tracker_retry_delay_min = 60
// when tracker_failed_max trackers
// has failed, wait 10 minutes instead
, tracker_retry_delay_max = 10 * 60
, tracker_failed_max = 5
};
struct find_peer_by_ip struct find_peer_by_ip
{ {
find_peer_by_ip(tcp::endpoint const& a, const torrent* t) find_peer_by_ip(tcp::endpoint const& a, const torrent* t)
@ -156,7 +146,6 @@ namespace libtorrent
, m_last_scrape(min_time()) , m_last_scrape(min_time())
, m_torrent_file(tf) , m_torrent_file(tf)
, m_storage(0) , m_storage(0)
, m_next_tracker_announce(time_now())
, m_host_resolver(ses.m_io_service) , m_host_resolver(ses.m_io_service)
, m_lsd_announce_timer(ses.m_io_service) , m_lsd_announce_timer(ses.m_io_service)
, m_tracker_timer(ses.m_io_service) , m_tracker_timer(ses.m_io_service)
@ -182,11 +171,8 @@ namespace libtorrent
, m_complete(-1) , m_complete(-1)
, m_incomplete(-1) , m_incomplete(-1)
, m_deficit_counter(0) , m_deficit_counter(0)
, m_duration(1800)
, m_sequence_number(seq) , m_sequence_number(seq)
, m_last_working_tracker(-1) , m_last_working_tracker(-1)
, m_currently_trying_tracker(-1)
, m_failed_trackers(0)
, m_time_scaler(0) , m_time_scaler(0)
, m_abort(false) , m_abort(false)
, m_paused(paused) , m_paused(paused)
@ -201,8 +187,6 @@ namespace libtorrent
, m_has_incoming(false) , m_has_incoming(false)
, m_files_checked(false) , m_files_checked(false)
, m_announcing(false) , m_announcing(false)
, m_start_sent(false)
, m_complete_sent(false)
{ {
if (resume_data) m_resume_data.swap(*resume_data); if (resume_data) m_resume_data.swap(*resume_data);
@ -237,7 +221,6 @@ namespace libtorrent
, m_last_scrape(min_time()) , m_last_scrape(min_time())
, m_torrent_file(new torrent_info(info_hash)) , m_torrent_file(new torrent_info(info_hash))
, m_storage(0) , m_storage(0)
, m_next_tracker_announce(time_now())
, m_host_resolver(ses.m_io_service) , m_host_resolver(ses.m_io_service)
, m_lsd_announce_timer(ses.m_io_service) , m_lsd_announce_timer(ses.m_io_service)
, m_tracker_timer(ses.m_io_service) , m_tracker_timer(ses.m_io_service)
@ -262,11 +245,8 @@ namespace libtorrent
, m_complete(-1) , m_complete(-1)
, m_incomplete(-1) , m_incomplete(-1)
, m_deficit_counter(0) , m_deficit_counter(0)
, m_duration(1800)
, m_sequence_number(seq) , m_sequence_number(seq)
, m_last_working_tracker(-1) , m_last_working_tracker(-1)
, m_currently_trying_tracker(-1)
, m_failed_trackers(0)
, m_time_scaler(0) , m_time_scaler(0)
, m_abort(false) , m_abort(false)
, m_paused(paused) , m_paused(paused)
@ -281,8 +261,6 @@ namespace libtorrent
, m_has_incoming(false) , m_has_incoming(false)
, m_files_checked(false) , m_files_checked(false)
, m_announcing(false) , m_announcing(false)
, m_start_sent(false)
, m_complete_sent(false)
{ {
if (resume_data) m_resume_data.swap(*resume_data); if (resume_data) m_resume_data.swap(*resume_data);
@ -304,6 +282,7 @@ namespace libtorrent
{ {
m_trackers.push_back(announce_entry(tracker_url)); m_trackers.push_back(announce_entry(tracker_url));
m_trackers.back().fail_limit = 0; m_trackers.back().fail_limit = 0;
m_trackers.back().source = announce_entry::source_magnet_link;
m_torrent_file->add_tracker(tracker_url); m_torrent_file->add_tracker(tracker_url);
} }
} }
@ -355,7 +334,12 @@ namespace libtorrent
if (m_torrent_file->is_valid() && m_torrent_file->priv()) return false; if (m_torrent_file->is_valid() && m_torrent_file->priv()) return false;
if (m_trackers.empty()) return true; if (m_trackers.empty()) return true;
return m_failed_trackers > 0 || !m_ses.settings().use_dht_as_fallback; int verified_trackers = 0;
for (std::vector<announce_entry>::const_iterator i = m_trackers.begin()
, end(m_trackers.end()); i != end; ++i)
if (i->verified) ++verified_trackers;
return verified_trackers == 0 || !m_settings.use_dht_as_fallback;
} }
#endif #endif
@ -919,16 +903,8 @@ namespace libtorrent
if (m_trackers.empty()) return; if (m_trackers.empty()) return;
restart_tracker_timer(time_now() + seconds(tracker_retry_delay_max));
if (m_abort) e = tracker_request::stopped; if (m_abort) e = tracker_request::stopped;
if (e == tracker_request::none)
{
if (!m_start_sent) e = tracker_request::started;
if (!m_complete_sent && is_seed()) e = tracker_request::completed;
}
tracker_request req; tracker_request req;
req.info_hash = m_torrent_file->info_hash(); req.info_hash = m_torrent_file->info_hash();
req.pid = m_ses.get_peer_id(); req.pid = m_ses.get_peer_id();
@ -942,11 +918,6 @@ namespace libtorrent
if (ep != tcp::endpoint()) if (ep != tcp::endpoint())
req.ipv6 = ep.address().to_string(ec); req.ipv6 = ep.address().to_string(ec);
if (m_currently_trying_tracker == -1) m_currently_trying_tracker = 0;
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 // if we are aborting. we don't want any new peers
req.num_want = (req.event == tracker_request::stopped) req.num_want = (req.event == tracker_request::stopped)
?0:m_settings.num_want; ?0:m_settings.num_want;
@ -955,6 +926,28 @@ namespace libtorrent
?0:m_ses.m_listen_sockets.front().external_port; ?0:m_ses.m_listen_sockets.front().external_port;
req.key = m_ses.m_key; req.key = m_ses.m_key;
ptime now = time_now();
int tier = INT_MAX;
for (int i = 0; i < m_trackers.size(); ++i)
{
announce_entry& ae = m_trackers[i];
if (ae.tier > tier) break;
if (ae.is_working()) tier = ae.tier;
if (!ae.can_announce(now))
{
if (ae.is_working() && !m_settings.announce_to_all_trackers) break;
continue;
}
req.url = ae.url;
req.event = e;
if (req.event == tracker_request::none)
{
if (!ae.start_sent) req.event = tracker_request::started;
if (!ae.complete_sent && is_seed()) req.event = tracker_request::completed;
}
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
if (m_abort) if (m_abort)
{ {
@ -967,12 +960,17 @@ namespace libtorrent
m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
, tracker_login(), m_ses.m_listen_interface.address() , tracker_login(), m_ses.m_listen_interface.address()
, m_abort?boost::shared_ptr<torrent>():shared_from_this()); , m_abort?boost::shared_ptr<torrent>():shared_from_this());
ae.updating = true;
if (m_ses.m_alerts.should_post<tracker_announce_alert>()) if (m_ses.m_alerts.should_post<tracker_announce_alert>())
{ {
m_ses.m_alerts.post_alert( m_ses.m_alerts.post_alert(
tracker_announce_alert(get_handle(), req.url, req.event)); tracker_announce_alert(get_handle(), req.url, req.event));
} }
if (ae.is_working() && !m_settings.announce_to_all_trackers) break;
}
update_tracker_timer();
} }
void torrent::scrape_tracker() void torrent::scrape_tracker()
@ -980,7 +978,6 @@ namespace libtorrent
if (m_trackers.empty()) return; if (m_trackers.empty()) return;
int i = m_last_working_tracker; int i = m_last_working_tracker;
if (i == -1) i = m_currently_trying_tracker;
if (i == -1) i = 0; if (i == -1) i = 0;
tracker_request req; tracker_request req;
@ -1037,42 +1034,36 @@ namespace libtorrent
if (external_ip != address()) if (external_ip != address())
m_ses.set_external_address(external_ip); m_ses.set_external_address(external_ip);
if (!m_start_sent && r.event == tracker_request::started) ptime now = time_now();
m_start_sent = true;
if (!m_complete_sent && r.event == tracker_request::completed)
m_complete_sent = true;
m_failed_trackers = 0; if (interval < m_settings.min_announce_interval)
interval = m_settings.min_announce_interval;
if (interval < m_ses.settings().min_announce_interval) announce_entry* ae = find_tracker(r);
interval = m_ses.settings().min_announce_interval; if (ae)
if (m_currently_trying_tracker != -1)
{ {
TORRENT_ASSERT(m_currently_trying_tracker >= 0); if (!ae->start_sent && r.event == tracker_request::started)
TORRENT_ASSERT(m_currently_trying_tracker < int(m_trackers.size())); ae->start_sent = true;
TORRENT_ASSERT(m_trackers[m_currently_trying_tracker].url == r.url); if (!ae->complete_sent && r.event == tracker_request::completed)
ae->complete_sent = true;
m_trackers[m_currently_trying_tracker].verified = true; ae->verified = true;
ae->updating = false;
m_last_working_tracker ae->fails = 0;
= prioritize_tracker(m_currently_trying_tracker); ae->next_announce = now + seconds(interval);
m_currently_trying_tracker = 0; int tracker_index = ae - &m_trackers[0];
TORRENT_ASSERT(m_trackers[m_currently_trying_tracker].url == r.url); m_last_working_tracker = prioritize_tracker(tracker_index);
} }
update_tracker_timer();
m_duration = interval;
restart_tracker_timer(time_now() + seconds(m_duration));
if (complete >= 0) m_complete = complete; if (complete >= 0) m_complete = complete;
if (incomplete >= 0) m_incomplete = incomplete; if (incomplete >= 0) m_incomplete = incomplete;
if (complete >= 0 && incomplete >= 0) if (complete >= 0 && incomplete >= 0)
m_last_scrape = time_now(); m_last_scrape = now;
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
std::stringstream s; std::stringstream s;
s << "TRACKER RESPONSE:\n" s << "TRACKER RESPONSE:\n"
"interval: " << m_duration << "\n" "interval: " << interval << "\n"
"peers:\n"; "peers:\n";
for (std::vector<peer_entry>::const_iterator i = peer_list.begin(); for (std::vector<peer_entry>::const_iterator i = peer_list.begin();
i != peer_list.end(); ++i) i != peer_list.end(); ++i)
@ -1117,16 +1108,6 @@ namespace libtorrent
get_handle(), peer_list.size(), r.url)); get_handle(), peer_list.size(), r.url));
} }
m_got_tracker_response = true; 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 void torrent::on_peer_name_lookup(error_code const& e, tcp::resolver::iterator host
@ -2083,7 +2064,10 @@ namespace libtorrent
{ {
m_trackers = urls; m_trackers = urls;
m_last_working_tracker = -1; m_last_working_tracker = -1;
m_currently_trying_tracker = -1; for (std::vector<announce_entry>::iterator i = m_trackers.begin()
, end(m_trackers.end()); i != end; ++i)
if (i->source == 0) i->source = announce_entry::source_client;
if (!m_trackers.empty()) start_announcing(); if (!m_trackers.empty()) start_announcing();
else stop_announcing(); else stop_announcing();
} }
@ -2092,12 +2076,16 @@ namespace libtorrent
{ {
std::vector<announce_entry>::iterator k = std::find_if(m_trackers.begin() std::vector<announce_entry>::iterator k = std::find_if(m_trackers.begin()
, m_trackers.end(), boost::bind(&announce_entry::url, _1) == url.url); , m_trackers.end(), boost::bind(&announce_entry::url, _1) == url.url);
if (k != m_trackers.end()) return; if (k != m_trackers.end())
{
k->source |= url.source;
return;
}
k = std::upper_bound(m_trackers.begin(), m_trackers.end(), url k = std::upper_bound(m_trackers.begin(), m_trackers.end(), url
, boost::bind(&announce_entry::tier, _1) < boost::bind(&announce_entry::tier, _2)); , boost::bind(&announce_entry::tier, _1) < boost::bind(&announce_entry::tier, _2));
if (k - m_trackers.begin() < m_currently_trying_tracker) ++m_currently_trying_tracker;
if (k - m_trackers.begin() < m_last_working_tracker) ++m_last_working_tracker; if (k - m_trackers.begin() < m_last_working_tracker) ++m_last_working_tracker;
m_trackers.insert(k, url); k = m_trackers.insert(k, url);
if (k->source == 0) k->source = announce_entry::source_client;
if (!m_trackers.empty()) start_announcing(); if (!m_trackers.empty()) start_announcing();
} }
@ -3454,7 +3442,16 @@ namespace libtorrent
m_picker.reset(); m_picker.reset();
set_state(torrent_status::seeding); set_state(torrent_status::seeding);
if (!m_complete_sent && m_announcing) announce_with_tracker(); if (!m_announcing) return;
ptime now = time_now();
for (std::vector<announce_entry>::iterator i = m_trackers.begin()
, end(m_trackers.end()); i != end; ++i)
{
if (i->complete_sent) continue;
i->next_announce = now;
}
announce_with_tracker();
} }
// this will move the tracker with the given index // this will move the tracker with the given index
@ -3470,67 +3467,30 @@ namespace libtorrent
while (index > 0 && m_trackers[index].tier == m_trackers[index-1].tier) while (index > 0 && m_trackers[index].tier == m_trackers[index-1].tier)
{ {
std::swap(m_trackers[index].url, m_trackers[index-1].url); using std::swap;
swap(m_trackers[index], m_trackers[index-1]);
if (m_last_working_tracker == index) ++m_last_working_tracker;
--index; --index;
} }
return index; return index;
} }
void torrent::try_next_tracker(tracker_request const& req) int torrent::deprioritize_tracker(int index)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_trackers.empty()) TORRENT_ASSERT(index >= 0);
TORRENT_ASSERT(index < m_trackers.size());
if (index >= (int)m_trackers.size()) return -1;
while (index < m_trackers.size() - 1 && m_trackers[index].tier == m_trackers[index + 1].tier)
{ {
m_currently_trying_tracker = -1; using std::swap;
return; swap(m_trackers[index], m_trackers[index + 1]);
if (m_last_working_tracker == index) --m_last_working_tracker;
++index;
} }
return index;
// increase tracker index until we find a tracker we can use
// or until we reach the end of the tracker list
do
{
++m_currently_trying_tracker;
} 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()))
{
announce_with_tracker(req.event);
return;
}
int delay = tracker_retry_delay_min
+ (std::min)(int(m_failed_trackers), int(tracker_failed_max))
* (tracker_retry_delay_max - tracker_retry_delay_min)
/ tracker_failed_max;
++m_failed_trackers;
// if we've looped the tracker list, wait a bit before retrying
m_currently_trying_tracker = -1;
// if we're stopping, just give up. Don't bother retrying
if (req.event == tracker_request::stopped)
return;
restart_tracker_timer(time_now() + seconds(delay));
#ifndef TORRENT_DISABLE_DHT
if (m_abort) return;
// only start the announce if we want to announce with the dht
ptime now = time_now();
if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
{
// force the DHT to reannounce
m_last_dht_announce = now;
boost::weak_ptr<torrent> self(shared_from_this());
m_ses.m_dht->announce(m_torrent_file->info_hash()
, m_ses.m_listen_sockets.front().external_port
, bind(&torrent::on_dht_announce_response_disp, self, _1));
}
#endif
} }
void torrent::files_checked() void torrent::files_checked()
@ -3562,7 +3522,9 @@ namespace libtorrent
} }
else else
{ {
m_complete_sent = true; for (std::vector<announce_entry>::iterator i = m_trackers.begin()
, end(m_trackers.end()); i != end; ++i)
i->complete_sent = true;
if (m_state != torrent_status::finished) finished(); if (m_state != torrent_status::finished) finished();
} }
@ -4206,14 +4168,31 @@ namespace libtorrent
start_announcing(); start_announcing();
} }
void torrent::restart_tracker_timer(ptime announce_at) void torrent::update_tracker_timer()
{ {
if (!m_announcing) return; if (!m_announcing) return;
m_next_tracker_announce = announce_at; ptime next_announce = max_time();
int tier = INT_MAX;
for (std::vector<announce_entry>::iterator i = m_trackers.begin()
, end(m_trackers.end()); i != end; ++i)
{
if (i->tier > tier) break;
if (i->is_working()) tier = i->tier;
if (i->fails >= i->fail_limit && i->fail_limit != 0) continue;
if (i->updating) continue;
if (i->next_announce < next_announce) next_announce = i->next_announce;
if (i->is_working() && !m_settings.announce_to_all_trackers) break;
}
if (next_announce == max_time()) return;
// since we don't know if we have to re-issue the async_wait or not
// always do it
// if (m_tracker_timer.expires_at() <= next_announce) return;
error_code ec; error_code ec;
boost::weak_ptr<torrent> self(shared_from_this()); boost::weak_ptr<torrent> self(shared_from_this());
m_tracker_timer.expires_at(m_next_tracker_announce, ec); m_tracker_timer.expires_at(next_announce, ec);
m_tracker_timer.async_wait(bind(&torrent::on_tracker_announce_disp, self, _1)); m_tracker_timer.async_wait(bind(&torrent::on_tracker_announce_disp, self, _1));
} }
@ -4231,7 +4210,8 @@ namespace libtorrent
if (!m_trackers.empty()) if (!m_trackers.empty())
{ {
// tell the tracker that we're back // tell the tracker that we're back
m_start_sent = false; std::for_each(m_trackers.begin(), m_trackers.end()
, bind(&announce_entry::reset, _1));
m_stat.clear(); m_stat.clear();
announce_with_tracker(); announce_with_tracker();
} }
@ -4258,7 +4238,10 @@ namespace libtorrent
m_announcing = false; m_announcing = false;
if (!m_trackers.empty()) ptime now = time_now();
for (std::vector<announce_entry>::iterator i = m_trackers.begin()
, end(m_trackers.end()); i != end; ++i)
i->next_announce = now;
announce_with_tracker(tracker_request::stopped); announce_with_tracker(tracker_request::stopped);
} }
@ -4447,6 +4430,15 @@ namespace libtorrent
return m_tracker_address; return m_tracker_address;
} }
announce_entry* torrent::find_tracker(tracker_request const& r)
{
std::vector<announce_entry>::iterator i = std::find_if(
m_trackers.begin(), m_trackers.end()
, bind(&announce_entry::url, _1) == r.url);
if (i == m_trackers.end()) return 0;
return &*i;
}
void torrent::file_progress(std::vector<float>& fp) const void torrent::file_progress(std::vector<float>& fp) const
{ {
fp.clear(); fp.clear();
@ -4683,19 +4675,19 @@ namespace libtorrent
if (st.next_announce.is_negative() || is_paused()) if (st.next_announce.is_negative() || is_paused())
st.next_announce = boost::posix_time::seconds(0); st.next_announce = boost::posix_time::seconds(0);
st.announce_interval = boost::posix_time::seconds(m_duration); st.announce_interval = boost::posix_time::seconds(0);
if (m_last_working_tracker >= 0) if (m_last_working_tracker >= 0)
{ {
TORRENT_ASSERT(m_last_working_tracker < m_trackers.size()); TORRENT_ASSERT(m_last_working_tracker < m_trackers.size());
st.current_tracker st.current_tracker = m_trackers[m_last_working_tracker].url;
= m_trackers[m_last_working_tracker].url;
} }
else if (m_currently_trying_tracker >= 0) else
{ {
TORRENT_ASSERT(m_currently_trying_tracker < m_trackers.size()); std::vector<announce_entry>::const_iterator i;
st.current_tracker for (i = m_trackers.begin(); i != m_trackers.end(); ++i)
= m_trackers[m_currently_trying_tracker].url; if (i->updating) break;
if (i != m_trackers.end()) st.current_tracker = i->url;
} }
st.num_uploads = m_num_uploads; st.num_uploads = m_num_uploads;
@ -4797,18 +4789,17 @@ namespace libtorrent
if (r.kind == tracker_request::announce_request) if (r.kind == tracker_request::announce_request)
{ {
announce_entry* ae = find_tracker(r);
if (ae)
{
ae->failed();
int tracker_index = ae - &m_trackers[0];
deprioritize_tracker(tracker_index);
}
if (m_ses.m_alerts.should_post<tracker_error_alert>()) if (m_ses.m_alerts.should_post<tracker_error_alert>())
{ {
m_ses.m_alerts.post_alert(tracker_error_alert(get_handle() m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
, m_failed_trackers + 1, 0, r.url, "tracker timed out")); , ae?ae->fails:0, 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) else if (r.kind == tracker_request::scrape_request)
@ -4819,9 +4810,7 @@ namespace libtorrent
, r.url, "tracker timed out")); , r.url, "tracker timed out"));
} }
} }
update_tracker_timer();
if (r.kind == tracker_request::announce_request)
try_next_tracker(r);
} }
// TODO: with some response codes, we should just consider // TODO: with some response codes, we should just consider
@ -4839,18 +4828,17 @@ namespace libtorrent
#endif #endif
if (r.kind == tracker_request::announce_request) if (r.kind == tracker_request::announce_request)
{ {
announce_entry* ae = find_tracker(r);
if (ae)
{
ae->failed();
int tracker_index = ae - &m_trackers[0];
deprioritize_tracker(tracker_index);
}
if (m_ses.m_alerts.should_post<tracker_error_alert>()) if (m_ses.m_alerts.should_post<tracker_error_alert>())
{ {
m_ses.m_alerts.post_alert(tracker_error_alert(get_handle() m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
, m_failed_trackers + 1, response_code, r.url, str)); , ae?ae->fails:0, 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) else if (r.kind == tracker_request::scrape_request)
@ -4860,9 +4848,7 @@ namespace libtorrent
m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), r.url, str)); m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), r.url, str));
} }
} }
update_tracker_timer();
if (r.kind == tracker_request::announce_request)
try_next_tracker(r);
} }

View File

@ -478,7 +478,7 @@ namespace libtorrent
// ============ end deprecation =============== // ============ end deprecation ===============
#endif #endif
std::vector<announce_entry> const& torrent_handle::trackers() const std::vector<announce_entry> torrent_handle::trackers() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
const static std::vector<announce_entry> empty; const static std::vector<announce_entry> empty;

View File

@ -540,6 +540,7 @@ namespace libtorrent
if (e.url.empty()) continue; if (e.url.empty()) continue;
e.tier = j; e.tier = j;
e.fail_limit = 0; e.fail_limit = 0;
e.source = announce_entry::source_torrent;
m_urls.push_back(e); m_urls.push_back(e);
} }
} }
@ -565,6 +566,7 @@ namespace libtorrent
{ {
announce_entry e(torrent_file.dict_find_string_value("announce")); announce_entry e(torrent_file.dict_find_string_value("announce"));
e.fail_limit = 0; e.fail_limit = 0;
e.source = announce_entry::source_torrent;
if (!e.url.empty()) m_urls.push_back(e); if (!e.url.empty()) m_urls.push_back(e);
} }
@ -638,11 +640,12 @@ namespace libtorrent
{ {
announce_entry e(url); announce_entry e(url);
e.tier = tier; e.tier = tier;
e.source = announce_entry::source_client;
m_urls.push_back(e); m_urls.push_back(e);
using boost::bind; using boost::bind;
std::sort(m_urls.begin(), m_urls.end(), boost::bind<bool>(std::less<int>() std::sort(m_urls.begin(), m_urls.end(), bind(&announce_entry::tier, _1)
, bind(&announce_entry::tier, _1), bind(&announce_entry::tier, _2))); < bind(&announce_entry::tier, _2));
} }
#ifndef TORRENT_NO_DEPRECATE #ifndef TORRENT_NO_DEPRECATE