lt sync 2224
This commit is contained in:
parent
ff837215e3
commit
c5eba92174
|
@ -56,39 +56,55 @@ namespace libtorrent
|
|||
struct TORRENT_EXPORT tracker_alert: torrent_alert
|
||||
{
|
||||
tracker_alert(torrent_handle const& h
|
||||
, std::string const& url_
|
||||
, alert::severity_t s
|
||||
, std::string const& msg)
|
||||
: torrent_alert(h, s, msg)
|
||||
, url(url_)
|
||||
{}
|
||||
|
||||
std::string url;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT tracker_error_alert: tracker_alert
|
||||
{
|
||||
tracker_error_alert(torrent_handle const& h
|
||||
, int times
|
||||
, int status
|
||||
, std::string const& url
|
||||
, std::string const& msg)
|
||||
: torrent_alert(h, alert::warning, msg)
|
||||
: tracker_alert(h, url, alert::warning, msg)
|
||||
, times_in_row(times)
|
||||
, status_code(status)
|
||||
{}
|
||||
|
||||
virtual std::auto_ptr<alert> clone() const
|
||||
{ return std::auto_ptr<alert>(new tracker_alert(*this)); }
|
||||
{ return std::auto_ptr<alert>(new tracker_error_alert(*this)); }
|
||||
|
||||
int times_in_row;
|
||||
int status_code;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT tracker_warning_alert: torrent_alert
|
||||
struct TORRENT_EXPORT tracker_warning_alert: tracker_alert
|
||||
{
|
||||
tracker_warning_alert(torrent_handle const& h
|
||||
, std::string const& url
|
||||
, std::string const& msg)
|
||||
: torrent_alert(h, alert::warning, msg)
|
||||
: tracker_alert(h, url, alert::warning, msg)
|
||||
{}
|
||||
|
||||
virtual std::auto_ptr<alert> clone() const
|
||||
{ return std::auto_ptr<alert>(new tracker_warning_alert(*this)); }
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT scrape_reply_alert: torrent_alert
|
||||
struct TORRENT_EXPORT scrape_reply_alert: tracker_alert
|
||||
{
|
||||
scrape_reply_alert(torrent_handle const& h
|
||||
, int incomplete_
|
||||
, int complete_
|
||||
, std::string const& url
|
||||
, std::string const& msg)
|
||||
: torrent_alert(h, alert::info, msg)
|
||||
: tracker_alert(h, url, alert::info, msg)
|
||||
, incomplete(incomplete_)
|
||||
, complete(complete_)
|
||||
{}
|
||||
|
@ -100,23 +116,25 @@ namespace libtorrent
|
|||
{ return std::auto_ptr<alert>(new scrape_reply_alert(*this)); }
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT scrape_failed_alert: torrent_alert
|
||||
struct TORRENT_EXPORT scrape_failed_alert: tracker_alert
|
||||
{
|
||||
scrape_failed_alert(torrent_handle const& h
|
||||
, std::string const& url
|
||||
, std::string const& msg)
|
||||
: torrent_alert(h, alert::warning, msg)
|
||||
: tracker_alert(h, url, alert::warning, msg)
|
||||
{}
|
||||
|
||||
virtual std::auto_ptr<alert> clone() const
|
||||
{ return std::auto_ptr<alert>(new scrape_failed_alert(*this)); }
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT tracker_reply_alert: torrent_alert
|
||||
struct TORRENT_EXPORT tracker_reply_alert: tracker_alert
|
||||
{
|
||||
tracker_reply_alert(torrent_handle const& h
|
||||
, int np
|
||||
, std::string const& url
|
||||
, std::string const& msg)
|
||||
: torrent_alert(h, alert::info, msg)
|
||||
: tracker_alert(h, url, alert::info, msg)
|
||||
, num_peers(np)
|
||||
{}
|
||||
|
||||
|
@ -126,10 +144,12 @@ namespace libtorrent
|
|||
{ return std::auto_ptr<alert>(new tracker_reply_alert(*this)); }
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT tracker_announce_alert: torrent_alert
|
||||
struct TORRENT_EXPORT tracker_announce_alert: tracker_alert
|
||||
{
|
||||
tracker_announce_alert(torrent_handle const& h, std::string const& msg)
|
||||
: torrent_alert(h, alert::info, msg)
|
||||
tracker_announce_alert(torrent_handle const& h
|
||||
, std::string const& url
|
||||
, std::string const& msg)
|
||||
: tracker_alert(h, url, alert::info, msg)
|
||||
{}
|
||||
|
||||
virtual std::auto_ptr<alert> clone() const
|
||||
|
|
|
@ -198,25 +198,7 @@ namespace libtorrent
|
|||
, const char* net_interface = 0);
|
||||
bool is_listening() const;
|
||||
|
||||
torrent_handle add_torrent(
|
||||
boost::intrusive_ptr<torrent_info> ti
|
||||
, fs::path const& save_path
|
||||
, entry const& resume_data
|
||||
, storage_mode_t storage_mode
|
||||
, storage_constructor_type sc
|
||||
, bool paused
|
||||
, void* userdata);
|
||||
|
||||
torrent_handle add_torrent(
|
||||
char const* tracker_url
|
||||
, sha1_hash const& info_hash
|
||||
, char const* name
|
||||
, fs::path const& save_path
|
||||
, entry const& resume_data
|
||||
, storage_mode_t storage_mode
|
||||
, storage_constructor_type sc
|
||||
, bool paused
|
||||
, void* userdata);
|
||||
torrent_handle add_torrent(add_torrent_params const&);
|
||||
|
||||
void remove_torrent(torrent_handle const& h, int options);
|
||||
|
||||
|
@ -491,6 +473,10 @@ namespace libtorrent
|
|||
// recomputed.
|
||||
int m_unchoke_time_scaler;
|
||||
|
||||
// this is used to decide when to recalculate which
|
||||
// torrents to keep queued and which to activate
|
||||
int m_auto_manage_time_scaler;
|
||||
|
||||
// works like unchoke_time_scaler but it
|
||||
// is only decresed when the unchoke set
|
||||
// is recomputed, and when it reaches zero,
|
||||
|
@ -513,6 +499,10 @@ namespace libtorrent
|
|||
bool m_incoming_connection;
|
||||
|
||||
void second_tick(asio::error_code const& e);
|
||||
void recalculate_auto_managed_torrents();
|
||||
void recalculate_unchoke_slots(int congested_torrents
|
||||
, int uncongested_torrents);
|
||||
|
||||
ptime m_last_tick;
|
||||
|
||||
// when outgoing_ports is configured, this is the
|
||||
|
@ -532,6 +522,10 @@ namespace libtorrent
|
|||
// but for the udp port used by the DHT.
|
||||
int m_external_udp_port;
|
||||
|
||||
// the sequence number to assign to the
|
||||
// next torrent that's added
|
||||
int m_torrent_sequence;
|
||||
|
||||
udp_socket m_dht_socket;
|
||||
|
||||
void on_receive_udp(asio::error_code const& e
|
||||
|
@ -613,7 +607,8 @@ namespace libtorrent
|
|||
struct tracker_logger : request_callback
|
||||
{
|
||||
tracker_logger(session_impl& ses): m_ses(ses) {}
|
||||
void tracker_warning(std::string const& str)
|
||||
void tracker_warning(tracker_request const& req
|
||||
, std::string const& str)
|
||||
{
|
||||
debug_log("*** tracker warning: " + str);
|
||||
}
|
||||
|
|
|
@ -260,8 +260,17 @@ namespace libtorrent
|
|||
m_num_connect_candidates = 1;
|
||||
}
|
||||
|
||||
void erase_peer(iterator i);
|
||||
|
||||
private:
|
||||
|
||||
bool compare_peer(policy::peer const& lhs, policy::peer const& rhs
|
||||
, address const& external_ip) const;
|
||||
|
||||
// since the peer list can grow too large
|
||||
// to scan all of it, start at this iterator
|
||||
iterator m_round_robin;
|
||||
|
||||
iterator find_disconnect_candidate();
|
||||
iterator find_connect_candidate();
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/fingerprint.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
#include "libtorrent/disk_io_thread.hpp"
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
|
||||
#include "libtorrent/storage.hpp"
|
||||
|
||||
|
@ -120,6 +121,34 @@ namespace libtorrent
|
|||
boost::shared_ptr<aux::session_impl> m_impl;
|
||||
};
|
||||
|
||||
struct add_torrent_params
|
||||
{
|
||||
add_torrent_params(storage_constructor_type sc = default_storage_constructor)
|
||||
: tracker_url(0)
|
||||
, name(0)
|
||||
, resume_data(0)
|
||||
, storage_mode(storage_mode_sparse)
|
||||
, paused(true)
|
||||
, auto_managed(true)
|
||||
, duplicate_is_error(false)
|
||||
, storage(sc)
|
||||
, userdata(0)
|
||||
{}
|
||||
|
||||
boost::intrusive_ptr<torrent_info> ti;
|
||||
char const* tracker_url;
|
||||
sha1_hash info_hash;
|
||||
char const* name;
|
||||
fs::path save_path;
|
||||
entry const* resume_data;
|
||||
storage_mode_t storage_mode;
|
||||
bool paused;
|
||||
bool auto_managed;
|
||||
bool duplicate_is_error;
|
||||
storage_constructor_type storage;
|
||||
void* userdata;
|
||||
};
|
||||
|
||||
class TORRENT_EXPORT session: public boost::noncopyable, aux::eh_initializer
|
||||
{
|
||||
public:
|
||||
|
@ -148,6 +177,9 @@ namespace libtorrent
|
|||
torrent_handle find_torrent(sha1_hash const& info_hash) const;
|
||||
|
||||
// all torrent_handles must be destructed before the session is destructed!
|
||||
torrent_handle add_torrent(add_torrent_params const& params);
|
||||
|
||||
// deprecated in 0.14
|
||||
torrent_handle add_torrent(
|
||||
torrent_info const& ti
|
||||
, fs::path const& save_path
|
||||
|
@ -156,6 +188,7 @@ namespace libtorrent
|
|||
, bool paused = false
|
||||
, storage_constructor_type sc = default_storage_constructor) TORRENT_DEPRECATED;
|
||||
|
||||
// deprecated in 0.14
|
||||
torrent_handle add_torrent(
|
||||
boost::intrusive_ptr<torrent_info> ti
|
||||
, fs::path const& save_path
|
||||
|
@ -163,8 +196,9 @@ namespace libtorrent
|
|||
, storage_mode_t storage_mode = storage_mode_sparse
|
||||
, bool paused = false
|
||||
, storage_constructor_type sc = default_storage_constructor
|
||||
, void* userdata = 0);
|
||||
, void* userdata = 0) TORRENT_DEPRECATED;
|
||||
|
||||
// deprecated in 0.14
|
||||
torrent_handle add_torrent(
|
||||
char const* tracker_url
|
||||
, sha1_hash const& info_hash
|
||||
|
@ -174,7 +208,7 @@ namespace libtorrent
|
|||
, storage_mode_t storage_mode = storage_mode_sparse
|
||||
, bool paused = false
|
||||
, storage_constructor_type sc = default_storage_constructor
|
||||
, void* userdata = 0);
|
||||
, void* userdata = 0) TORRENT_DEPRECATED;
|
||||
|
||||
session_proxy abort() { return session_proxy(m_impl); }
|
||||
|
||||
|
|
|
@ -128,6 +128,12 @@ namespace libtorrent
|
|||
, cache_expiry(60)
|
||||
, outgoing_ports(0,0)
|
||||
, peer_tos(0)
|
||||
, active_downloads(8)
|
||||
, active_seeds(5)
|
||||
, auto_manage_interval(30)
|
||||
, share_ratio_limit(2.f)
|
||||
, seed_time_ratio_limit(7.f)
|
||||
, seed_time_limit(24 * 60 * 60) // 24 hours
|
||||
{}
|
||||
|
||||
// this is the user agent that will be sent to the tracker
|
||||
|
@ -347,8 +353,31 @@ namespace libtorrent
|
|||
// http://qbone.internet2.edu/qbss/
|
||||
// For unmarked packets, set to 0
|
||||
char peer_tos;
|
||||
};
|
||||
|
||||
// for auto managed torrents, these are the limits
|
||||
// they are subject to. If there are too many torrents
|
||||
// some of the auto managed ones will be paused until
|
||||
// some slots free up.
|
||||
int active_downloads;
|
||||
int active_seeds;
|
||||
|
||||
// the number of seconds in between recalculating which
|
||||
// torrents to activate and which ones to queue
|
||||
int auto_manage_interval;
|
||||
|
||||
// when a seeding torrent reaches eaither the share ratio
|
||||
// (bytes up / bytes down) or the seed time ratio
|
||||
// (seconds as seed / seconds as downloader) or the seed
|
||||
// time limit (seconds as seed) it is considered
|
||||
// done, and it will leave room for other torrents
|
||||
// the default value for share ratio is 2
|
||||
// the default seed time ratio is 7, because that's a common
|
||||
// asymmetry ratio on connections
|
||||
float share_ratio_limit;
|
||||
float seed_time_ratio_limit;
|
||||
int seed_time_limit;
|
||||
};
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
struct dht_settings
|
||||
{
|
||||
|
|
|
@ -105,7 +105,9 @@ namespace libtorrent
|
|||
, int block_size
|
||||
, storage_constructor_type sc
|
||||
, bool paused
|
||||
, entry const& resume_data);
|
||||
, entry const* resume_data
|
||||
, int seq
|
||||
, bool auto_managed);
|
||||
|
||||
// used with metadata-less torrents
|
||||
// (the metadata is downloaded from the peers)
|
||||
|
@ -120,7 +122,9 @@ namespace libtorrent
|
|||
, int block_size
|
||||
, storage_constructor_type sc
|
||||
, bool paused
|
||||
, entry const& resume_data);
|
||||
, entry const* resume_data
|
||||
, int seq
|
||||
, bool auto_managed);
|
||||
|
||||
~torrent();
|
||||
|
||||
|
@ -147,6 +151,9 @@ namespace libtorrent
|
|||
void files_checked();
|
||||
void start_checking();
|
||||
|
||||
float seed_cycles(session_settings const& s) const;
|
||||
int seed_cycles_int(session_settings const& s) const { return int(seed_cycles(s)); }
|
||||
|
||||
storage_mode_t storage_mode() const { return m_storage_mode; }
|
||||
// this will flag the torrent as aborted. The main
|
||||
// loop in session_impl will check for this state
|
||||
|
@ -180,6 +187,9 @@ namespace libtorrent
|
|||
bool is_paused() const { return m_paused; }
|
||||
void save_resume_data();
|
||||
|
||||
bool is_auto_managed() const { return m_auto_managed; }
|
||||
void auto_managed(bool a);
|
||||
|
||||
void delete_files();
|
||||
|
||||
// ============ start deprecation =============
|
||||
|
@ -318,7 +328,8 @@ namespace libtorrent
|
|||
tracker_request const& r);
|
||||
virtual void tracker_request_error(tracker_request const& r
|
||||
, int response_code, const std::string& str);
|
||||
virtual void tracker_warning(std::string const& msg);
|
||||
virtual void tracker_warning(tracker_request const& req
|
||||
, std::string const& msg);
|
||||
virtual void tracker_scrape_response(tracker_request const& req
|
||||
, int complete, int incomplete, int downloaded);
|
||||
|
||||
|
@ -561,6 +572,8 @@ namespace libtorrent
|
|||
// a return value of false indicates an error
|
||||
bool set_metadata(entry const& metadata, std::string& error);
|
||||
|
||||
int sequence_number() const { return m_sequence_number; }
|
||||
|
||||
private:
|
||||
|
||||
void on_files_deleted(int ret, disk_io_job const& j);
|
||||
|
@ -592,6 +605,13 @@ namespace libtorrent
|
|||
// paused to the time should_request() is called
|
||||
bool m_just_paused;
|
||||
|
||||
// if this is true, libtorrent may pause and resume
|
||||
// this torrent depending on queuing rules. Torrents
|
||||
// started with auto_managed flag set may be added in
|
||||
// a paused state in case there are no available
|
||||
// slots.
|
||||
bool m_auto_managed;
|
||||
|
||||
tracker_request::event_t m_event;
|
||||
|
||||
void parse_response(const entry& e, std::vector<peer_entry>& peer_list);
|
||||
|
|
|
@ -118,6 +118,7 @@ namespace libtorrent
|
|||
, all_time_download(0)
|
||||
, active_time(0)
|
||||
, seeding_time(0)
|
||||
, seed_cycles(0.f)
|
||||
{}
|
||||
|
||||
enum state_t
|
||||
|
@ -255,6 +256,8 @@ namespace libtorrent
|
|||
// from resume data
|
||||
int active_time;
|
||||
int seeding_time;
|
||||
|
||||
float seed_cycles;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT block_info
|
||||
|
@ -332,6 +335,9 @@ namespace libtorrent
|
|||
void resume() const;
|
||||
void save_resume_data() const;
|
||||
|
||||
bool is_auto_managed() const;
|
||||
void auto_managed(bool m) const;
|
||||
|
||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||
void resolve_countries(bool r);
|
||||
bool resolve_countries() const;
|
||||
|
@ -342,6 +348,7 @@ namespace libtorrent
|
|||
|
||||
// ================ start deprecation ============
|
||||
|
||||
// deprecated in 0.13
|
||||
// marks the piece with the given index as filtered
|
||||
// it will not be downloaded
|
||||
void filter_piece(int index, bool filter) const TORRENT_DEPRECATED;
|
||||
|
@ -370,6 +377,7 @@ namespace libtorrent
|
|||
// to.
|
||||
void use_interface(const char* net_interface) const;
|
||||
|
||||
// deprecated in 0.14
|
||||
// use save_resume_data() instead. It is async. and
|
||||
// will return the resume data in an alert
|
||||
entry write_resume_data() const TORRENT_DEPRECATED;
|
||||
|
|
|
@ -118,20 +118,21 @@ namespace libtorrent
|
|||
friend class tracker_manager;
|
||||
request_callback(): m_manager(0) {}
|
||||
virtual ~request_callback() {}
|
||||
virtual void tracker_warning(std::string const& msg) = 0;
|
||||
virtual void tracker_warning(tracker_request const& req
|
||||
, std::string const& msg) = 0;
|
||||
virtual void tracker_scrape_response(tracker_request const& req
|
||||
, int complete, int incomplete, int downloads) {}
|
||||
virtual void tracker_response(
|
||||
tracker_request const&
|
||||
tracker_request const& req
|
||||
, std::vector<peer_entry>& peers
|
||||
, int interval
|
||||
, int complete
|
||||
, int incomplete
|
||||
, address const& external_ip) = 0;
|
||||
virtual void tracker_request_timed_out(
|
||||
tracker_request const&) = 0;
|
||||
tracker_request const& req) = 0;
|
||||
virtual void tracker_request_error(
|
||||
tracker_request const&
|
||||
tracker_request const& req
|
||||
, int response_code
|
||||
, const std::string& description) = 0;
|
||||
|
||||
|
|
|
@ -2449,6 +2449,7 @@ namespace libtorrent
|
|||
|
||||
if (pid == m_ses.get_peer_id())
|
||||
{
|
||||
set_failed();
|
||||
disconnect("closing connection to ourself");
|
||||
return;
|
||||
}
|
||||
|
@ -2465,6 +2466,7 @@ namespace libtorrent
|
|||
// since it most likely is ourself then
|
||||
if (pid == m_ses.get_peer_id())
|
||||
{
|
||||
set_failed();
|
||||
disconnect("closing connection to ourself");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -306,7 +306,7 @@ namespace libtorrent
|
|||
entry const* warning = e.find_key("warning message");
|
||||
if (warning && warning->type() == entry::string_t)
|
||||
{
|
||||
cb->tracker_warning(warning->string());
|
||||
cb->tracker_warning(tracker_req(), warning->string());
|
||||
}
|
||||
|
||||
std::vector<peer_entry> peer_list;
|
||||
|
|
|
@ -384,12 +384,26 @@ namespace libtorrent
|
|||
, "blocked peer removed from peer list"));
|
||||
}
|
||||
}
|
||||
if (p) p->clear_peer(&i->second);
|
||||
if (i->second.seed) --m_num_seeds;
|
||||
m_peers.erase(i++);
|
||||
erase_peer(i++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// any peer that is erased from m_peers will be
|
||||
// erased through this function. This way we can make
|
||||
// sure that any references to the peer are removed
|
||||
// as well, such as in the piece picker.
|
||||
void policy::erase_peer(iterator i)
|
||||
{
|
||||
if (m_torrent->has_picker())
|
||||
m_torrent->picker().clear_peer(&i->second);
|
||||
if (i->second.seed) --m_num_seeds;
|
||||
if (is_connect_candidate(i->second, m_torrent->is_finished()))
|
||||
--m_num_connect_candidates;
|
||||
if (m_round_robin == i) ++m_round_robin;
|
||||
|
||||
m_peers.erase(i);
|
||||
}
|
||||
|
||||
bool policy::is_connect_candidate(peer const& p, bool finished)
|
||||
{
|
||||
if (p.connection
|
||||
|
@ -450,16 +464,14 @@ namespace libtorrent
|
|||
|
||||
policy::iterator policy::find_connect_candidate()
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
// too expensive
|
||||
// INVARIANT_CHECK;
|
||||
|
||||
ptime now = time_now();
|
||||
ptime min_connect_time(now);
|
||||
iterator candidate = m_peers.end();
|
||||
|
||||
int min_reconnect_time = m_torrent->settings().min_reconnect_time;
|
||||
bool finished = m_torrent->is_finished();
|
||||
|
||||
int min_cidr_distance = (std::numeric_limits<int>::max)();
|
||||
address external_ip = m_torrent->session().external_address();
|
||||
|
||||
// don't bias any particular peers when seeding
|
||||
|
@ -472,75 +484,35 @@ namespace libtorrent
|
|||
external_ip = address_v4(bytes);
|
||||
}
|
||||
|
||||
#ifndef TORRENT_DISABLE_GEO_IP
|
||||
int max_inet_as_rate = -1;
|
||||
bool has_db = m_torrent->session().has_asnum_db();
|
||||
#endif
|
||||
if (m_round_robin == iterator() || m_round_robin == m_peers.end())
|
||||
m_round_robin = m_peers.begin();
|
||||
|
||||
int connect_candidates = 0;
|
||||
int seeds = 0;
|
||||
for (iterator i = m_peers.begin(); i != m_peers.end(); ++i)
|
||||
for (int iterations = (std::min)(int(m_peers.size()), 300);
|
||||
iterations > 0; ++m_round_robin, --iterations)
|
||||
{
|
||||
if (i->second.seed) ++seeds;
|
||||
if (!is_connect_candidate(i->second, finished)) continue;
|
||||
++connect_candidates;
|
||||
if (m_round_robin == m_peers.end()) m_round_robin = m_peers.begin();
|
||||
|
||||
if (!is_connect_candidate(m_round_robin->second, finished)) continue;
|
||||
|
||||
// prefer peers with lower failcount
|
||||
if (candidate != m_peers.end()
|
||||
&& candidate->second.failcount < i->second.failcount)
|
||||
&& !compare_peer(candidate->second, m_round_robin->second, external_ip)) continue;
|
||||
|
||||
if (now - m_round_robin->second.connected <
|
||||
seconds(m_round_robin->second.failcount * min_reconnect_time))
|
||||
continue;
|
||||
|
||||
if (now - i->second.connected < seconds(i->second.failcount * min_reconnect_time))
|
||||
continue;
|
||||
|
||||
TORRENT_ASSERT(i->second.connected <= now);
|
||||
|
||||
// don't replace a candidate that is on the local
|
||||
// network with one that isn't. Local peers should
|
||||
// always be tried first
|
||||
if (candidate != m_peers.end()
|
||||
&& is_local(candidate->second.ip.address())
|
||||
&& !is_local(i->second.ip.address()))
|
||||
continue;
|
||||
|
||||
if (i->second.connected > min_connect_time) continue;
|
||||
|
||||
#ifndef TORRENT_DISABLE_GEO_IP
|
||||
if (!finished && has_db)
|
||||
{
|
||||
// don't bias fast peers when seeding
|
||||
std::pair<const int, int>* inet_as = i->second.inet_as;
|
||||
int peak_rate = inet_as ? inet_as->second : 0;
|
||||
if (peak_rate <= max_inet_as_rate) continue;
|
||||
max_inet_as_rate = peak_rate;
|
||||
}
|
||||
|
||||
if (max_inet_as_rate <= 0)
|
||||
#endif
|
||||
{
|
||||
int distance = cidr_distance(external_ip, i->second.ip.address());
|
||||
if (distance > min_cidr_distance) continue;
|
||||
|
||||
min_cidr_distance = distance;
|
||||
}
|
||||
|
||||
min_connect_time = i->second.connected;
|
||||
candidate = i;
|
||||
candidate = m_round_robin;
|
||||
}
|
||||
|
||||
m_num_connect_candidates = connect_candidates;
|
||||
m_num_seeds = seeds;
|
||||
TORRENT_ASSERT(min_connect_time <= now);
|
||||
|
||||
#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
|
||||
if (candidate != m_peers.end())
|
||||
{
|
||||
(*m_torrent->session().m_logger) << time_now_string()
|
||||
<< " *** FOUND CONNECTION CANDIDATE ["
|
||||
" ip: " << candidate->second.ip <<
|
||||
" d: " << min_cidr_distance <<
|
||||
" d: " << cidr_distance(external_ip, candidate->second.ip.address()) <<
|
||||
" external: " << external_ip <<
|
||||
" t: " << total_seconds(time_now() - min_connect_time) <<
|
||||
" t: " << total_seconds(time_now() - candidate->second.connected) <<
|
||||
" ]\n";
|
||||
}
|
||||
#endif
|
||||
|
@ -554,10 +526,6 @@ namespace libtorrent
|
|||
|
||||
if (m_torrent->is_paused()) return;
|
||||
|
||||
piece_picker* p = 0;
|
||||
if (m_torrent->has_picker())
|
||||
p = &m_torrent->picker();
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
bool pinged = false;
|
||||
#endif
|
||||
|
@ -589,9 +557,7 @@ namespace libtorrent
|
|||
&& !pe.banned
|
||||
&& now - pe.connected > minutes(120))
|
||||
{
|
||||
if (p) p->clear_peer(&pe);
|
||||
if (pe.seed) --m_num_seeds;
|
||||
m_peers.erase(i++);
|
||||
erase_peer(i++);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -599,52 +565,6 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
// maintain the number of connections
|
||||
// -------------------------------------
|
||||
/*
|
||||
// count the number of connected peers except for peers
|
||||
// that are currently in the process of disconnecting
|
||||
int num_connected_peers = 0;
|
||||
|
||||
for (iterator i = m_peers.begin();
|
||||
i != m_peers.end(); ++i)
|
||||
{
|
||||
if (i->connection && !i->connection->is_disconnecting())
|
||||
++num_connected_peers;
|
||||
}
|
||||
|
||||
if (m_torrent->max_connections() != (std::numeric_limits<int>::max)())
|
||||
{
|
||||
int max_connections = m_torrent->max_connections();
|
||||
|
||||
if (num_connected_peers >= max_connections)
|
||||
{
|
||||
// every minute, disconnect the worst peer in hope of finding a better peer
|
||||
|
||||
ptime local_time = time_now();
|
||||
if (m_last_optimistic_disconnect + seconds(120) <= local_time
|
||||
&& find_connect_candidate() != m_peers.end())
|
||||
{
|
||||
m_last_optimistic_disconnect = local_time;
|
||||
--max_connections; // this will have the effect of disconnecting the worst peer
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// don't do a disconnect earlier than 1 minute after some peer was connected
|
||||
m_last_optimistic_disconnect = time_now();
|
||||
}
|
||||
|
||||
while (num_connected_peers > max_connections)
|
||||
{
|
||||
bool ret = disconnect_one_peer();
|
||||
(void)ret;
|
||||
TORRENT_ASSERT(ret);
|
||||
--num_connected_peers;
|
||||
}
|
||||
}
|
||||
*/
|
||||
// ------------------------
|
||||
// upload shift
|
||||
// ------------------------
|
||||
|
@ -769,6 +689,9 @@ namespace libtorrent
|
|||
"with higher priority, closing");
|
||||
}
|
||||
}
|
||||
|
||||
if (m_num_connect_candidates > 0)
|
||||
--m_num_connect_candidates;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -797,8 +720,6 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(i->second.connection);
|
||||
if (!c.fast_reconnect())
|
||||
i->second.connected = time_now();
|
||||
if (m_num_connect_candidates > 0)
|
||||
--m_num_connect_candidates;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -823,10 +744,7 @@ namespace libtorrent
|
|||
p->connection->disconnect("duplicate connection");
|
||||
return false;
|
||||
}
|
||||
if (m_torrent->has_picker())
|
||||
m_torrent->picker().clear_peer(&i->second);
|
||||
if (i->second.seed) --m_num_seeds;
|
||||
m_peers.erase(i);
|
||||
erase_peer(i);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -859,7 +777,8 @@ namespace libtorrent
|
|||
policy::peer* policy::peer_from_tracker(tcp::endpoint const& remote, peer_id const& pid
|
||||
, int src, char flags)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
// way too expensive
|
||||
//INVARIANT_CHECK;
|
||||
|
||||
// just ignore the obviously invalid entries
|
||||
if (remote.address() == address() || remote.port() == 0)
|
||||
|
@ -1405,5 +1324,38 @@ namespace libtorrent
|
|||
return prev_amount_upload;
|
||||
}
|
||||
}
|
||||
|
||||
// this returns true if lhs is a better connect candidate than rhs
|
||||
bool policy::compare_peer(policy::peer const& lhs, policy::peer const& rhs
|
||||
, address const& external_ip) const
|
||||
{
|
||||
// prefer peers with lower failcount
|
||||
if (lhs.failcount < rhs.failcount) return true;
|
||||
if (lhs.failcount > rhs.failcount) return false;
|
||||
|
||||
// Local peers should always be tried first
|
||||
bool lhs_local = is_local(lhs.ip.address());
|
||||
bool rhs_local = is_local(rhs.ip.address());
|
||||
if (lhs_local && !rhs_local) return true;
|
||||
if (!lhs_local && rhs_local) return false;
|
||||
|
||||
if (lhs.connected < rhs.connected) return true;
|
||||
if (lhs.connected > rhs.connected) return false;
|
||||
|
||||
#ifndef TORRENT_DISABLE_GEO_IP
|
||||
// don't bias fast peers when seeding
|
||||
if (!m_torrent->is_finished() && m_torrent->session().has_asnum_db())
|
||||
{
|
||||
std::pair<const int, int>* lhs_as = lhs.inet_as;
|
||||
std::pair<const int, int>* rhs_as = rhs.inet_as;
|
||||
if (lhs_as ? lhs_as->second : 0 > rhs_as ? rhs->second : 0) return true;
|
||||
if (lhs_as ? lhs_as->second : 0 < rhs_as ? rhs->second : 0) return false;
|
||||
}
|
||||
#endif
|
||||
int lhs_distance = cidr_distance(external_ip, lhs.ip.address());
|
||||
int rhs_distance = cidr_distance(external_ip, rhs.ip.address());
|
||||
if (lhs_distance < rhs_distance) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -239,6 +239,10 @@ namespace libtorrent
|
|||
return m_impl->find_torrent_handle(info_hash);
|
||||
}
|
||||
|
||||
torrent_handle session::add_torrent(add_torrent_params const& params)
|
||||
{
|
||||
return m_impl->add_torrent(params);
|
||||
}
|
||||
|
||||
// if the torrent already exists, this will throw duplicate_torrent
|
||||
torrent_handle session::add_torrent(
|
||||
|
@ -251,8 +255,13 @@ namespace libtorrent
|
|||
{
|
||||
TORRENT_ASSERT(!ti.m_half_metadata);
|
||||
boost::intrusive_ptr<torrent_info> tip(new torrent_info(ti));
|
||||
return m_impl->add_torrent(tip, save_path, resume_data
|
||||
, storage_mode, sc, paused, 0);
|
||||
add_torrent_params p(sc);
|
||||
p.ti = tip;
|
||||
p.save_path = save_path;
|
||||
p.resume_data = &resume_data;
|
||||
p.storage_mode = storage_mode;
|
||||
p.paused = paused;
|
||||
return m_impl->add_torrent(p);
|
||||
}
|
||||
|
||||
torrent_handle session::add_torrent(
|
||||
|
@ -265,8 +274,14 @@ namespace libtorrent
|
|||
, void* userdata)
|
||||
{
|
||||
TORRENT_ASSERT(!ti->m_half_metadata);
|
||||
return m_impl->add_torrent(ti, save_path, resume_data
|
||||
, storage_mode, sc, paused, userdata);
|
||||
add_torrent_params p(sc);
|
||||
p.ti = ti;
|
||||
p.save_path = save_path;
|
||||
p.resume_data = &resume_data;
|
||||
p.storage_mode = storage_mode;
|
||||
p.paused = paused;
|
||||
p.userdata = userdata;
|
||||
return m_impl->add_torrent(p);
|
||||
}
|
||||
|
||||
torrent_handle session::add_torrent(
|
||||
|
@ -280,8 +295,13 @@ namespace libtorrent
|
|||
, storage_constructor_type sc
|
||||
, void* userdata)
|
||||
{
|
||||
return m_impl->add_torrent(tracker_url, info_hash, name, save_path, e
|
||||
, storage_mode, sc, paused, userdata);
|
||||
add_torrent_params p(sc);
|
||||
p.tracker_url = tracker_url;
|
||||
p.info_hash = info_hash;
|
||||
p.save_path = save_path;
|
||||
p.paused = paused;
|
||||
p.userdata = userdata;
|
||||
return m_impl->add_torrent(p);
|
||||
}
|
||||
|
||||
void session::remove_torrent(const torrent_handle& h, int options)
|
||||
|
|
|
@ -74,6 +74,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/aux_/session_impl.hpp"
|
||||
#include "libtorrent/kademlia/dht_tracker.hpp"
|
||||
#include "libtorrent/enum_net.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
|
||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||
|
||||
|
@ -158,6 +159,7 @@ namespace aux {
|
|||
, m_max_connections(200)
|
||||
, m_num_unchoked(0)
|
||||
, m_unchoke_time_scaler(0)
|
||||
, m_auto_manage_time_scaler(0)
|
||||
, m_optimistic_unchoke_time_scaler(0)
|
||||
, m_disconnect_time_scaler(90)
|
||||
, m_incoming_connection(false)
|
||||
|
@ -165,6 +167,7 @@ namespace aux {
|
|||
#ifndef TORRENT_DISABLE_DHT
|
||||
, m_dht_same_port(true)
|
||||
, m_external_udp_port(0)
|
||||
, m_torrent_sequence(0)
|
||||
, m_dht_socket(m_io_service, bind(&session_impl::on_receive_udp, this, _1, _2, _3, _4)
|
||||
, m_half_open)
|
||||
#endif
|
||||
|
@ -762,7 +765,7 @@ namespace aux {
|
|||
+ boost::lexical_cast<std::string>(ep) + "' " + e.message();
|
||||
(*m_logger) << msg << "\n";
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#ifdef TORRENT_WINDOWS
|
||||
// Windows sometimes generates this error. It seems to be
|
||||
// non-fatal and we have to do another async_accept.
|
||||
if (e.value() == ERROR_SEM_TIMEOUT)
|
||||
|
@ -1035,7 +1038,7 @@ namespace aux {
|
|||
{
|
||||
m_alerts.post_alert(
|
||||
tracker_announce_alert(
|
||||
t.get_handle(), "tracker announce"));
|
||||
t.get_handle(), req.url, "tracker announce"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1173,6 +1176,16 @@ namespace aux {
|
|||
c.keep_alive();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// auto managed torrent
|
||||
// --------------------------------------------------------------
|
||||
m_auto_manage_time_scaler--;
|
||||
if (m_auto_manage_time_scaler <= 0)
|
||||
{
|
||||
m_auto_manage_time_scaler = settings().auto_manage_interval;
|
||||
recalculate_auto_managed_torrents();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// unchoke set and optimistic unchoke calculations
|
||||
// --------------------------------------------------------------
|
||||
|
@ -1180,173 +1193,8 @@ namespace aux {
|
|||
if (m_unchoke_time_scaler <= 0 && !m_connections.empty())
|
||||
{
|
||||
m_unchoke_time_scaler = settings().unchoke_interval;
|
||||
|
||||
std::vector<peer_connection*> peers;
|
||||
for (connection_map::iterator i = m_connections.begin()
|
||||
, end(m_connections.end()); i != end; ++i)
|
||||
{
|
||||
peer_connection* p = i->get();
|
||||
torrent* t = p->associated_torrent().lock().get();
|
||||
if (!p->peer_info_struct()
|
||||
|| t == 0
|
||||
|| !p->is_peer_interested()
|
||||
|| p->is_disconnecting()
|
||||
|| p->is_connecting()
|
||||
|| (p->share_diff() < -free_upload_amount
|
||||
&& !t->is_seed()))
|
||||
{
|
||||
if (!(*i)->is_choked() && t)
|
||||
{
|
||||
policy::peer* pi = p->peer_info_struct();
|
||||
if (pi && pi->optimistically_unchoked)
|
||||
{
|
||||
pi->optimistically_unchoked = false;
|
||||
// force a new optimistic unchoke
|
||||
m_optimistic_unchoke_time_scaler = 0;
|
||||
}
|
||||
t->choke_peer(*(*i));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
peers.push_back(i->get());
|
||||
}
|
||||
|
||||
// sorts the peers that are eligible for unchoke by download rate and secondary
|
||||
// by total upload. The reason for this is, if all torrents are being seeded,
|
||||
// the download rate will be 0, and the peers we have sent the least to should
|
||||
// be unchoked
|
||||
std::sort(peers.begin(), peers.end()
|
||||
, bind(&peer_connection::unchoke_compare, _1, _2));
|
||||
|
||||
std::for_each(m_connections.begin(), m_connections.end()
|
||||
, bind(&peer_connection::reset_choke_counters, _1));
|
||||
|
||||
// auto unchoke
|
||||
int upload_limit = m_bandwidth_manager[peer_connection::upload_channel]->throttle();
|
||||
if (m_settings.auto_upload_slots && upload_limit != bandwidth_limit::inf)
|
||||
{
|
||||
// if our current upload rate is less than 90% of our
|
||||
// limit AND most torrents are not "congested", i.e.
|
||||
// they are not holding back because of a per-torrent
|
||||
// limit
|
||||
if (m_stat.upload_rate() < upload_limit * 0.9f
|
||||
&& m_allowed_upload_slots <= m_num_unchoked + 1
|
||||
&& congested_torrents < uncongested_torrents)
|
||||
{
|
||||
++m_allowed_upload_slots;
|
||||
}
|
||||
else if (m_upload_channel.queue_size() > 1
|
||||
&& m_allowed_upload_slots > m_max_uploads)
|
||||
{
|
||||
--m_allowed_upload_slots;
|
||||
}
|
||||
}
|
||||
|
||||
// reserve one upload slot for optimistic unchokes
|
||||
int unchoke_set_size = m_allowed_upload_slots - 1;
|
||||
|
||||
m_num_unchoked = 0;
|
||||
// go through all the peers and unchoke the first ones and choke
|
||||
// all the other ones.
|
||||
for (std::vector<peer_connection*>::iterator i = peers.begin()
|
||||
, end(peers.end()); i != end; ++i)
|
||||
{
|
||||
peer_connection* p = *i;
|
||||
TORRENT_ASSERT(p);
|
||||
torrent* t = p->associated_torrent().lock().get();
|
||||
TORRENT_ASSERT(t);
|
||||
if (unchoke_set_size > 0)
|
||||
{
|
||||
if (p->is_choked())
|
||||
{
|
||||
if (!t->unchoke_peer(*p))
|
||||
continue;
|
||||
}
|
||||
|
||||
--unchoke_set_size;
|
||||
++m_num_unchoked;
|
||||
|
||||
TORRENT_ASSERT(p->peer_info_struct());
|
||||
if (p->peer_info_struct()->optimistically_unchoked)
|
||||
{
|
||||
// force a new optimistic unchoke
|
||||
m_optimistic_unchoke_time_scaler = 0;
|
||||
p->peer_info_struct()->optimistically_unchoked = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TORRENT_ASSERT(p->peer_info_struct());
|
||||
if (!p->is_choked() && !p->peer_info_struct()->optimistically_unchoked)
|
||||
t->choke_peer(*p);
|
||||
if (!p->is_choked())
|
||||
++m_num_unchoked;
|
||||
}
|
||||
}
|
||||
|
||||
m_optimistic_unchoke_time_scaler--;
|
||||
if (m_optimistic_unchoke_time_scaler <= 0)
|
||||
{
|
||||
m_optimistic_unchoke_time_scaler
|
||||
= settings().optimistic_unchoke_multiplier;
|
||||
|
||||
// find the peer that has been waiting the longest to be optimistically
|
||||
// unchoked
|
||||
connection_map::iterator current_optimistic_unchoke = m_connections.end();
|
||||
connection_map::iterator optimistic_unchoke_candidate = m_connections.end();
|
||||
ptime last_unchoke = max_time();
|
||||
|
||||
for (connection_map::iterator i = m_connections.begin()
|
||||
, end(m_connections.end()); i != end; ++i)
|
||||
{
|
||||
peer_connection* p = i->get();
|
||||
TORRENT_ASSERT(p);
|
||||
policy::peer* pi = p->peer_info_struct();
|
||||
if (!pi) continue;
|
||||
torrent* t = p->associated_torrent().lock().get();
|
||||
if (!t) continue;
|
||||
|
||||
if (pi->optimistically_unchoked)
|
||||
{
|
||||
TORRENT_ASSERT(!p->is_choked());
|
||||
TORRENT_ASSERT(current_optimistic_unchoke == m_connections.end());
|
||||
current_optimistic_unchoke = i;
|
||||
}
|
||||
|
||||
if (pi->last_optimistically_unchoked < last_unchoke
|
||||
&& !p->is_connecting()
|
||||
&& !p->is_disconnecting()
|
||||
&& p->is_peer_interested()
|
||||
&& t->free_upload_slots()
|
||||
&& p->is_choked())
|
||||
{
|
||||
last_unchoke = pi->last_optimistically_unchoked;
|
||||
optimistic_unchoke_candidate = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (optimistic_unchoke_candidate != m_connections.end()
|
||||
&& optimistic_unchoke_candidate != current_optimistic_unchoke)
|
||||
{
|
||||
if (current_optimistic_unchoke != m_connections.end())
|
||||
{
|
||||
torrent* t = (*current_optimistic_unchoke)->associated_torrent().lock().get();
|
||||
TORRENT_ASSERT(t);
|
||||
(*current_optimistic_unchoke)->peer_info_struct()->optimistically_unchoked = false;
|
||||
t->choke_peer(*current_optimistic_unchoke->get());
|
||||
}
|
||||
else
|
||||
{
|
||||
++m_num_unchoked;
|
||||
}
|
||||
|
||||
torrent* t = (*optimistic_unchoke_candidate)->associated_torrent().lock().get();
|
||||
TORRENT_ASSERT(t);
|
||||
bool ret = t->unchoke_peer(*optimistic_unchoke_candidate->get());
|
||||
TORRENT_ASSERT(ret);
|
||||
(*optimistic_unchoke_candidate)->peer_info_struct()->optimistically_unchoked = true;
|
||||
}
|
||||
}
|
||||
recalculate_unchoke_slots(congested_torrents
|
||||
, uncongested_torrents);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------
|
||||
|
@ -1357,7 +1205,7 @@ namespace aux {
|
|||
{
|
||||
m_disconnect_time_scaler = 90;
|
||||
|
||||
// every 60 seconds, disconnect the worst peer
|
||||
// every 90 seconds, disconnect the worst peer
|
||||
// if we have reached the connection limit
|
||||
if (num_connections() >= max_connections() && !m_torrents.empty())
|
||||
{
|
||||
|
@ -1372,6 +1220,269 @@ namespace aux {
|
|||
}
|
||||
}
|
||||
|
||||
void session_impl::recalculate_auto_managed_torrents()
|
||||
{
|
||||
// these vectors are filled with auto managed torrents
|
||||
std::vector<torrent*> downloaders;
|
||||
downloaders.reserve(m_torrents.size());
|
||||
std::vector<torrent*> seeds;
|
||||
seeds.reserve(m_torrents.size());
|
||||
|
||||
// these counters are set to the number of torrents
|
||||
// of each kind we're allowed to have active
|
||||
int num_downloaders = settings().active_downloads;
|
||||
int num_seeds = settings().active_seeds;
|
||||
|
||||
for (torrent_map::iterator i = m_torrents.begin()
|
||||
, end(m_torrents.end()); i != end; ++i)
|
||||
{
|
||||
torrent* t = i->second.get();
|
||||
TORRENT_ASSERT(t);
|
||||
if (t->is_auto_managed())
|
||||
{
|
||||
// this torrent is auto managed, add it to
|
||||
// the list (depending on if it's a seed or not)
|
||||
if (t->is_finished())
|
||||
seeds.push_back(t);
|
||||
else
|
||||
downloaders.push_back(t);
|
||||
}
|
||||
else if (!t->is_paused())
|
||||
{
|
||||
// this is not an auto managed torrent,
|
||||
// if it's running, decrease the respective
|
||||
// counters.
|
||||
if (t->is_finished())
|
||||
{
|
||||
--num_seeds;
|
||||
--num_downloaders;
|
||||
}
|
||||
else
|
||||
{
|
||||
--num_downloaders;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool handled_by_extension = false;
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
// TODO: allow extensions to sort torrents for queuing
|
||||
#endif
|
||||
|
||||
if (!handled_by_extension)
|
||||
{
|
||||
std::sort(downloaders.begin(), downloaders.end()
|
||||
, bind(&torrent::sequence_number, _1) < bind(&torrent::sequence_number, _2));
|
||||
|
||||
std::sort(seeds.begin(), seeds.end()
|
||||
, bind(&torrent::seed_cycles_int, _1, boost::ref(m_settings))
|
||||
< bind(&torrent::seed_cycles_int, _2, boost::ref(m_settings)));
|
||||
}
|
||||
|
||||
for (std::vector<torrent*>::iterator i = downloaders.begin()
|
||||
, end(downloaders.end()); i != end; ++i)
|
||||
{
|
||||
torrent* t = *i;
|
||||
if (num_downloaders > 0)
|
||||
{
|
||||
--num_downloaders;
|
||||
if (t->is_paused()) t->resume();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!t->is_paused()) t->pause();
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<torrent*>::iterator i = seeds.begin()
|
||||
, end(seeds.end()); i != end; ++i)
|
||||
{
|
||||
torrent* t = *i;
|
||||
if (num_downloaders > 0 && num_seeds > 0)
|
||||
{
|
||||
--num_downloaders;
|
||||
--num_seeds;
|
||||
if (t->is_paused()) t->resume();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!t->is_paused()) t->pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void session_impl::recalculate_unchoke_slots(int congested_torrents
|
||||
, int uncongested_torrents)
|
||||
{
|
||||
std::vector<peer_connection*> peers;
|
||||
for (connection_map::iterator i = m_connections.begin()
|
||||
, end(m_connections.end()); i != end; ++i)
|
||||
{
|
||||
peer_connection* p = i->get();
|
||||
torrent* t = p->associated_torrent().lock().get();
|
||||
if (!p->peer_info_struct()
|
||||
|| t == 0
|
||||
|| !p->is_peer_interested()
|
||||
|| p->is_disconnecting()
|
||||
|| p->is_connecting()
|
||||
|| (p->share_diff() < -free_upload_amount
|
||||
&& !t->is_seed()))
|
||||
{
|
||||
if (!(*i)->is_choked() && t)
|
||||
{
|
||||
policy::peer* pi = p->peer_info_struct();
|
||||
if (pi && pi->optimistically_unchoked)
|
||||
{
|
||||
pi->optimistically_unchoked = false;
|
||||
// force a new optimistic unchoke
|
||||
m_optimistic_unchoke_time_scaler = 0;
|
||||
}
|
||||
t->choke_peer(*(*i));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
peers.push_back(i->get());
|
||||
}
|
||||
|
||||
// sorts the peers that are eligible for unchoke by download rate and secondary
|
||||
// by total upload. The reason for this is, if all torrents are being seeded,
|
||||
// the download rate will be 0, and the peers we have sent the least to should
|
||||
// be unchoked
|
||||
std::sort(peers.begin(), peers.end()
|
||||
, bind(&peer_connection::unchoke_compare, _1, _2));
|
||||
|
||||
std::for_each(m_connections.begin(), m_connections.end()
|
||||
, bind(&peer_connection::reset_choke_counters, _1));
|
||||
|
||||
// auto unchoke
|
||||
int upload_limit = m_bandwidth_manager[peer_connection::upload_channel]->throttle();
|
||||
if (m_settings.auto_upload_slots && upload_limit != bandwidth_limit::inf)
|
||||
{
|
||||
// if our current upload rate is less than 90% of our
|
||||
// limit AND most torrents are not "congested", i.e.
|
||||
// they are not holding back because of a per-torrent
|
||||
// limit
|
||||
if (m_stat.upload_rate() < upload_limit * 0.9f
|
||||
&& m_allowed_upload_slots <= m_num_unchoked + 1
|
||||
&& congested_torrents < uncongested_torrents)
|
||||
{
|
||||
++m_allowed_upload_slots;
|
||||
}
|
||||
else if (m_upload_channel.queue_size() > 1
|
||||
&& m_allowed_upload_slots > m_max_uploads)
|
||||
{
|
||||
--m_allowed_upload_slots;
|
||||
}
|
||||
}
|
||||
|
||||
// reserve one upload slot for optimistic unchokes
|
||||
int unchoke_set_size = m_allowed_upload_slots - 1;
|
||||
|
||||
m_num_unchoked = 0;
|
||||
// go through all the peers and unchoke the first ones and choke
|
||||
// all the other ones.
|
||||
for (std::vector<peer_connection*>::iterator i = peers.begin()
|
||||
, end(peers.end()); i != end; ++i)
|
||||
{
|
||||
peer_connection* p = *i;
|
||||
TORRENT_ASSERT(p);
|
||||
torrent* t = p->associated_torrent().lock().get();
|
||||
TORRENT_ASSERT(t);
|
||||
if (unchoke_set_size > 0)
|
||||
{
|
||||
if (p->is_choked())
|
||||
{
|
||||
if (!t->unchoke_peer(*p))
|
||||
continue;
|
||||
}
|
||||
|
||||
--unchoke_set_size;
|
||||
++m_num_unchoked;
|
||||
|
||||
TORRENT_ASSERT(p->peer_info_struct());
|
||||
if (p->peer_info_struct()->optimistically_unchoked)
|
||||
{
|
||||
// force a new optimistic unchoke
|
||||
m_optimistic_unchoke_time_scaler = 0;
|
||||
p->peer_info_struct()->optimistically_unchoked = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TORRENT_ASSERT(p->peer_info_struct());
|
||||
if (!p->is_choked() && !p->peer_info_struct()->optimistically_unchoked)
|
||||
t->choke_peer(*p);
|
||||
if (!p->is_choked())
|
||||
++m_num_unchoked;
|
||||
}
|
||||
}
|
||||
|
||||
m_optimistic_unchoke_time_scaler--;
|
||||
if (m_optimistic_unchoke_time_scaler <= 0)
|
||||
{
|
||||
m_optimistic_unchoke_time_scaler
|
||||
= settings().optimistic_unchoke_multiplier;
|
||||
|
||||
// find the peer that has been waiting the longest to be optimistically
|
||||
// unchoked
|
||||
connection_map::iterator current_optimistic_unchoke = m_connections.end();
|
||||
connection_map::iterator optimistic_unchoke_candidate = m_connections.end();
|
||||
ptime last_unchoke = max_time();
|
||||
|
||||
for (connection_map::iterator i = m_connections.begin()
|
||||
, end(m_connections.end()); i != end; ++i)
|
||||
{
|
||||
peer_connection* p = i->get();
|
||||
TORRENT_ASSERT(p);
|
||||
policy::peer* pi = p->peer_info_struct();
|
||||
if (!pi) continue;
|
||||
torrent* t = p->associated_torrent().lock().get();
|
||||
if (!t) continue;
|
||||
|
||||
if (pi->optimistically_unchoked)
|
||||
{
|
||||
TORRENT_ASSERT(!p->is_choked());
|
||||
TORRENT_ASSERT(current_optimistic_unchoke == m_connections.end());
|
||||
current_optimistic_unchoke = i;
|
||||
}
|
||||
|
||||
if (pi->last_optimistically_unchoked < last_unchoke
|
||||
&& !p->is_connecting()
|
||||
&& !p->is_disconnecting()
|
||||
&& p->is_peer_interested()
|
||||
&& t->free_upload_slots()
|
||||
&& p->is_choked())
|
||||
{
|
||||
last_unchoke = pi->last_optimistically_unchoked;
|
||||
optimistic_unchoke_candidate = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (optimistic_unchoke_candidate != m_connections.end()
|
||||
&& optimistic_unchoke_candidate != current_optimistic_unchoke)
|
||||
{
|
||||
if (current_optimistic_unchoke != m_connections.end())
|
||||
{
|
||||
torrent* t = (*current_optimistic_unchoke)->associated_torrent().lock().get();
|
||||
TORRENT_ASSERT(t);
|
||||
(*current_optimistic_unchoke)->peer_info_struct()->optimistically_unchoked = false;
|
||||
t->choke_peer(*current_optimistic_unchoke->get());
|
||||
}
|
||||
else
|
||||
{
|
||||
++m_num_unchoked;
|
||||
}
|
||||
|
||||
torrent* t = (*optimistic_unchoke_candidate)->associated_torrent().lock().get();
|
||||
TORRENT_ASSERT(t);
|
||||
bool ret = t->unchoke_peer(*optimistic_unchoke_candidate->get());
|
||||
TORRENT_ASSERT(ret);
|
||||
(*optimistic_unchoke_candidate)->peer_info_struct()->optimistically_unchoked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void session_impl::operator()()
|
||||
{
|
||||
eh_initializer();
|
||||
|
@ -1476,18 +1587,11 @@ namespace aux {
|
|||
return torrent_handle(find_torrent(info_hash));
|
||||
}
|
||||
|
||||
torrent_handle session_impl::add_torrent(
|
||||
boost::intrusive_ptr<torrent_info> ti
|
||||
, fs::path const& save_path
|
||||
, entry const& resume_data
|
||||
, storage_mode_t storage_mode
|
||||
, storage_constructor_type sc
|
||||
, bool paused
|
||||
, void* userdata)
|
||||
torrent_handle session_impl::add_torrent(add_torrent_params const& params)
|
||||
{
|
||||
TORRENT_ASSERT(!save_path.empty());
|
||||
TORRENT_ASSERT(!params.save_path.empty());
|
||||
|
||||
if (ti->begin_files() == ti->end_files())
|
||||
if (params.ti && params.ti->num_files() == 0)
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
throw std::runtime_error("no files in torrent");
|
||||
|
@ -1510,9 +1614,18 @@ namespace aux {
|
|||
#endif
|
||||
}
|
||||
|
||||
// figure out the info hash of the torrent
|
||||
sha1_hash const* ih = 0;
|
||||
if (params.ti) ih = ¶ms.ti->info_hash();
|
||||
else ih = ¶ms.info_hash;
|
||||
|
||||
// is the torrent already active?
|
||||
if (!find_torrent(ti->info_hash()).expired())
|
||||
boost::shared_ptr<torrent> torrent_ptr = find_torrent(*ih).lock();
|
||||
if (torrent_ptr)
|
||||
{
|
||||
if (!params.duplicate_is_error)
|
||||
return torrent_handle(torrent_ptr);
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
throw duplicate_torrent();
|
||||
#else
|
||||
|
@ -1523,25 +1636,36 @@ namespace aux {
|
|||
// create the torrent and the data associated with
|
||||
// the checker thread and store it before starting
|
||||
// the thread
|
||||
boost::shared_ptr<torrent> torrent_ptr(
|
||||
new torrent(*this, ti, save_path
|
||||
, m_listen_interface, storage_mode, 16 * 1024
|
||||
, sc, paused, resume_data));
|
||||
if (params.ti)
|
||||
{
|
||||
torrent_ptr.reset(new torrent(*this, params.ti, params.save_path
|
||||
, m_listen_interface, params.storage_mode, 16 * 1024
|
||||
, params.storage, params.paused, params.resume_data
|
||||
, m_torrent_sequence, params.auto_managed));
|
||||
}
|
||||
else
|
||||
{
|
||||
torrent_ptr.reset(new torrent(*this, params.tracker_url, *ih, params.name
|
||||
, params.save_path, m_listen_interface, params.storage_mode, 16 * 1024
|
||||
, params.storage, params.paused, params.resume_data
|
||||
, m_torrent_sequence, params.auto_managed));
|
||||
}
|
||||
torrent_ptr->start();
|
||||
++m_torrent_sequence;
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
, end(m_extensions.end()); i != end; ++i)
|
||||
{
|
||||
boost::shared_ptr<torrent_plugin> tp((*i)(torrent_ptr.get(), userdata));
|
||||
boost::shared_ptr<torrent_plugin> tp((*i)(torrent_ptr.get(), params.userdata));
|
||||
if (tp) torrent_ptr->add_extension(tp);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
if (m_dht)
|
||||
if (m_dht && params.ti)
|
||||
{
|
||||
torrent_info::nodes_t const& nodes = ti->nodes();
|
||||
torrent_info::nodes_t const& nodes = params.ti->nodes();
|
||||
std::for_each(nodes.begin(), nodes.end(), bind(
|
||||
(void(dht::dht_tracker::*)(std::pair<std::string, int> const&))
|
||||
&dht::dht_tracker::add_node
|
||||
|
@ -1549,7 +1673,7 @@ namespace aux {
|
|||
}
|
||||
#endif
|
||||
|
||||
m_torrents.insert(std::make_pair(ti->info_hash(), torrent_ptr));
|
||||
m_torrents.insert(std::make_pair(*ih, torrent_ptr));
|
||||
|
||||
return torrent_handle(torrent_ptr);
|
||||
}
|
||||
|
@ -1568,62 +1692,6 @@ namespace aux {
|
|||
m_queued_for_checking.front()->start_checking();
|
||||
}
|
||||
|
||||
torrent_handle session_impl::add_torrent(
|
||||
char const* tracker_url
|
||||
, sha1_hash const& info_hash
|
||||
, char const* name
|
||||
, fs::path const& save_path
|
||||
, entry const& resume_data
|
||||
, storage_mode_t storage_mode
|
||||
, storage_constructor_type sc
|
||||
, bool paused
|
||||
, void* userdata)
|
||||
{
|
||||
|
||||
// TODO: support resume data in this case
|
||||
TORRENT_ASSERT(!save_path.empty());
|
||||
|
||||
// lock the session
|
||||
session_impl::mutex_t::scoped_lock l(m_mutex);
|
||||
|
||||
// INVARIANT_CHECK;
|
||||
|
||||
// is the torrent already active?
|
||||
if (!find_torrent(info_hash).expired())
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
throw duplicate_torrent();
|
||||
#else
|
||||
return torrent_handle();
|
||||
#endif
|
||||
}
|
||||
|
||||
// you cannot add new torrents to a session that is closing down
|
||||
TORRENT_ASSERT(!is_aborted());
|
||||
|
||||
// create the torrent and the data associated with
|
||||
// the checker thread and store it before starting
|
||||
// the thread
|
||||
boost::shared_ptr<torrent> torrent_ptr(
|
||||
new torrent(*this, tracker_url, info_hash, name
|
||||
, save_path, m_listen_interface, storage_mode, 16 * 1024
|
||||
, sc, paused, resume_data));
|
||||
torrent_ptr->start();
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
, end(m_extensions.end()); i != end; ++i)
|
||||
{
|
||||
boost::shared_ptr<torrent_plugin> tp((*i)(torrent_ptr.get(), userdata));
|
||||
if (tp) torrent_ptr->add_extension(tp);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_torrents.insert(std::make_pair(info_hash, torrent_ptr));
|
||||
|
||||
return torrent_handle(torrent_ptr);
|
||||
}
|
||||
|
||||
void session_impl::remove_torrent(const torrent_handle& h, int options)
|
||||
{
|
||||
boost::shared_ptr<torrent> tptr = h.m_torrent.lock();
|
||||
|
@ -1672,7 +1740,7 @@ namespace aux {
|
|||
{
|
||||
m_alerts.post_alert(
|
||||
tracker_announce_alert(
|
||||
t.get_handle(), "tracker announce, event=stopped"));
|
||||
t.get_handle(), req.url, "tracker announce, event=stopped"));
|
||||
}
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
|
|
|
@ -157,11 +157,14 @@ namespace libtorrent
|
|||
, int block_size
|
||||
, storage_constructor_type sc
|
||||
, bool paused
|
||||
, entry const& resume_data)
|
||||
, entry const* resume_data
|
||||
, int seq
|
||||
, bool auto_managed)
|
||||
: m_torrent_file(tf)
|
||||
, m_abort(false)
|
||||
, m_paused(paused)
|
||||
, m_just_paused(false)
|
||||
, m_auto_managed(auto_managed)
|
||||
, m_event(tracker_request::started)
|
||||
, m_block_size(0)
|
||||
, m_storage(0)
|
||||
|
@ -196,7 +199,6 @@ namespace libtorrent
|
|||
, m_storage_mode(storage_mode)
|
||||
, m_state(torrent_status::queued_for_checking)
|
||||
, m_progress(0.f)
|
||||
, m_resume_data(resume_data)
|
||||
, m_default_block_size(block_size)
|
||||
, m_connections_initialized(true)
|
||||
, m_settings(ses.settings())
|
||||
|
@ -206,11 +208,13 @@ namespace libtorrent
|
|||
, m_max_connections((std::numeric_limits<int>::max)())
|
||||
, m_deficit_counter(0)
|
||||
, m_policy(this)
|
||||
, m_sequence_number(seq)
|
||||
, m_active_time(seconds(0))
|
||||
, m_seeding_time(seconds(0))
|
||||
, m_total_uploaded(0)
|
||||
, m_total_downloaded(0)
|
||||
{
|
||||
if (resume_data) m_resume_data = *resume_data;
|
||||
#ifndef NDEBUG
|
||||
m_files_checked = false;
|
||||
#endif
|
||||
|
@ -227,11 +231,14 @@ namespace libtorrent
|
|||
, int block_size
|
||||
, storage_constructor_type sc
|
||||
, bool paused
|
||||
, entry const& resume_data)
|
||||
, entry const* resume_data
|
||||
, int seq
|
||||
, bool auto_managed)
|
||||
: m_torrent_file(new torrent_info(info_hash))
|
||||
, m_abort(false)
|
||||
, m_paused(paused)
|
||||
, m_just_paused(false)
|
||||
, m_auto_managed(auto_managed)
|
||||
, m_event(tracker_request::started)
|
||||
, m_block_size(0)
|
||||
, m_storage(0)
|
||||
|
@ -265,7 +272,6 @@ namespace libtorrent
|
|||
, m_storage_mode(storage_mode)
|
||||
, m_state(torrent_status::queued_for_checking)
|
||||
, m_progress(0.f)
|
||||
, m_resume_data(resume_data)
|
||||
, m_default_block_size(block_size)
|
||||
, m_connections_initialized(false)
|
||||
, m_settings(ses.settings())
|
||||
|
@ -275,11 +281,13 @@ namespace libtorrent
|
|||
, m_max_connections((std::numeric_limits<int>::max)())
|
||||
, m_deficit_counter(0)
|
||||
, m_policy(this)
|
||||
, m_sequence_number(seq)
|
||||
, m_active_time(seconds(0))
|
||||
, m_seeding_time(seconds(0))
|
||||
, m_total_uploaded(0)
|
||||
, m_total_downloaded(0)
|
||||
{
|
||||
if (resume_data) m_resume_data = *resume_data;
|
||||
#ifndef NDEBUG
|
||||
m_files_checked = false;
|
||||
#endif
|
||||
|
@ -453,6 +461,7 @@ namespace libtorrent
|
|||
}
|
||||
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
|
||||
m_num_pieces = 0;
|
||||
auto_managed(false);
|
||||
pause();
|
||||
return;
|
||||
}
|
||||
|
@ -633,6 +642,7 @@ namespace libtorrent
|
|||
}
|
||||
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
|
||||
m_num_pieces = 0;
|
||||
auto_managed(false);
|
||||
pause();
|
||||
m_ses.done_checking(shared_from_this());
|
||||
return;
|
||||
|
@ -727,7 +737,7 @@ namespace libtorrent
|
|||
if (m_ses.m_alerts.should_post(alert::info))
|
||||
{
|
||||
m_ses.m_alerts.post_alert(tracker_reply_alert(
|
||||
get_handle(), peers.size(), "Got peers from DHT"));
|
||||
get_handle(), peers.size(), "DHT", "Got peers from DHT"));
|
||||
}
|
||||
std::for_each(peers.begin(), peers.end(), bind(
|
||||
&policy::peer_from_tracker, boost::ref(m_policy), _1, peer_id(0)
|
||||
|
@ -767,7 +777,7 @@ namespace libtorrent
|
|||
return !m_paused && m_next_request < time_now();
|
||||
}
|
||||
|
||||
void torrent::tracker_warning(std::string const& msg)
|
||||
void torrent::tracker_warning(tracker_request const& req, std::string const& msg)
|
||||
{
|
||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||
|
||||
|
@ -775,7 +785,7 @@ namespace libtorrent
|
|||
|
||||
if (m_ses.m_alerts.should_post(alert::warning))
|
||||
{
|
||||
m_ses.m_alerts.post_alert(tracker_warning_alert(get_handle(), msg));
|
||||
m_ses.m_alerts.post_alert(tracker_warning_alert(get_handle(), req.url, msg));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -792,10 +802,8 @@ namespace libtorrent
|
|||
|
||||
if (m_ses.m_alerts.should_post(alert::info))
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "Got scrape response from tracker: " << req.url;
|
||||
m_ses.m_alerts.post_alert(scrape_reply_alert(
|
||||
get_handle(), m_incomplete, m_complete, s.str()));
|
||||
get_handle(), m_incomplete, m_complete, req.url, "got scrape response from tracker"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -891,10 +899,8 @@ namespace libtorrent
|
|||
|
||||
if (m_ses.m_alerts.should_post(alert::info))
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "Got response from tracker: " << r.url;
|
||||
m_ses.m_alerts.post_alert(tracker_reply_alert(
|
||||
get_handle(), peer_list.size(), s.str()));
|
||||
get_handle(), peer_list.size(), r.url, "got response from tracker"));
|
||||
}
|
||||
m_got_tracker_response = true;
|
||||
}
|
||||
|
@ -3268,6 +3274,42 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void torrent::auto_managed(bool a)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
if (m_auto_managed == a) return;
|
||||
m_auto_managed = a;
|
||||
// recalculate which torrents should be
|
||||
// paused
|
||||
m_ses.m_auto_manage_time_scaler = 0;
|
||||
}
|
||||
|
||||
float torrent::seed_cycles(session_settings const& s) const
|
||||
{
|
||||
if (!is_seed()) return 0.f;
|
||||
|
||||
int seeding = total_seconds(m_seeding_time);
|
||||
int downloading = total_seconds(m_active_time) - seeding;
|
||||
|
||||
// if the seed time limit is set to less than 60 minutes
|
||||
// use 60 minutes, to avoid oscillation
|
||||
float ret = seeding / float((std::max)(s.seed_time_limit, 60 * 60));
|
||||
|
||||
// if it took less than 30 minutes to download, disregard the
|
||||
// seed_time_ratio_limit, since it would make it oscillate too frequent
|
||||
if (downloading > 30 * 60 && s.seed_time_ratio_limit >= 1.f)
|
||||
ret = (std::max)(ret, (seeding / downloading
|
||||
/ s.seed_time_ratio_limit));
|
||||
|
||||
size_type downloaded = (std::max)(m_total_downloaded, m_torrent_file->total_size());
|
||||
if (downloaded > 0 && s.share_ratio_limit >= 1.f)
|
||||
ret = (std::max)(ret, float(m_total_uploaded) / downloaded
|
||||
/ s.share_ratio_limit);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// this is an async operation triggered by the client
|
||||
void torrent::save_resume_data()
|
||||
{
|
||||
|
@ -3612,6 +3654,7 @@ namespace libtorrent
|
|||
st.list_peers = m_policy.num_peers();
|
||||
st.list_seeds = m_policy.num_seeds();
|
||||
st.connect_candidates = m_policy.num_connect_candidates();
|
||||
st.seed_cycles = seed_cycles(m_ses.m_settings);
|
||||
|
||||
st.all_time_upload = m_total_uploaded;
|
||||
st.all_time_download = m_total_downloaded;
|
||||
|
@ -3740,16 +3783,14 @@ namespace libtorrent
|
|||
|
||||
if (m_ses.m_alerts.should_post(alert::warning))
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "tracker: \"" << r.url << "\" timed out";
|
||||
if (r.kind == tracker_request::announce_request)
|
||||
{
|
||||
m_ses.m_alerts.post_alert(tracker_alert(get_handle()
|
||||
, m_failed_trackers + 1, 0, s.str()));
|
||||
m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
|
||||
, m_failed_trackers + 1, 0, r.url, "tracker timed out"));
|
||||
}
|
||||
else if (r.kind == tracker_request::scrape_request)
|
||||
{
|
||||
m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), s.str()));
|
||||
m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), r.url, "tracker timed out"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3772,16 +3813,14 @@ namespace libtorrent
|
|||
#endif
|
||||
if (m_ses.m_alerts.should_post(alert::warning))
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "tracker: \"" << r.url << "\" " << str;
|
||||
if (r.kind == tracker_request::announce_request)
|
||||
{
|
||||
m_ses.m_alerts.post_alert(tracker_alert(get_handle()
|
||||
, m_failed_trackers + 1, response_code, s.str()));
|
||||
m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
|
||||
, m_failed_trackers + 1, response_code, r.url, str));
|
||||
}
|
||||
else if (r.kind == tracker_request::scrape_request)
|
||||
{
|
||||
m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), s.str()));
|
||||
m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), r.url, str));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -265,6 +265,18 @@ namespace libtorrent
|
|||
TORRENT_FORWARD(resume());
|
||||
}
|
||||
|
||||
bool torrent_handle::is_auto_managed() const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
TORRENT_FORWARD_RETURN(is_auto_managed(), true);
|
||||
}
|
||||
|
||||
void torrent_handle::auto_managed(bool m) const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
TORRENT_FORWARD(auto_managed(m));
|
||||
}
|
||||
|
||||
void torrent_handle::set_tracker_login(std::string const& name
|
||||
, std::string const& password) const
|
||||
{
|
||||
|
|
|
@ -144,7 +144,7 @@ namespace libtorrent
|
|||
{
|
||||
std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6";
|
||||
std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6";
|
||||
cb->tracker_warning("the tracker only resolves to an "
|
||||
cb->tracker_warning(tracker_req(), "the tracker only resolves to an "
|
||||
+ tracker_address_type + " address, and you're listening on an "
|
||||
+ bind_address_type + " socket. This may prevent you from receiving incoming connections.");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue