+
const std::vector<announce_entry>& trackers() const;
-int prioritize_tracker(int index);
The trackers() function will return a sorted vector of announce_entry.
@@ -735,14 +732,11 @@ ones with lower tier will always be tried before the one with higher tier number
struct announce_entry
{
+ announce_entry(std::string const& url);
std::string url;
int tier;
};
-
The prioritize_tracker() is used internally to move a tracker to the front
-of its tier group. i.e. It will never be moved pass a tracker with a different tier
-number. For more information about how multiple trackers are dealt with, see the
-specification.
@@ -813,6 +807,9 @@ struct torrent_handle
void set_tracker_login(std::string const& username, std::string const& password);
+ std::vector<announce_entry> const& trackers() const;
+ void replace_trackers(std::vector<announce_entry> const&);
+
void set_ratio(float ratio);
void set_max_uploads(int max_uploads);
void set_max_connections(int max_connections);
@@ -840,6 +837,7 @@ struct torrent_handle
The default constructor will initialize the handle to an invalid state. Which means you cannot
perform any operation on it, unless you first assign it a valid handle. If you try to perform
any operation on an uninitialized handle, it will throw invalid_handle.
+
TODO: document ``trackers()`` and ``replace_trackers()``
@@ -1691,13 +1689,16 @@ struct file_error_alert: alert
This alert is generated on tracker time outs, premature disconnects, invalid response or
a HTTP response other than "200 OK". From the alert you can get the handle to the torrent
the tracker belongs to. This alert is generated as severity level warning.
+The times_in_row member says how many times in a row this tracker has failed.
struct tracker_alert: alert
{
- tracker_alert(const torrent_handle& h, const std::string& msg);
+ tracker_alert(const torrent_handle& h, int times
+ , const std::string& msg);
virtual std::auto_ptr<alert> clone() const;
torrent_handle handle;
+ int times_in_row;
};
diff --git a/docs/manual.rst b/docs/manual.rst
index f3a21aae8..7bdf66ba8 100755
--- a/docs/manual.rst
+++ b/docs/manual.rst
@@ -559,7 +559,7 @@ The ``torrent_info`` has the following synopsis::
{
public:
- torrent_info(const entry& torrent_file)
+ torrent_info(entry const& torrent_file)
torrent_info(int piece_size, const char* name);
entry create_torrent() const;
@@ -569,7 +569,7 @@ The ``torrent_info`` has the following synopsis::
void add_tracker(std::string const& url, int tier = 0);
void add_file(boost::filesystem::path file, size_type size);
- typedef std::vector>file_entry>::const_iterator file_iterator;
+ typedef std::vector
::const_iterator file_iterator;
typedef std::vector::const_reverse_iterator reverse_file_iterator;
file_iterator begin_files() const;
@@ -578,11 +578,9 @@ The ``torrent_info`` has the following synopsis::
reverse_file_iterator rend_files() const;
int num_files() const;
- const file_entry& file_at(int index) const;
+ file_entry const& file_at(int index) const;
- const std::vector& trackers() const;
-
- int prioritize_tracker(int index);
+ std::vector const& trackers() const;
size_type total_size() const;
size_type piece_length() const;
@@ -649,13 +647,12 @@ The ``print()`` function is there for debug purposes only. It will print the inf
the torrent file to the given outstream.
-trackers() prioritize_tracker()
--------------------------------
+trackers()
+----------
::
const std::vector& trackers() const;
- int prioritize_tracker(int index);
The ``trackers()`` function will return a sorted vector of ``announce_entry``.
Each announce entry contains a string, which is the tracker url, and a tier index. The
@@ -666,17 +663,11 @@ ones with lower tier will always be tried before the one with higher tier number
struct announce_entry
{
+ announce_entry(std::string const& url);
std::string url;
int tier;
};
-The ``prioritize_tracker()`` is used internally to move a tracker to the front
-of its tier group. i.e. It will never be moved pass a tracker with a different tier
-number. For more information about how multiple trackers are dealt with, see the
-specification_.
-
-.. _specification: http://home.elp.rr.com/tur/multitracker-spec.txt
-
total_size() piece_length() piece_size() num_pieces()
-----------------------------------------------------
@@ -756,6 +747,9 @@ Its declaration looks like this::
void set_tracker_login(std::string const& username, std::string const& password);
+ std::vector const& trackers() const;
+ void replace_trackers(std::vector const&);
+
void set_ratio(float ratio);
void set_max_uploads(int max_uploads);
void set_max_connections(int max_connections);
@@ -784,6 +778,7 @@ The default constructor will initialize the handle to an invalid state. Which me
perform any operation on it, unless you first assign it a valid handle. If you try to perform
any operation on an uninitialized handle, it will throw ``invalid_handle``.
+*TODO: document ``trackers()`` and ``replace_trackers()``*
save_path()
-----------
@@ -1709,17 +1704,22 @@ This alert is generated on tracker time outs, premature disconnects, invalid res
a HTTP response other than "200 OK". From the alert you can get the handle to the torrent
the tracker belongs to. This alert is generated as severity level ``warning``.
+The ``times_in_row`` member says how many times in a row this tracker has failed.
+
::
struct tracker_alert: alert
{
- tracker_alert(const torrent_handle& h, const std::string& msg);
+ tracker_alert(const torrent_handle& h, int times
+ , const std::string& msg);
virtual std::auto_ptr clone() const;
torrent_handle handle;
+ int times_in_row;
};
+
hash_failed_alert
-----------------
diff --git a/include/libtorrent/alert_types.hpp b/include/libtorrent/alert_types.hpp
index edede69db..4c2b6e726 100755
--- a/include/libtorrent/alert_types.hpp
+++ b/include/libtorrent/alert_types.hpp
@@ -43,15 +43,18 @@ namespace libtorrent
struct tracker_alert: alert
{
tracker_alert(const torrent_handle& h
+ , int times
, const std::string& msg)
: alert(alert::warning, msg)
, handle(h)
+ , times_in_row(times)
{}
virtual std::auto_ptr clone() const
{ return std::auto_ptr(new tracker_alert(*this)); }
torrent_handle handle;
+ int times_in_row;
};
struct hash_failed_alert: alert
diff --git a/include/libtorrent/bencode.hpp b/include/libtorrent/bencode.hpp
index f9372b8bd..a4cf74afb 100755
--- a/include/libtorrent/bencode.hpp
+++ b/include/libtorrent/bencode.hpp
@@ -93,10 +93,6 @@ namespace libtorrent
struct invalid_encoding: std::exception
{
- invalid_encoding()
- {
- int i = 0;
- }
virtual const char* what() const throw() { return "invalid bencoding"; }
};
diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp
index 4863273df..df8a1be2d 100755
--- a/include/libtorrent/torrent.hpp
+++ b/include/libtorrent/torrent.hpp
@@ -301,6 +301,11 @@ namespace libtorrent
piece_manager& filesystem();
torrent_info const& torrent_file() const { return m_torrent_file; }
+ std::vector const& trackers() const
+ { return m_trackers; }
+
+ void replace_trackers(std::vector const& urls);
+
torrent_handle get_handle() const;
// DEBUG
@@ -343,6 +348,7 @@ namespace libtorrent
private:
void try_next_tracker();
+ int prioritize_tracker(int tracker_index);
torrent_info m_torrent_file;
@@ -396,11 +402,13 @@ namespace libtorrent
std::auto_ptr m_picker;
+ std::vector m_trackers;
// this is an index into m_torrent_file.trackers()
int m_last_working_tracker;
int m_currently_trying_tracker;
// the number of connection attempts that has
- // failed in a row
+ // failed in a row, this is currently used to
+ // determine the timeout until next try.
int m_failed_trackers;
// this is a counter that is increased every
diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp
index 3c9e638e3..7b7714796 100755
--- a/include/libtorrent/torrent_handle.hpp
+++ b/include/libtorrent/torrent_handle.hpp
@@ -183,6 +183,9 @@ namespace libtorrent
torrent_status status() const;
void get_download_queue(std::vector& queue) const;
+ std::vector const& trackers() const;
+ void replace_trackers(std::vector const&);
+
bool has_metadata() const;
const torrent_info& get_torrent_info() const;
bool is_valid() const;
diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp
index 61d323edb..35b774cbc 100755
--- a/include/libtorrent/torrent_info.hpp
+++ b/include/libtorrent/torrent_info.hpp
@@ -67,6 +67,7 @@ namespace libtorrent
struct announce_entry
{
+ announce_entry(std::string const& u): url(u), tier(0) {}
std::string url;
int tier;
};
@@ -115,11 +116,6 @@ namespace libtorrent
const std::vector& trackers() const { return m_urls; }
- // this will move the tracker with the given index
- // to a prioritized position in the list (move it towards
- // the begining) and return the new index to the tracker.
- int prioritize_tracker(int index);
-
size_type total_size() const { assert(m_piece_length > 0); return m_total_size; }
size_type piece_length() const { assert(m_piece_length > 0); return m_piece_length; }
int num_pieces() const { assert(m_piece_length > 0); return (int)m_piece_hash.size(); }
diff --git a/src/torrent.cpp b/src/torrent.cpp
index 276bcaf57..07e4430a2 100755
--- a/src/torrent.cpp
+++ b/src/torrent.cpp
@@ -162,6 +162,7 @@ namespace libtorrent
, m_policy()
, m_ses(ses)
, m_picker(0)
+ , m_trackers(m_torrent_file.trackers())
, m_last_working_tracker(-1)
, m_currently_trying_tracker(0)
, m_failed_trackers(0)
@@ -213,6 +214,7 @@ namespace libtorrent
, m_download_bandwidth_limit(std::numeric_limits::max())
, m_save_path(save_path)
{
+ m_trackers.push_back(announce_entry(tracker_url));
m_requested_metadata.resize(256, 0);
m_policy.reset(new policy(this));
m_torrent_file.add_tracker(tracker_url);
@@ -265,7 +267,7 @@ namespace libtorrent
if (interval < 60) interval = 60;
m_last_working_tracker
- = m_torrent_file.prioritize_tracker(m_currently_trying_tracker);
+ = prioritize_tracker(m_currently_trying_tracker);
m_next_request = boost::posix_time::second_clock::local_time()
+ boost::posix_time::seconds(m_duration);
m_currently_trying_tracker = 0;
@@ -416,15 +418,20 @@ namespace libtorrent
// decrease the trust point of all peers that sent
// parts of this piece.
- for (std::vector::iterator i = downloaders.begin();
- i != downloaders.end();
- ++i)
+ // first, build a set of all peers that participated
+ std::set peers;
+ std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
+
+ for (std::set::iterator i = peers.begin()
+ , end(peers.end()); i != end; ++i)
{
peer_iterator p = m_connections.find(*i);
if (p == m_connections.end()) continue;
p->second->received_invalid_data();
- if (p->second->trust_points() <= -7)
+ // either, we have received too many failed hashes
+ // or this was the only peer that sent us this piece.
+ if (p->second->trust_points() <= -7 || peers.size() == 1)
{
// we don't trust this peer anymore
// ban it.
@@ -467,9 +474,11 @@ namespace libtorrent
// increase the trust point of all peers that sent
// parts of this piece.
- for (std::vector::iterator i = downloaders.begin();
- i != downloaders.end();
- ++i)
+ std::set peers;
+ std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
+
+ for (std::set::iterator i = peers.begin()
+ , end(peers.end()); i != end; ++i)
{
peer_iterator p = m_connections.find(*i);
if (p == m_connections.end()) continue;
@@ -487,6 +496,15 @@ namespace libtorrent
return m_username + ":" + m_password;
}
+ void torrent::replace_trackers(std::vector const& urls)
+ {
+ assert(!urls.empty());
+ m_trackers = urls;
+ if (m_currently_trying_tracker >= (int)m_trackers.size())
+ m_currently_trying_tracker = m_trackers.size()-1;
+ m_last_working_tracker = -1;
+ }
+
tracker_request torrent::generate_tracker_request()
{
m_duration = 1800;
@@ -502,7 +520,7 @@ namespace libtorrent
req.left = bytes_left();
if (req.left == -1) req.left = 1000;
req.event = m_event;
- req.url = m_torrent_file.trackers()[m_currently_trying_tracker].url;
+ req.url = m_trackers[m_currently_trying_tracker].url;
req.num_want = std::max(
(m_policy->get_max_connections()
- m_policy->num_peers()), 0);
@@ -637,12 +655,27 @@ namespace libtorrent
force_tracker_request();
}
+ // this will move the tracker with the given index
+ // to a prioritized position in the list (move it towards
+ // the begining) and return the new index to the tracker.
+ int torrent::prioritize_tracker(int index)
+ {
+ assert(index >= 0);
+ if (index >= (int)m_trackers.size()) return (int)m_trackers.size()-1;
+
+ while (index > 0 && m_trackers[index].tier == m_trackers[index-1].tier)
+ {
+ std::swap(m_trackers[index].url, m_trackers[index-1].url);
+ --index;
+ }
+ return index;
+ }
void torrent::try_next_tracker()
{
++m_currently_trying_tracker;
- if ((unsigned)m_currently_trying_tracker >= m_torrent_file.trackers().size())
+ if ((unsigned)m_currently_trying_tracker >= m_trackers.size())
{
int delay = tracker_retry_delay_min
+ std::min(m_failed_trackers, (int)tracker_failed_max)
@@ -659,6 +692,7 @@ namespace libtorrent
// don't delay before trying the next tracker
m_next_request = boost::posix_time::second_clock::local_time();
}
+
}
void torrent::check_files(detail::piece_checker_data& data,
@@ -921,7 +955,7 @@ namespace libtorrent
if (m_last_working_tracker >= 0)
{
st.current_tracker
- = m_torrent_file.trackers()[m_last_working_tracker].url;
+ = m_trackers[m_last_working_tracker].url;
}
st.progress = st.total_done
@@ -1060,9 +1094,10 @@ namespace libtorrent
{
std::stringstream s;
s << "tracker: \""
- << m_torrent_file.trackers()[m_currently_trying_tracker].url
+ << m_trackers[m_currently_trying_tracker].url
<< "\" timed out";
- m_ses.m_alerts.post_alert(tracker_alert(get_handle(), s.str()));
+ m_ses.m_alerts.post_alert(tracker_alert(get_handle()
+ , m_failed_trackers, s.str()));
}
try_next_tracker();
}
@@ -1079,9 +1114,10 @@ namespace libtorrent
{
std::stringstream s;
s << "tracker: \""
- << m_torrent_file.trackers()[m_currently_trying_tracker].url
+ << m_trackers[m_currently_trying_tracker].url
<< "\" " << str;
- m_ses.m_alerts.post_alert(tracker_alert(get_handle(), s.str()));
+ m_ses.m_alerts.post_alert(tracker_alert(get_handle()
+ , m_failed_trackers, s.str()));
}
diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp
index 954afefd5..65f9bc37f 100755
--- a/src/torrent_handle.cpp
+++ b/src/torrent_handle.cpp
@@ -313,6 +313,22 @@ namespace libtorrent
throw invalid_handle();
}
+ std::vector const& torrent_handle::trackers() const
+ {
+ INVARIANT_CHECK;
+
+ return call_member const&>(m_ses
+ , m_chk, m_info_hash, boost::bind(&torrent::trackers, _1));
+ }
+
+ void torrent_handle::replace_trackers(std::vector const& urls)
+ {
+ INVARIANT_CHECK;
+
+ call_member(m_ses, m_chk, m_info_hash
+ , boost::bind(&torrent::replace_trackers, _1, urls));
+ }
+
const torrent_info& torrent_handle::get_torrent_info() const
{
INVARIANT_CHECK;
diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp
index 6667b8f97..a1251c2e6 100755
--- a/src/torrent_info.cpp
+++ b/src/torrent_info.cpp
@@ -193,9 +193,8 @@ namespace libtorrent
const entry::list_type& ll = j->list();
for (entry::list_type::const_iterator k = ll.begin(); k != ll.end(); ++k)
{
- announce_entry e;
+ announce_entry e(k->string());
e.tier = (int)std::distance(l.begin(), j);
- e.url = k->string();
m_urls.push_back(e);
}
}
@@ -220,10 +219,7 @@ namespace libtorrent
{
i = torrent_file.find_key("announce");
if (i == 0) throw invalid_torrent_file();
- announce_entry e;
- e.tier = 0;
- e.url = i->string();
- m_urls.push_back(e);
+ m_urls.push_back(announce_entry(i->string()));
}
// extract creation date
@@ -271,8 +267,7 @@ namespace libtorrent
void torrent_info::add_tracker(std::string const& url, int tier)
{
- announce_entry e;
- e.url = url;
+ announce_entry e(url);
e.tier = tier;
m_urls.push_back(e);
}
@@ -414,19 +409,6 @@ namespace libtorrent
assert(false);
}
- int torrent_info::prioritize_tracker(int index)
- {
- assert(index >= 0);
- if (index >= (int)m_urls.size()) return (int)m_urls.size()-1;
-
- while (index > 0 && m_urls[index].tier == m_urls[index-1].tier)
- {
- std::swap(m_urls[index].url, m_urls[index-1].url);
- --index;
- }
- return index;
- }
-
void torrent_info::print(std::ostream& os) const
{
os << "trackers:\n";