lt sync 2224

This commit is contained in:
Andrew Resch 2008-04-24 07:54:44 +00:00
parent ff837215e3
commit c5eba92174
16 changed files with 651 additions and 442 deletions

View File

@ -56,39 +56,55 @@ namespace libtorrent
struct TORRENT_EXPORT tracker_alert: torrent_alert struct TORRENT_EXPORT tracker_alert: torrent_alert
{ {
tracker_alert(torrent_handle const& h 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 times
, int status , int status
, std::string const& url
, std::string const& msg) , std::string const& msg)
: torrent_alert(h, alert::warning, msg) : tracker_alert(h, url, alert::warning, msg)
, times_in_row(times) , times_in_row(times)
, status_code(status) , status_code(status)
{} {}
virtual std::auto_ptr<alert> clone() const 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 times_in_row;
int status_code; 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 tracker_warning_alert(torrent_handle const& h
, std::string const& url
, std::string const& msg) , std::string const& msg)
: torrent_alert(h, alert::warning, msg) : tracker_alert(h, url, alert::warning, msg)
{} {}
virtual std::auto_ptr<alert> clone() const virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new tracker_warning_alert(*this)); } { 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 scrape_reply_alert(torrent_handle const& h
, int incomplete_ , int incomplete_
, int complete_ , int complete_
, std::string const& url
, std::string const& msg) , std::string const& msg)
: torrent_alert(h, alert::info, msg) : tracker_alert(h, url, alert::info, msg)
, incomplete(incomplete_) , incomplete(incomplete_)
, complete(complete_) , complete(complete_)
{} {}
@ -100,23 +116,25 @@ namespace libtorrent
{ return std::auto_ptr<alert>(new scrape_reply_alert(*this)); } { 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 scrape_failed_alert(torrent_handle const& h
, std::string const& url
, std::string const& msg) , std::string const& msg)
: torrent_alert(h, alert::warning, msg) : tracker_alert(h, url, alert::warning, msg)
{} {}
virtual std::auto_ptr<alert> clone() const virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new scrape_failed_alert(*this)); } { 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 tracker_reply_alert(torrent_handle const& h
, int np , int np
, std::string const& url
, std::string const& msg) , std::string const& msg)
: torrent_alert(h, alert::info, msg) : tracker_alert(h, url, alert::info, msg)
, num_peers(np) , num_peers(np)
{} {}
@ -126,10 +144,12 @@ namespace libtorrent
{ return std::auto_ptr<alert>(new tracker_reply_alert(*this)); } { 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) tracker_announce_alert(torrent_handle const& h
: torrent_alert(h, alert::info, msg) , std::string const& url
, std::string const& msg)
: tracker_alert(h, url, alert::info, msg)
{} {}
virtual std::auto_ptr<alert> clone() const virtual std::auto_ptr<alert> clone() const

View File

@ -198,25 +198,7 @@ namespace libtorrent
, const char* net_interface = 0); , const char* net_interface = 0);
bool is_listening() const; bool is_listening() const;
torrent_handle add_torrent( torrent_handle add_torrent(add_torrent_params const&);
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);
void remove_torrent(torrent_handle const& h, int options); void remove_torrent(torrent_handle const& h, int options);
@ -491,6 +473,10 @@ namespace libtorrent
// recomputed. // recomputed.
int m_unchoke_time_scaler; 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 // works like unchoke_time_scaler but it
// is only decresed when the unchoke set // is only decresed when the unchoke set
// is recomputed, and when it reaches zero, // is recomputed, and when it reaches zero,
@ -513,6 +499,10 @@ namespace libtorrent
bool m_incoming_connection; bool m_incoming_connection;
void second_tick(asio::error_code const& e); 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; ptime m_last_tick;
// when outgoing_ports is configured, this is the // when outgoing_ports is configured, this is the
@ -532,6 +522,10 @@ namespace libtorrent
// but for the udp port used by the DHT. // but for the udp port used by the DHT.
int m_external_udp_port; 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; udp_socket m_dht_socket;
void on_receive_udp(asio::error_code const& e void on_receive_udp(asio::error_code const& e
@ -613,7 +607,8 @@ namespace libtorrent
struct tracker_logger : request_callback struct tracker_logger : request_callback
{ {
tracker_logger(session_impl& ses): m_ses(ses) {} 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); debug_log("*** tracker warning: " + str);
} }

View File

@ -260,8 +260,17 @@ namespace libtorrent
m_num_connect_candidates = 1; m_num_connect_candidates = 1;
} }
void erase_peer(iterator i);
private: 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_disconnect_candidate();
iterator find_connect_candidate(); iterator find_connect_candidate();

View File

@ -62,6 +62,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/fingerprint.hpp" #include "libtorrent/fingerprint.hpp"
#include "libtorrent/time.hpp" #include "libtorrent/time.hpp"
#include "libtorrent/disk_io_thread.hpp" #include "libtorrent/disk_io_thread.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/storage.hpp" #include "libtorrent/storage.hpp"
@ -120,6 +121,34 @@ namespace libtorrent
boost::shared_ptr<aux::session_impl> m_impl; 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 class TORRENT_EXPORT session: public boost::noncopyable, aux::eh_initializer
{ {
public: public:
@ -148,6 +177,9 @@ namespace libtorrent
torrent_handle find_torrent(sha1_hash const& info_hash) const; torrent_handle find_torrent(sha1_hash const& info_hash) const;
// all torrent_handles must be destructed before the session is destructed! // 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_handle add_torrent(
torrent_info const& ti torrent_info const& ti
, fs::path const& save_path , fs::path const& save_path
@ -156,6 +188,7 @@ namespace libtorrent
, bool paused = false , bool paused = false
, storage_constructor_type sc = default_storage_constructor) TORRENT_DEPRECATED; , storage_constructor_type sc = default_storage_constructor) TORRENT_DEPRECATED;
// deprecated in 0.14
torrent_handle add_torrent( torrent_handle add_torrent(
boost::intrusive_ptr<torrent_info> ti boost::intrusive_ptr<torrent_info> ti
, fs::path const& save_path , fs::path const& save_path
@ -163,8 +196,9 @@ namespace libtorrent
, storage_mode_t storage_mode = storage_mode_sparse , storage_mode_t storage_mode = storage_mode_sparse
, bool paused = false , bool paused = false
, storage_constructor_type sc = default_storage_constructor , storage_constructor_type sc = default_storage_constructor
, void* userdata = 0); , void* userdata = 0) TORRENT_DEPRECATED;
// deprecated in 0.14
torrent_handle add_torrent( torrent_handle add_torrent(
char const* tracker_url char const* tracker_url
, sha1_hash const& info_hash , sha1_hash const& info_hash
@ -174,7 +208,7 @@ namespace libtorrent
, storage_mode_t storage_mode = storage_mode_sparse , storage_mode_t storage_mode = storage_mode_sparse
, bool paused = false , bool paused = false
, storage_constructor_type sc = default_storage_constructor , storage_constructor_type sc = default_storage_constructor
, void* userdata = 0); , void* userdata = 0) TORRENT_DEPRECATED;
session_proxy abort() { return session_proxy(m_impl); } session_proxy abort() { return session_proxy(m_impl); }

View File

@ -128,6 +128,12 @@ namespace libtorrent
, cache_expiry(60) , cache_expiry(60)
, outgoing_ports(0,0) , outgoing_ports(0,0)
, peer_tos(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 // this is the user agent that will be sent to the tracker
@ -347,6 +353,29 @@ namespace libtorrent
// http://qbone.internet2.edu/qbss/ // http://qbone.internet2.edu/qbss/
// For unmarked packets, set to 0 // For unmarked packets, set to 0
char peer_tos; 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 #ifndef TORRENT_DISABLE_DHT

View File

@ -105,7 +105,9 @@ namespace libtorrent
, int block_size , int block_size
, storage_constructor_type sc , storage_constructor_type sc
, bool paused , bool paused
, entry const& resume_data); , entry const* resume_data
, int seq
, bool auto_managed);
// used with metadata-less torrents // used with metadata-less torrents
// (the metadata is downloaded from the peers) // (the metadata is downloaded from the peers)
@ -120,7 +122,9 @@ namespace libtorrent
, int block_size , int block_size
, storage_constructor_type sc , storage_constructor_type sc
, bool paused , bool paused
, entry const& resume_data); , entry const* resume_data
, int seq
, bool auto_managed);
~torrent(); ~torrent();
@ -147,6 +151,9 @@ namespace libtorrent
void files_checked(); void files_checked();
void start_checking(); 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; } storage_mode_t storage_mode() const { return m_storage_mode; }
// this will flag the torrent as aborted. The main // this will flag the torrent as aborted. The main
// loop in session_impl will check for this state // loop in session_impl will check for this state
@ -180,6 +187,9 @@ namespace libtorrent
bool is_paused() const { return m_paused; } bool is_paused() const { return m_paused; }
void save_resume_data(); void save_resume_data();
bool is_auto_managed() const { return m_auto_managed; }
void auto_managed(bool a);
void delete_files(); void delete_files();
// ============ start deprecation ============= // ============ start deprecation =============
@ -318,7 +328,8 @@ namespace libtorrent
tracker_request const& r); tracker_request const& r);
virtual void tracker_request_error(tracker_request const& r virtual void tracker_request_error(tracker_request const& r
, int response_code, const std::string& str); , 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 virtual void tracker_scrape_response(tracker_request const& req
, int complete, int incomplete, int downloaded); , int complete, int incomplete, int downloaded);
@ -561,6 +572,8 @@ namespace libtorrent
// a return value of false indicates an error // a return value of false indicates an error
bool set_metadata(entry const& metadata, std::string& error); bool set_metadata(entry const& metadata, std::string& error);
int sequence_number() const { return m_sequence_number; }
private: private:
void on_files_deleted(int ret, disk_io_job const& j); 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 // paused to the time should_request() is called
bool m_just_paused; 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; tracker_request::event_t m_event;
void parse_response(const entry& e, std::vector<peer_entry>& peer_list); void parse_response(const entry& e, std::vector<peer_entry>& peer_list);

View File

@ -118,6 +118,7 @@ namespace libtorrent
, all_time_download(0) , all_time_download(0)
, active_time(0) , active_time(0)
, seeding_time(0) , seeding_time(0)
, seed_cycles(0.f)
{} {}
enum state_t enum state_t
@ -255,6 +256,8 @@ namespace libtorrent
// from resume data // from resume data
int active_time; int active_time;
int seeding_time; int seeding_time;
float seed_cycles;
}; };
struct TORRENT_EXPORT block_info struct TORRENT_EXPORT block_info
@ -332,6 +335,9 @@ namespace libtorrent
void resume() const; void resume() const;
void save_resume_data() const; void save_resume_data() const;
bool is_auto_managed() const;
void auto_managed(bool m) const;
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
void resolve_countries(bool r); void resolve_countries(bool r);
bool resolve_countries() const; bool resolve_countries() const;
@ -342,6 +348,7 @@ namespace libtorrent
// ================ start deprecation ============ // ================ start deprecation ============
// deprecated in 0.13
// marks the piece with the given index as filtered // marks the piece with the given index as filtered
// it will not be downloaded // it will not be downloaded
void filter_piece(int index, bool filter) const TORRENT_DEPRECATED; void filter_piece(int index, bool filter) const TORRENT_DEPRECATED;
@ -370,6 +377,7 @@ namespace libtorrent
// to. // to.
void use_interface(const char* net_interface) const; void use_interface(const char* net_interface) const;
// deprecated in 0.14
// use save_resume_data() instead. It is async. and // use save_resume_data() instead. It is async. and
// will return the resume data in an alert // will return the resume data in an alert
entry write_resume_data() const TORRENT_DEPRECATED; entry write_resume_data() const TORRENT_DEPRECATED;

View File

@ -118,20 +118,21 @@ namespace libtorrent
friend class tracker_manager; friend class tracker_manager;
request_callback(): m_manager(0) {} request_callback(): m_manager(0) {}
virtual ~request_callback() {} 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 virtual void tracker_scrape_response(tracker_request const& req
, int complete, int incomplete, int downloads) {} , int complete, int incomplete, int downloads) {}
virtual void tracker_response( virtual void tracker_response(
tracker_request const& tracker_request const& req
, std::vector<peer_entry>& peers , std::vector<peer_entry>& peers
, int interval , int interval
, int complete , int complete
, int incomplete , int incomplete
, address const& external_ip) = 0; , address const& external_ip) = 0;
virtual void tracker_request_timed_out( virtual void tracker_request_timed_out(
tracker_request const&) = 0; tracker_request const& req) = 0;
virtual void tracker_request_error( virtual void tracker_request_error(
tracker_request const& tracker_request const& req
, int response_code , int response_code
, const std::string& description) = 0; , const std::string& description) = 0;

View File

@ -2449,6 +2449,7 @@ namespace libtorrent
if (pid == m_ses.get_peer_id()) if (pid == m_ses.get_peer_id())
{ {
set_failed();
disconnect("closing connection to ourself"); disconnect("closing connection to ourself");
return; return;
} }
@ -2465,6 +2466,7 @@ namespace libtorrent
// since it most likely is ourself then // since it most likely is ourself then
if (pid == m_ses.get_peer_id()) if (pid == m_ses.get_peer_id())
{ {
set_failed();
disconnect("closing connection to ourself"); disconnect("closing connection to ourself");
return; return;
} }

View File

@ -306,7 +306,7 @@ namespace libtorrent
entry const* warning = e.find_key("warning message"); entry const* warning = e.find_key("warning message");
if (warning && warning->type() == entry::string_t) 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; std::vector<peer_entry> peer_list;

View File

@ -384,12 +384,26 @@ namespace libtorrent
, "blocked peer removed from peer list")); , "blocked peer removed from peer list"));
} }
} }
if (p) p->clear_peer(&i->second); erase_peer(i++);
if (i->second.seed) --m_num_seeds;
m_peers.erase(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) bool policy::is_connect_candidate(peer const& p, bool finished)
{ {
if (p.connection if (p.connection
@ -450,16 +464,14 @@ namespace libtorrent
policy::iterator policy::find_connect_candidate() policy::iterator policy::find_connect_candidate()
{ {
INVARIANT_CHECK; // too expensive
// INVARIANT_CHECK;
ptime now = time_now(); ptime now = time_now();
ptime min_connect_time(now);
iterator candidate = m_peers.end(); iterator candidate = m_peers.end();
int min_reconnect_time = m_torrent->settings().min_reconnect_time; int min_reconnect_time = m_torrent->settings().min_reconnect_time;
bool finished = m_torrent->is_finished(); bool finished = m_torrent->is_finished();
int min_cidr_distance = (std::numeric_limits<int>::max)();
address external_ip = m_torrent->session().external_address(); address external_ip = m_torrent->session().external_address();
// don't bias any particular peers when seeding // don't bias any particular peers when seeding
@ -472,75 +484,35 @@ namespace libtorrent
external_ip = address_v4(bytes); external_ip = address_v4(bytes);
} }
#ifndef TORRENT_DISABLE_GEO_IP if (m_round_robin == iterator() || m_round_robin == m_peers.end())
int max_inet_as_rate = -1; m_round_robin = m_peers.begin();
bool has_db = m_torrent->session().has_asnum_db();
#endif
int connect_candidates = 0; for (int iterations = (std::min)(int(m_peers.size()), 300);
int seeds = 0; iterations > 0; ++m_round_robin, --iterations)
for (iterator i = m_peers.begin(); i != m_peers.end(); ++i)
{ {
if (i->second.seed) ++seeds; if (m_round_robin == m_peers.end()) m_round_robin = m_peers.begin();
if (!is_connect_candidate(i->second, finished)) continue;
++connect_candidates; if (!is_connect_candidate(m_round_robin->second, finished)) continue;
// prefer peers with lower failcount
if (candidate != m_peers.end() 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; continue;
if (now - i->second.connected < seconds(i->second.failcount * min_reconnect_time)) candidate = m_round_robin;
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;
} }
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 defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
if (candidate != m_peers.end()) if (candidate != m_peers.end())
{ {
(*m_torrent->session().m_logger) << time_now_string() (*m_torrent->session().m_logger) << time_now_string()
<< " *** FOUND CONNECTION CANDIDATE [" << " *** FOUND CONNECTION CANDIDATE ["
" ip: " << candidate->second.ip << " ip: " << candidate->second.ip <<
" d: " << min_cidr_distance << " d: " << cidr_distance(external_ip, candidate->second.ip.address()) <<
" external: " << external_ip << " external: " << external_ip <<
" t: " << total_seconds(time_now() - min_connect_time) << " t: " << total_seconds(time_now() - candidate->second.connected) <<
" ]\n"; " ]\n";
} }
#endif #endif
@ -554,10 +526,6 @@ namespace libtorrent
if (m_torrent->is_paused()) return; if (m_torrent->is_paused()) return;
piece_picker* p = 0;
if (m_torrent->has_picker())
p = &m_torrent->picker();
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
bool pinged = false; bool pinged = false;
#endif #endif
@ -589,9 +557,7 @@ namespace libtorrent
&& !pe.banned && !pe.banned
&& now - pe.connected > minutes(120)) && now - pe.connected > minutes(120))
{ {
if (p) p->clear_peer(&pe); erase_peer(i++);
if (pe.seed) --m_num_seeds;
m_peers.erase(i++);
} }
else 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 // upload shift
// ------------------------ // ------------------------
@ -769,6 +689,9 @@ namespace libtorrent
"with higher priority, closing"); "with higher priority, closing");
} }
} }
if (m_num_connect_candidates > 0)
--m_num_connect_candidates;
} }
else else
{ {
@ -797,8 +720,6 @@ namespace libtorrent
TORRENT_ASSERT(i->second.connection); TORRENT_ASSERT(i->second.connection);
if (!c.fast_reconnect()) if (!c.fast_reconnect())
i->second.connected = time_now(); i->second.connected = time_now();
if (m_num_connect_candidates > 0)
--m_num_connect_candidates;
return true; return true;
} }
@ -823,10 +744,7 @@ namespace libtorrent
p->connection->disconnect("duplicate connection"); p->connection->disconnect("duplicate connection");
return false; return false;
} }
if (m_torrent->has_picker()) erase_peer(i);
m_torrent->picker().clear_peer(&i->second);
if (i->second.seed) --m_num_seeds;
m_peers.erase(i);
} }
} }
else else
@ -859,7 +777,8 @@ namespace libtorrent
policy::peer* policy::peer_from_tracker(tcp::endpoint const& remote, peer_id const& pid policy::peer* policy::peer_from_tracker(tcp::endpoint const& remote, peer_id const& pid
, int src, char flags) , int src, char flags)
{ {
INVARIANT_CHECK; // way too expensive
//INVARIANT_CHECK;
// just ignore the obviously invalid entries // just ignore the obviously invalid entries
if (remote.address() == address() || remote.port() == 0) if (remote.address() == address() || remote.port() == 0)
@ -1405,5 +1324,38 @@ namespace libtorrent
return prev_amount_upload; 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;
}
} }

View File

@ -239,6 +239,10 @@ namespace libtorrent
return m_impl->find_torrent_handle(info_hash); 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 // if the torrent already exists, this will throw duplicate_torrent
torrent_handle session::add_torrent( torrent_handle session::add_torrent(
@ -251,8 +255,13 @@ namespace libtorrent
{ {
TORRENT_ASSERT(!ti.m_half_metadata); TORRENT_ASSERT(!ti.m_half_metadata);
boost::intrusive_ptr<torrent_info> tip(new torrent_info(ti)); boost::intrusive_ptr<torrent_info> tip(new torrent_info(ti));
return m_impl->add_torrent(tip, save_path, resume_data add_torrent_params p(sc);
, storage_mode, sc, paused, 0); 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( torrent_handle session::add_torrent(
@ -265,8 +274,14 @@ namespace libtorrent
, void* userdata) , void* userdata)
{ {
TORRENT_ASSERT(!ti->m_half_metadata); TORRENT_ASSERT(!ti->m_half_metadata);
return m_impl->add_torrent(ti, save_path, resume_data add_torrent_params p(sc);
, storage_mode, sc, paused, userdata); 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( torrent_handle session::add_torrent(
@ -280,8 +295,13 @@ namespace libtorrent
, storage_constructor_type sc , storage_constructor_type sc
, void* userdata) , void* userdata)
{ {
return m_impl->add_torrent(tracker_url, info_hash, name, save_path, e add_torrent_params p(sc);
, storage_mode, sc, paused, userdata); 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) void session::remove_torrent(const torrent_handle& h, int options)

View File

@ -74,6 +74,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/kademlia/dht_tracker.hpp" #include "libtorrent/kademlia/dht_tracker.hpp"
#include "libtorrent/enum_net.hpp" #include "libtorrent/enum_net.hpp"
#include "libtorrent/config.hpp"
#ifndef TORRENT_DISABLE_ENCRYPTION #ifndef TORRENT_DISABLE_ENCRYPTION
@ -158,6 +159,7 @@ namespace aux {
, m_max_connections(200) , m_max_connections(200)
, m_num_unchoked(0) , m_num_unchoked(0)
, m_unchoke_time_scaler(0) , m_unchoke_time_scaler(0)
, m_auto_manage_time_scaler(0)
, m_optimistic_unchoke_time_scaler(0) , m_optimistic_unchoke_time_scaler(0)
, m_disconnect_time_scaler(90) , m_disconnect_time_scaler(90)
, m_incoming_connection(false) , m_incoming_connection(false)
@ -165,6 +167,7 @@ namespace aux {
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
, m_dht_same_port(true) , m_dht_same_port(true)
, m_external_udp_port(0) , 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_dht_socket(m_io_service, bind(&session_impl::on_receive_udp, this, _1, _2, _3, _4)
, m_half_open) , m_half_open)
#endif #endif
@ -762,7 +765,7 @@ namespace aux {
+ boost::lexical_cast<std::string>(ep) + "' " + e.message(); + boost::lexical_cast<std::string>(ep) + "' " + e.message();
(*m_logger) << msg << "\n"; (*m_logger) << msg << "\n";
#endif #endif
#ifdef _WIN32 #ifdef TORRENT_WINDOWS
// Windows sometimes generates this error. It seems to be // Windows sometimes generates this error. It seems to be
// non-fatal and we have to do another async_accept. // non-fatal and we have to do another async_accept.
if (e.value() == ERROR_SEM_TIMEOUT) if (e.value() == ERROR_SEM_TIMEOUT)
@ -1035,7 +1038,7 @@ namespace aux {
{ {
m_alerts.post_alert( m_alerts.post_alert(
tracker_announce_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(); 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 // unchoke set and optimistic unchoke calculations
// -------------------------------------------------------------- // --------------------------------------------------------------
@ -1180,173 +1193,8 @@ namespace aux {
if (m_unchoke_time_scaler <= 0 && !m_connections.empty()) if (m_unchoke_time_scaler <= 0 && !m_connections.empty())
{ {
m_unchoke_time_scaler = settings().unchoke_interval; m_unchoke_time_scaler = settings().unchoke_interval;
recalculate_unchoke_slots(congested_torrents
std::vector<peer_connection*> peers; , uncongested_torrents);
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;
}
}
} }
// -------------------------------------------------------------- // --------------------------------------------------------------
@ -1357,7 +1205,7 @@ namespace aux {
{ {
m_disconnect_time_scaler = 90; 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 we have reached the connection limit
if (num_connections() >= max_connections() && !m_torrents.empty()) 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()() void session_impl::operator()()
{ {
eh_initializer(); eh_initializer();
@ -1476,18 +1587,11 @@ namespace aux {
return torrent_handle(find_torrent(info_hash)); return torrent_handle(find_torrent(info_hash));
} }
torrent_handle session_impl::add_torrent( torrent_handle session_impl::add_torrent(add_torrent_params const& params)
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_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 #ifndef BOOST_NO_EXCEPTIONS
throw std::runtime_error("no files in torrent"); throw std::runtime_error("no files in torrent");
@ -1510,9 +1614,18 @@ namespace aux {
#endif #endif
} }
// figure out the info hash of the torrent
sha1_hash const* ih = 0;
if (params.ti) ih = &params.ti->info_hash();
else ih = &params.info_hash;
// is the torrent already active? // 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 #ifndef BOOST_NO_EXCEPTIONS
throw duplicate_torrent(); throw duplicate_torrent();
#else #else
@ -1523,25 +1636,36 @@ namespace aux {
// create the torrent and the data associated with // create the torrent and the data associated with
// the checker thread and store it before starting // the checker thread and store it before starting
// the thread // the thread
boost::shared_ptr<torrent> torrent_ptr( if (params.ti)
new torrent(*this, ti, save_path {
, m_listen_interface, storage_mode, 16 * 1024 torrent_ptr.reset(new torrent(*this, params.ti, params.save_path
, sc, paused, resume_data)); , 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(); torrent_ptr->start();
++m_torrent_sequence;
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin() for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i) , 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); if (tp) torrent_ptr->add_extension(tp);
} }
#endif #endif
#ifndef TORRENT_DISABLE_DHT #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( std::for_each(nodes.begin(), nodes.end(), bind(
(void(dht::dht_tracker::*)(std::pair<std::string, int> const&)) (void(dht::dht_tracker::*)(std::pair<std::string, int> const&))
&dht::dht_tracker::add_node &dht::dht_tracker::add_node
@ -1549,7 +1673,7 @@ namespace aux {
} }
#endif #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); return torrent_handle(torrent_ptr);
} }
@ -1568,62 +1692,6 @@ namespace aux {
m_queued_for_checking.front()->start_checking(); 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) void session_impl::remove_torrent(const torrent_handle& h, int options)
{ {
boost::shared_ptr<torrent> tptr = h.m_torrent.lock(); boost::shared_ptr<torrent> tptr = h.m_torrent.lock();
@ -1672,7 +1740,7 @@ namespace aux {
{ {
m_alerts.post_alert( m_alerts.post_alert(
tracker_announce_alert( tracker_announce_alert(
t.get_handle(), "tracker announce, event=stopped")); t.get_handle(), req.url, "tracker announce, event=stopped"));
} }
} }
#ifndef NDEBUG #ifndef NDEBUG

View File

@ -157,11 +157,14 @@ namespace libtorrent
, int block_size , int block_size
, storage_constructor_type sc , storage_constructor_type sc
, bool paused , bool paused
, entry const& resume_data) , entry const* resume_data
, int seq
, bool auto_managed)
: m_torrent_file(tf) : m_torrent_file(tf)
, m_abort(false) , m_abort(false)
, m_paused(paused) , m_paused(paused)
, m_just_paused(false) , m_just_paused(false)
, m_auto_managed(auto_managed)
, m_event(tracker_request::started) , m_event(tracker_request::started)
, m_block_size(0) , m_block_size(0)
, m_storage(0) , m_storage(0)
@ -196,7 +199,6 @@ namespace libtorrent
, m_storage_mode(storage_mode) , m_storage_mode(storage_mode)
, m_state(torrent_status::queued_for_checking) , m_state(torrent_status::queued_for_checking)
, m_progress(0.f) , m_progress(0.f)
, m_resume_data(resume_data)
, m_default_block_size(block_size) , m_default_block_size(block_size)
, m_connections_initialized(true) , m_connections_initialized(true)
, m_settings(ses.settings()) , m_settings(ses.settings())
@ -206,11 +208,13 @@ namespace libtorrent
, m_max_connections((std::numeric_limits<int>::max)()) , m_max_connections((std::numeric_limits<int>::max)())
, m_deficit_counter(0) , m_deficit_counter(0)
, m_policy(this) , m_policy(this)
, m_sequence_number(seq)
, m_active_time(seconds(0)) , m_active_time(seconds(0))
, m_seeding_time(seconds(0)) , m_seeding_time(seconds(0))
, m_total_uploaded(0) , m_total_uploaded(0)
, m_total_downloaded(0) , m_total_downloaded(0)
{ {
if (resume_data) m_resume_data = *resume_data;
#ifndef NDEBUG #ifndef NDEBUG
m_files_checked = false; m_files_checked = false;
#endif #endif
@ -227,11 +231,14 @@ namespace libtorrent
, int block_size , int block_size
, storage_constructor_type sc , storage_constructor_type sc
, bool paused , bool paused
, entry const& resume_data) , entry const* resume_data
, int seq
, bool auto_managed)
: m_torrent_file(new torrent_info(info_hash)) : m_torrent_file(new torrent_info(info_hash))
, m_abort(false) , m_abort(false)
, m_paused(paused) , m_paused(paused)
, m_just_paused(false) , m_just_paused(false)
, m_auto_managed(auto_managed)
, m_event(tracker_request::started) , m_event(tracker_request::started)
, m_block_size(0) , m_block_size(0)
, m_storage(0) , m_storage(0)
@ -265,7 +272,6 @@ namespace libtorrent
, m_storage_mode(storage_mode) , m_storage_mode(storage_mode)
, m_state(torrent_status::queued_for_checking) , m_state(torrent_status::queued_for_checking)
, m_progress(0.f) , m_progress(0.f)
, m_resume_data(resume_data)
, m_default_block_size(block_size) , m_default_block_size(block_size)
, m_connections_initialized(false) , m_connections_initialized(false)
, m_settings(ses.settings()) , m_settings(ses.settings())
@ -275,11 +281,13 @@ namespace libtorrent
, m_max_connections((std::numeric_limits<int>::max)()) , m_max_connections((std::numeric_limits<int>::max)())
, m_deficit_counter(0) , m_deficit_counter(0)
, m_policy(this) , m_policy(this)
, m_sequence_number(seq)
, m_active_time(seconds(0)) , m_active_time(seconds(0))
, m_seeding_time(seconds(0)) , m_seeding_time(seconds(0))
, m_total_uploaded(0) , m_total_uploaded(0)
, m_total_downloaded(0) , m_total_downloaded(0)
{ {
if (resume_data) m_resume_data = *resume_data;
#ifndef NDEBUG #ifndef NDEBUG
m_files_checked = false; m_files_checked = false;
#endif #endif
@ -453,6 +461,7 @@ namespace libtorrent
} }
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false); std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
m_num_pieces = 0; m_num_pieces = 0;
auto_managed(false);
pause(); pause();
return; return;
} }
@ -633,6 +642,7 @@ namespace libtorrent
} }
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false); std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
m_num_pieces = 0; m_num_pieces = 0;
auto_managed(false);
pause(); pause();
m_ses.done_checking(shared_from_this()); m_ses.done_checking(shared_from_this());
return; return;
@ -727,7 +737,7 @@ namespace libtorrent
if (m_ses.m_alerts.should_post(alert::info)) if (m_ses.m_alerts.should_post(alert::info))
{ {
m_ses.m_alerts.post_alert(tracker_reply_alert( 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( std::for_each(peers.begin(), peers.end(), bind(
&policy::peer_from_tracker, boost::ref(m_policy), _1, peer_id(0) &policy::peer_from_tracker, boost::ref(m_policy), _1, peer_id(0)
@ -767,7 +777,7 @@ namespace libtorrent
return !m_paused && m_next_request < time_now(); 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); 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)) 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)) 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( 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)) 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( 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; 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 // this is an async operation triggered by the client
void torrent::save_resume_data() void torrent::save_resume_data()
{ {
@ -3612,6 +3654,7 @@ namespace libtorrent
st.list_peers = m_policy.num_peers(); st.list_peers = m_policy.num_peers();
st.list_seeds = m_policy.num_seeds(); st.list_seeds = m_policy.num_seeds();
st.connect_candidates = m_policy.num_connect_candidates(); 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_upload = m_total_uploaded;
st.all_time_download = m_total_downloaded; st.all_time_download = m_total_downloaded;
@ -3740,16 +3783,14 @@ namespace libtorrent
if (m_ses.m_alerts.should_post(alert::warning)) 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) if (r.kind == tracker_request::announce_request)
{ {
m_ses.m_alerts.post_alert(tracker_alert(get_handle() m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
, m_failed_trackers + 1, 0, s.str())); , m_failed_trackers + 1, 0, r.url, "tracker timed out"));
} }
else if (r.kind == tracker_request::scrape_request) 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 #endif
if (m_ses.m_alerts.should_post(alert::warning)) if (m_ses.m_alerts.should_post(alert::warning))
{ {
std::stringstream s;
s << "tracker: \"" << r.url << "\" " << str;
if (r.kind == tracker_request::announce_request) if (r.kind == tracker_request::announce_request)
{ {
m_ses.m_alerts.post_alert(tracker_alert(get_handle() m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
, m_failed_trackers + 1, response_code, s.str())); , m_failed_trackers + 1, response_code, r.url, str));
} }
else if (r.kind == tracker_request::scrape_request) 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));
} }
} }

View File

@ -265,6 +265,18 @@ namespace libtorrent
TORRENT_FORWARD(resume()); 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 void torrent_handle::set_tracker_login(std::string const& name
, std::string const& password) const , std::string const& password) const
{ {

View File

@ -144,7 +144,7 @@ namespace libtorrent
{ {
std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6"; std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6";
std::string bind_address_type = bind_interface().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 " + tracker_address_type + " address, and you're listening on an "
+ bind_address_type + " socket. This may prevent you from receiving incoming connections."); + bind_address_type + " socket. This may prevent you from receiving incoming connections.");
} }