revert last...too many changes for now

This commit is contained in:
Marcos Pinto 2007-08-16 23:49:18 +00:00
parent 476a72b0e4
commit 1973d7c9e3
16 changed files with 1136 additions and 342 deletions

View File

@ -261,17 +261,6 @@ namespace libtorrent
{ return std::auto_ptr<alert>(new torrent_paused_alert(*this)); }
};
struct TORRENT_EXPORT torrent_checked_alert: torrent_alert
{
torrent_checked_alert(torrent_handle const& h, std::string const& msg)
: torrent_alert(h, alert::info, msg)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new torrent_checked_alert(*this)); }
};
struct TORRENT_EXPORT url_seed_alert: torrent_alert
{
url_seed_alert(

View File

@ -0,0 +1,78 @@
/*
Copyright (c) 2003, Magnus Jonsson
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_ALLOCATE_RESOURCES_HPP_INCLUDED
#define TORRENT_ALLOCATE_RESOURCES_HPP_INCLUDED
#include <map>
#include <utility>
#include <boost/shared_ptr.hpp>
#include "libtorrent/resource_request.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/session.hpp"
namespace libtorrent
{
class peer_connection;
class torrent;
int saturated_add(int a, int b);
// Function to allocate a limited resource fairly among many consumers.
// It takes into account the current use, and the consumer's desired use.
// Should be invoked periodically to allow it adjust to the situation (make
// sure "used" is updated between calls!).
// If resources = std::numeric_limits<int>::max() it means there is an infinite
// supply of resources (so everyone can get what they want).
void allocate_resources(
int resources
, std::map<sha1_hash, boost::shared_ptr<torrent> >& torrents
, resource_request torrent::* res);
void allocate_resources(
int resources
, std::map<tcp::endpoint, peer_connection*>& connections
, resource_request peer_connection::* res);
// Used for global limits.
void allocate_resources(
int resources
, std::vector<session*>& _sessions
, resource_request session::* res);
}
#endif

View File

@ -65,6 +65,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert.hpp"
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/allocate_resources.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/piece_block_progress.hpp"
#include "libtorrent/config.hpp"

View File

@ -64,6 +64,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert.hpp"
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/allocate_resources.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/piece_block_progress.hpp"
#include "libtorrent/config.hpp"
@ -212,7 +213,7 @@ namespace libtorrent
void add_stat(size_type downloaded, size_type uploaded);
// is called once every second by the main loop
void second_tick(float tick_interval) throw();
void second_tick(float tick_interval);
boost::shared_ptr<socket_type> get_socket() const { return m_socket; }
tcp::endpoint const& remote() const { return m_remote; }

View File

@ -155,13 +155,6 @@ namespace libtorrent
// this is true if the peer is a seed
bool seed;
// true if this peer currently is unchoked
// because of an optimistic unchoke.
// when the optimistic unchoke is moved to
// another peer, this peer will be choked
// if this is true
bool optimistically_unchoked;
// the time when this peer was optimistically unchoked
// the last time.
libtorrent::ptime last_optimistically_unchoked;
@ -210,18 +203,25 @@ namespace libtorrent
peer_connection* connection;
};
int num_peers() const { return m_peers.size(); }
int num_peers() const
{
return m_peers.size();
}
int num_uploads() const
{
return m_num_unchoked;
}
typedef std::list<peer>::iterator iterator;
typedef std::list<peer>::const_iterator const_iterator;
iterator begin_peer() { return m_peers.begin(); }
iterator end_peer() { return m_peers.end(); }
bool connect_one_peer();
bool disconnect_one_peer();
private:
/*
bool unchoke_one_peer();
void choke_one_peer();
iterator find_choke_candidate();
@ -233,7 +233,8 @@ namespace libtorrent
void seed_choke_one_peer();
iterator find_seed_choke_candidate();
iterator find_seed_unchoke_candidate();
*/
bool disconnect_one_peer();
iterator find_disconnect_candidate();
iterator find_connect_candidate();
@ -241,6 +242,10 @@ namespace libtorrent
torrent* m_torrent;
// the number of unchoked peers
// at any given time
int m_num_unchoked;
// free download we have got that hasn't
// been distributed yet.
size_type m_available_free_upload;
@ -248,7 +253,7 @@ namespace libtorrent
// if there is a connection limit,
// we disconnect one peer every minute in hope of
// establishing a connection with a better peer
// ptime m_last_optimistic_disconnect;
ptime m_last_optimistic_disconnect;
};
}

View File

@ -61,6 +61,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/version.hpp"
#include "libtorrent/fingerprint.hpp"
#include "libtorrent/resource_request.hpp"
#include "libtorrent/storage.hpp"
#ifdef _MSC_VER
@ -265,6 +266,12 @@ namespace libtorrent
void stop_natpmp();
void stop_upnp();
// Resource management used for global limits.
resource_request m_ul_bandwidth_quota;
resource_request m_dl_bandwidth_quota;
resource_request m_uploads_quota;
resource_request m_connections_quota;
private:
// just a way to initialize boost.filesystem

View File

@ -0,0 +1,594 @@
/*
Copyright (c) 2006, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_SESSION_IMPL_HPP_INCLUDED
#define TORRENT_SESSION_IMPL_HPP_INCLUDED
#include <ctime>
#include <algorithm>
#include <vector>
#include <set>
#include <list>
#include <deque>
#ifdef _MSC_VER
#pragma warning(push, 1)
#endif
#include <boost/limits.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/thread.hpp>
#include <boost/thread/recursive_mutex.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/torrent_info.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/peer_connection.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/policy.hpp"
#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/peer_info.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/fingerprint.hpp"
#include "libtorrent/debug.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/piece_block_progress.hpp"
#include "libtorrent/ip_filter.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/kademlia/dht_tracker.hpp"
#include "libtorrent/session_status.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/stat.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/bandwidth_manager.hpp"
#include "libtorrent/natpmp.hpp"
#include "libtorrent/upnp.hpp"
#include "libtorrent/lsd.hpp"
#include "libtorrent/socket_type.hpp"
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/disk_io_thread.hpp"
namespace libtorrent
{
namespace fs = boost::filesystem;
namespace aux
{
struct session_impl;
// this data is shared between the main thread and the
// thread that initialize pieces
struct piece_checker_data
{
piece_checker_data()
: processing(false), progress(0.f), abort(false) {}
boost::shared_ptr<torrent> torrent_ptr;
fs::path save_path;
sha1_hash info_hash;
void parse_resume_data(
const entry& rd
, const torrent_info& info
, std::string& error);
std::vector<int> piece_map;
std::vector<piece_picker::downloading_piece> unfinished_pieces;
std::vector<piece_picker::block_info> block_info;
std::vector<tcp::endpoint> peers;
entry resume_data;
// this is true if this torrent is being processed (checked)
// if it is not being processed, then it can be removed from
// the queue without problems, otherwise the abort flag has
// to be set.
bool processing;
// is filled in by storage::initialize_pieces()
// and represents the progress. It should be a
// value in the range [0, 1]
float progress;
// abort defaults to false and is typically
// filled in by torrent_handle when the user
// aborts the torrent
bool abort;
};
struct checker_impl: boost::noncopyable
{
checker_impl(session_impl& s): m_ses(s), m_abort(false) {}
void operator()();
piece_checker_data* find_torrent(const sha1_hash& info_hash);
void remove_torrent(sha1_hash const& info_hash);
#ifndef NDEBUG
void check_invariant() const;
#endif
// when the files has been checked
// the torrent is added to the session
session_impl& m_ses;
mutable boost::mutex m_mutex;
boost::condition m_cond;
// a list of all torrents that are currently in queue
// or checking their files
std::deque<boost::shared_ptr<piece_checker_data> > m_torrents;
std::deque<boost::shared_ptr<piece_checker_data> > m_processing;
bool m_abort;
};
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
struct tracker_logger;
#endif
// this is the link between the main thread and the
// thread started to run the main downloader loop
struct session_impl: boost::noncopyable
{
#ifndef NDEBUG
friend class ::libtorrent::peer_connection;
#endif
friend struct checker_impl;
friend class invariant_access;
typedef std::map<boost::shared_ptr<socket_type>
, boost::intrusive_ptr<peer_connection> >
connection_map;
typedef std::map<sha1_hash, boost::shared_ptr<torrent> > torrent_map;
session_impl(
std::pair<int, int> listen_port_range
, fingerprint const& cl_fprint
, char const* listen_interface = "0.0.0.0");
~session_impl();
#ifndef TORRENT_DISABLE_EXTENSIONS
void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*)> ext);
#endif
void operator()();
void open_listen_port();
void async_accept();
void on_incoming_connection(boost::shared_ptr<socket_type> const& s
, boost::weak_ptr<socket_acceptor> const& as, asio::error_code const& e);
// must be locked to access the data
// in this struct
typedef boost::recursive_mutex mutex_t;
mutable mutex_t m_mutex;
boost::weak_ptr<torrent> find_torrent(const sha1_hash& info_hash);
peer_id const& get_peer_id() const { return m_peer_id; }
void close_connection(boost::intrusive_ptr<peer_connection> const& p);
void connection_failed(boost::shared_ptr<socket_type> const& s
, tcp::endpoint const& a, char const* message);
void set_settings(session_settings const& s);
session_settings const& settings() const { return m_settings; }
#ifndef TORRENT_DISABLE_DHT
void add_dht_node(std::pair<std::string, int> const& node);
void add_dht_node(udp::endpoint n);
void add_dht_router(std::pair<std::string, int> const& node);
void set_dht_settings(dht_settings const& s);
dht_settings const& get_dht_settings() const { return m_dht_settings; }
void start_dht(entry const& startup_state);
void stop_dht();
entry dht_state() const;
#endif
#ifndef TORRENT_DISABLE_ENCRYPTION
void set_pe_settings(pe_settings const& settings);
pe_settings const& get_pe_settings() const { return m_pe_settings; }
#endif
// called when a port mapping is successful, or a router returns
// a failure to map a port
void on_port_mapping(int tcp_port, int udp_port, std::string const& errmsg);
bool is_aborted() const { return m_abort; }
void set_ip_filter(ip_filter const& f);
void set_port_filter(port_filter const& f);
bool listen_on(
std::pair<int, int> const& port_range
, const char* net_interface = 0);
bool is_listening() const;
torrent_handle add_torrent(
torrent_info const& ti
, fs::path const& save_path
, entry const& resume_data
, bool compact_mode
, int block_size
, storage_constructor_type sc);
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
, bool compact_mode
, int block_size
, storage_constructor_type sc);
void remove_torrent(torrent_handle const& h);
std::vector<torrent_handle> get_torrents();
void set_severity_level(alert::severity_t s);
std::auto_ptr<alert> pop_alert();
int upload_rate_limit() const;
int download_rate_limit() const;
void set_download_rate_limit(int bytes_per_second);
void set_upload_rate_limit(int bytes_per_second);
void set_max_half_open_connections(int limit);
void set_max_connections(int limit);
void set_max_uploads(int limit);
int max_connections() const { return m_max_connections; }
int max_uploads() const { return m_max_uploads; }
int num_uploads() const { return m_num_unchoked; }
int num_connections() const
{ return m_connections.size(); }
void unchoke_peer(peer_connection& c)
{
c.send_unchoke();
++m_num_unchoked;
}
session_status status() const;
void set_peer_id(peer_id const& id);
void set_key(int key);
unsigned short listen_port() const;
void abort();
torrent_handle find_torrent_handle(sha1_hash const& info_hash);
void announce_lsd(sha1_hash const& ih);
void set_peer_proxy(proxy_settings const& s)
{ m_peer_proxy = s; }
void set_web_seed_proxy(proxy_settings const& s)
{ m_web_seed_proxy = s; }
void set_tracker_proxy(proxy_settings const& s)
{ m_tracker_proxy = s; }
proxy_settings const& peer_proxy() const
{ return m_peer_proxy; }
proxy_settings const& web_seed_proxy() const
{ return m_web_seed_proxy; }
proxy_settings const& tracker_proxy() const
{ return m_tracker_proxy; }
#ifndef TORRENT_DISABLE_DHT
void set_dht_proxy(proxy_settings const& s)
{ m_dht_proxy = s; }
proxy_settings const& dht_proxy() const
{ return m_dht_proxy; }
#endif
void start_lsd();
void start_natpmp();
void start_upnp();
void stop_lsd();
void stop_natpmp();
void stop_upnp();
// handles delayed alerts
alert_manager m_alerts;
// private:
void on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih);
// this is where all active sockets are stored.
// the selector can sleep while there's no activity on
// them
io_service m_io_service;
asio::strand m_strand;
// the file pool that all storages in this session's
// torrents uses. It sets a limit on the number of
// open files by this session.
// file pool must be destructed after the torrents
// since they will still have references to it
// when they are destructed.
file_pool m_files;
// handles disk io requests asynchronously
disk_io_thread m_disk_thread;
// this is a list of half-open tcp connections
// (only outgoing connections)
// this has to be one of the last
// members to be destructed
connection_queue m_half_open;
// the bandwidth manager is responsible for
// handing out bandwidth to connections that
// asks for it, it can also throttle the
// rate.
bandwidth_manager<peer_connection, torrent> m_download_channel;
bandwidth_manager<peer_connection, torrent> m_upload_channel;
bandwidth_manager<peer_connection, torrent>* m_bandwidth_manager[2];
tracker_manager m_tracker_manager;
torrent_map m_torrents;
// this maps sockets to their peer_connection
// object. It is the complete list of all connected
// peers.
connection_map m_connections;
// filters incoming connections
ip_filter m_ip_filter;
// filters outgoing connections
port_filter m_port_filter;
// the peer id that is generated at the start of the session
peer_id m_peer_id;
// the key is an id that is used to identify the
// client with the tracker only. It is randomized
// at startup
int m_key;
// the range of ports we try to listen on
std::pair<int, int> m_listen_port_range;
// the ip-address of the interface
// we are supposed to listen on.
// if the ip is set to zero, it means
// that we should let the os decide which
// interface to listen on
tcp::endpoint m_listen_interface;
// this is typically set to the same as the local
// listen port. In case a NAT port forward was
// successfully opened, this will be set to the
// port that is open on the external (NAT) interface
// on the NAT box itself. This is the port that has
// to be published to peers, since this is the port
// the client is reachable through.
int m_external_listen_port;
boost::shared_ptr<socket_acceptor> m_listen_socket;
// the settings for the client
session_settings m_settings;
// the proxy settings for different
// kinds of connections
proxy_settings m_peer_proxy;
proxy_settings m_web_seed_proxy;
proxy_settings m_tracker_proxy;
#ifndef TORRENT_DISABLE_DHT
proxy_settings m_dht_proxy;
#endif
// set to true when the session object
// is being destructed and the thread
// should exit
volatile bool m_abort;
int m_max_uploads;
int m_max_connections;
// the number of unchoked peers
int m_num_unchoked;
// this is initialized to the unchoke_interval
// session_setting and decreased every second.
// when it reaches zero, it is reset to the
// unchoke_interval and the unchoke set is
// recomputed.
int m_unchoke_time_scaler;
// works like unchoke_time_scaler but it
// is only decresed when the unchoke set
// is recomputed, and when it reaches zero,
// the optimistic unchoke is moved to another peer.
int m_optimistic_unchoke_time_scaler;
// works like unchoke_time_scaler. Each time
// it reaches 0, and all the connections are
// used, the worst connection will be disconnected
// from the torrent with the most peers
int m_disconnect_time_scaler;
// statistics gathered from all torrents.
stat m_stat;
// is false by default and set to true when
// the first incoming connection is established
// this is used to know if the client is behind
// NAT or not.
bool m_incoming_connection;
void second_tick(asio::error_code const& e);
ptime m_last_tick;
#ifndef TORRENT_DISABLE_DHT
boost::intrusive_ptr<dht::dht_tracker> m_dht;
dht_settings m_dht_settings;
// if this is set to true, the dht listen port
// will be set to the same as the tcp listen port
// and will be synchronlized with it as it changes
// it defaults to true
bool m_dht_same_port;
// see m_external_listen_port. This is the same
// but for the udp port used by the DHT.
int m_external_udp_port;
#endif
#ifndef TORRENT_DISABLE_ENCRYPTION
pe_settings m_pe_settings;
#endif
boost::shared_ptr<natpmp> m_natpmp;
boost::shared_ptr<upnp> m_upnp;
boost::shared_ptr<lsd> m_lsd;
// the timer used to fire the second_tick
deadline_timer m_timer;
// the index of the torrent that will be offered to
// connect to a peer next time second_tick is called.
// This implements a round robin.
int m_next_connect_torrent;
#ifndef NDEBUG
void check_invariant(const char *place = 0);
#endif
#ifdef TORRENT_STATS
// logger used to write bandwidth usage statistics
std::ofstream m_stats_logger;
int m_second_counter;
#endif
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
boost::shared_ptr<logger> create_log(std::string const& name
, int instance, bool append = true);
// this list of tracker loggers serves as tracker_callbacks when
// shutting down. This list is just here to keep them alive during
// whe shutting down process
std::list<boost::shared_ptr<tracker_logger> > m_tracker_loggers;
public:
boost::shared_ptr<logger> m_logger;
private:
#endif
#ifndef TORRENT_DISABLE_EXTENSIONS
typedef std::list<boost::function<boost::shared_ptr<
torrent_plugin>(torrent*)> > extension_list_t;
extension_list_t m_extensions;
#endif
// data shared between the main thread
// and the checker thread
checker_impl m_checker_impl;
// the main working thread
boost::scoped_ptr<boost::thread> m_thread;
// the thread that calls initialize_pieces()
// on all torrents before they start downloading
boost::scoped_ptr<boost::thread> m_checker_thread;
};
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
struct tracker_logger : request_callback
{
tracker_logger(session_impl& ses): m_ses(ses) {}
void tracker_warning(std::string const& str)
{
debug_log("*** tracker warning: " + str);
}
void tracker_response(tracker_request const&
, std::vector<peer_entry>& peers
, int interval
, int complete
, int incomplete)
{
std::stringstream s;
s << "TRACKER RESPONSE:\n"
"interval: " << interval << "\n"
"peers:\n";
for (std::vector<peer_entry>::const_iterator i = peers.begin();
i != peers.end(); ++i)
{
s << " " << std::setfill(' ') << std::setw(16) << i->ip
<< " " << std::setw(5) << std::dec << i->port << " ";
if (!i->pid.is_all_zeros()) s << " " << i->pid;
s << "\n";
}
debug_log(s.str());
}
void tracker_request_timed_out(
tracker_request const&)
{
debug_log("*** tracker timed out");
}
void tracker_request_error(
tracker_request const&
, int response_code
, const std::string& str)
{
debug_log(std::string("*** tracker error: ")
+ boost::lexical_cast<std::string>(response_code) + ": "
+ str);
}
void debug_log(const std::string& line)
{
(*m_ses.m_logger) << line << "\n";
}
session_impl& m_ses;
};
#endif
}
}
#endif

View File

@ -105,8 +105,7 @@ namespace libtorrent
, send_redundant_have(false)
, lazy_bitfields(true)
, inactivity_timeout(600)
, unchoke_interval(15)
, optimistic_unchoke_multiplier(4)
, unchoke_interval(20)
, num_want(200)
, initial_picker_threshold(4)
, allowed_fast_set_size(10)
@ -243,10 +242,6 @@ namespace libtorrent
// the number of seconds between chokes/unchokes
int unchoke_interval;
// the number of unchoke intervals between
// optimistic unchokes
int optimistic_unchoke_multiplier;
// if this is set, this IP will be reported do the
// tracker in the ip= parameter.
address announce_ip;

View File

@ -62,6 +62,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/stat.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/resource_request.hpp"
#include "libtorrent/piece_picker.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/escape_string.hpp"
@ -153,6 +154,10 @@ namespace libtorrent
bool verify_resume_data(entry& rd, std::string& error)
{ assert(m_storage); return m_storage->verify_resume_data(rd, error); }
// is called every second by session. This will
// caclulate the upload/download and number
// of connections this torrent needs. And prepare
// it for being used by allocate_resources.
void second_tick(stat& accumulator, float tick_interval);
// debug purpose only
@ -511,6 +516,11 @@ namespace libtorrent
// --------------------------------------------
// RESOURCE MANAGEMENT
void distribute_resources(float tick_interval);
resource_request m_uploads_quota;
resource_request m_connections_quota;
void set_peer_upload_limit(tcp::endpoint ip, int limit);
void set_peer_download_limit(tcp::endpoint ip, int limit);
@ -520,9 +530,7 @@ namespace libtorrent
int download_limit() const;
void set_max_uploads(int limit);
int max_uploads() const { return m_max_uploads; }
void set_max_connections(int limit);
int max_connections() const { return m_max_connections; }
void move_storage(fs::path const& save_path);
// unless this returns true, new connections must wait
@ -697,9 +705,9 @@ namespace libtorrent
// determine the timeout until next try.
int m_failed_trackers;
// this is a counter that is decreased every
// second, and when it reaches 0, the policy::pulse()
// is called and the time scaler is reset to 10.
// this is a counter that is increased every
// second, and when it reaches 10, the policy::pulse()
// is called and the time scaler is reset to 0.
int m_time_scaler;
// the bitmask that says which pieces we have
@ -766,12 +774,6 @@ namespace libtorrent
session_settings const& m_settings;
storage_constructor_type m_storage_constructor;
// the maximum number of uploads for this torrent
int m_max_uploads;
// the maximum number of connections for this torrent
int m_max_connections;
#ifndef TORRENT_DISABLE_EXTENSIONS
typedef std::list<boost::shared_ptr<torrent_plugin> > extension_list_t;

View File

@ -65,6 +65,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert.hpp"
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/allocate_resources.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/piece_block_progress.hpp"
#include "libtorrent/config.hpp"

View File

@ -0,0 +1,225 @@
/*
Copyright (c) 2006, Magnus Jonsson, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
//The Standard Library defines the two template functions std::min()
//and std::max() in the <algorithm> header. In general, you should
//use these template functions for calculating the min and max values
//of a pair. Unfortunately, Visual C++ does not define these function
// templates. This is because the names min and max clash with
//the traditional min and max macros defined in <windows.h>.
//As a workaround, Visual C++ defines two alternative templates with
//identical functionality called _cpp_min() and _cpp_max(). You can
//use them instead of std::min() and std::max().To disable the
//generation of the min and max macros in Visual C++, #define
//NOMINMAX before #including <windows.h>.
#include "libtorrent/pch.hpp"
#ifdef _WIN32
//support boost1.32.0(2004-11-19 18:47)
//now all libs can be compiled and linked with static module
#define NOMINMAX
#endif
#include "libtorrent/allocate_resources.hpp"
#include "libtorrent/size_type.hpp"
#include "libtorrent/peer_connection.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/aux_/allocate_resources_impl.hpp"
#include <cassert>
#include <algorithm>
#include <boost/limits.hpp>
#if defined(_MSC_VER) && _MSC_VER < 1310
#define for if (false) {} else for
#else
#include <boost/iterator/transform_iterator.hpp>
#endif
namespace libtorrent
{
int saturated_add(int a, int b)
{
assert(a >= 0);
assert(b >= 0);
assert(a <= resource_request::inf);
assert(b <= resource_request::inf);
assert(resource_request::inf + resource_request::inf < 0);
unsigned int sum = unsigned(a) + unsigned(b);
if (sum > unsigned(resource_request::inf))
sum = resource_request::inf;
assert(sum >= unsigned(a) && sum >= unsigned(b));
return int(sum);
}
#if defined(_MSC_VER) && _MSC_VER < 1310
namespace detail
{
struct iterator_wrapper
{
typedef std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator orig_iter;
orig_iter iter;
iterator_wrapper(orig_iter i): iter(i) {}
void operator++() { ++iter; }
torrent& operator*() { return *(iter->second); }
bool operator==(const iterator_wrapper& i) const
{ return iter == i.iter; }
bool operator!=(const iterator_wrapper& i) const
{ return iter != i.iter; }
};
struct iterator_wrapper2
{
typedef std::map<tcp::endpoint, peer_connection*>::iterator orig_iter;
orig_iter iter;
iterator_wrapper2(orig_iter i): iter(i) {}
void operator++() { ++iter; }
peer_connection& operator*() { return *(iter->second); }
bool operator==(const iterator_wrapper2& i) const
{ return iter == i.iter; }
bool operator!=(const iterator_wrapper2& i) const
{ return iter != i.iter; }
};
}
void allocate_resources(
int resources
, std::map<sha1_hash, boost::shared_ptr<torrent> >& c
, resource_request torrent::* res)
{
aux::allocate_resources_impl(
resources
, detail::iterator_wrapper(c.begin())
, detail::iterator_wrapper(c.end())
, res);
}
void allocate_resources(
int resources
, std::map<tcp::endpoint, peer_connection*>& c
, resource_request peer_connection::* res)
{
aux::allocate_resources_impl(
resources
, detail::iterator_wrapper2(c.begin())
, detail::iterator_wrapper2(c.end())
, res);
}
#else
namespace aux
{
peer_connection& pick_peer(
std::pair<boost::shared_ptr<stream_socket>
, boost::intrusive_ptr<peer_connection> > const& p)
{
return *p.second;
}
peer_connection& pick_peer2(
std::pair<tcp::endpoint, peer_connection*> const& p)
{
return *p.second;
}
torrent& deref(std::pair<sha1_hash, boost::shared_ptr<torrent> > const& p)
{
return *p.second;
}
session& deref(session* p)
{
return *p;
}
}
void allocate_resources(
int resources
, std::map<sha1_hash, boost::shared_ptr<torrent> >& c
, resource_request torrent::* res)
{
typedef std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator orig_iter;
typedef std::pair<sha1_hash, boost::shared_ptr<torrent> > in_param;
typedef boost::transform_iterator<torrent& (*)(in_param const&), orig_iter> new_iter;
aux::allocate_resources_impl(
resources
, new_iter(c.begin(), &aux::deref)
, new_iter(c.end(), &aux::deref)
, res);
}
void allocate_resources(
int resources
, std::map<tcp::endpoint, peer_connection*>& c
, resource_request peer_connection::* res)
{
typedef std::map<tcp::endpoint, peer_connection*>::iterator orig_iter;
typedef std::pair<tcp::endpoint, peer_connection*> in_param;
typedef boost::transform_iterator<peer_connection& (*)(in_param const&), orig_iter> new_iter;
aux::allocate_resources_impl(
resources
, new_iter(c.begin(), &aux::pick_peer2)
, new_iter(c.end(), &aux::pick_peer2)
, res);
}
void allocate_resources(
int resources
, std::vector<session*>& _sessions
, resource_request session::* res)
{
typedef std::vector<session*>::iterator orig_iter;
typedef session* in_param;
typedef boost::transform_iterator<session& (*)(in_param), orig_iter> new_iter;
aux::allocate_resources_impl(
resources
, new_iter(_sessions.begin(), &aux::deref)
, new_iter(_sessions.end(), &aux::deref)
, res);
}
#endif
} // namespace libtorrent

View File

@ -109,8 +109,8 @@ namespace libtorrent
, m_prefer_whole_pieces(false)
, m_request_large_blocks(false)
, m_non_prioritized(false)
, m_upload_limit(bandwidth_limit::inf)
, m_download_limit(bandwidth_limit::inf)
, m_upload_limit(resource_request::inf)
, m_download_limit(resource_request::inf)
, m_peer_info(peerinfo)
, m_speed(slow)
, m_connection_ticket(-1)
@ -185,8 +185,8 @@ namespace libtorrent
, m_prefer_whole_pieces(false)
, m_request_large_blocks(false)
, m_non_prioritized(false)
, m_upload_limit(bandwidth_limit::inf)
, m_download_limit(bandwidth_limit::inf)
, m_upload_limit(resource_request::inf)
, m_download_limit(resource_request::inf)
, m_peer_info(peerinfo)
, m_speed(slow)
, m_remote_bytes_dled(0)
@ -526,18 +526,30 @@ namespace libtorrent
&& p.start + p.length <= t->torrent_file().piece_size(p.piece)
&& (p.start % t->block_size() == 0);
}
struct disconnect_torrent
{
disconnect_torrent(boost::weak_ptr<torrent>& t): m_t(&t) {}
~disconnect_torrent() { if (m_t) m_t->reset(); }
void cancel() { m_t = 0; }
private:
boost::weak_ptr<torrent>* m_t;
};
void peer_connection::attach_to_torrent(sha1_hash const& ih)
{
INVARIANT_CHECK;
assert(!m_disconnecting);
assert(m_torrent.expired());
boost::weak_ptr<torrent> wpt = m_ses.find_torrent(ih);
m_torrent = m_ses.find_torrent(ih);
boost::shared_ptr<torrent> t = m_torrent.lock();
if (t && t->is_aborted())
{
m_torrent.reset();
t.reset();
}
if (!t)
{
@ -548,6 +560,7 @@ namespace libtorrent
throw std::runtime_error("got info-hash that is not in our session");
}
disconnect_torrent disconnect(m_torrent);
if (t->is_paused())
{
// paused torrents will not accept
@ -558,27 +571,21 @@ namespace libtorrent
throw std::runtime_error("connection rejected by paused torrent");
}
assert(m_torrent.expired());
// check to make sure we don't have another connection with the same
// info_hash and peer_id. If we do. close this connection.
t->attach_peer(this);
m_torrent = wpt;
assert(!m_torrent.expired());
// if the torrent isn't ready to accept
// connections yet, we'll have to wait with
// our initialization
if (t->ready_for_connections()) init();
assert(!m_torrent.expired());
// assume the other end has no pieces
// if we don't have valid metadata yet,
// leave the vector unallocated
assert(m_num_pieces == 0);
std::fill(m_have_piece.begin(), m_have_piece.end(), false);
assert(!m_torrent.expired());
disconnect.cancel();
}
// message handlers
@ -1536,7 +1543,7 @@ namespace libtorrent
// if the peer has the piece and we want
// to download it, request it
if (int(m_have_piece.size()) > index
if (m_have_piece.size() > index
&& m_have_piece[index]
&& t->has_picker()
&& t->picker().piece_priority(index) > 0)
@ -1893,7 +1900,7 @@ namespace libtorrent
void peer_connection::set_upload_limit(int limit)
{
assert(limit >= -1);
if (limit == -1) limit = std::numeric_limits<int>::max();
if (limit == -1) limit = resource_request::inf;
if (limit < 10) limit = 10;
m_upload_limit = limit;
m_bandwidth_limit[upload_channel].throttle(m_upload_limit);
@ -1902,7 +1909,7 @@ namespace libtorrent
void peer_connection::set_download_limit(int limit)
{
assert(limit >= -1);
if (limit == -1) limit = std::numeric_limits<int>::max();
if (limit == -1) limit = resource_request::inf;
if (limit < 10) limit = 10;
m_download_limit = limit;
m_bandwidth_limit[download_channel].throttle(m_download_limit);
@ -2037,13 +2044,10 @@ namespace libtorrent
if (m_packet_size >= m_recv_pos) m_recv_buffer.resize(m_packet_size);
}
void peer_connection::second_tick(float tick_interval) throw()
void peer_connection::second_tick(float tick_interval)
{
INVARIANT_CHECK;
try
{
ptime now(time_now());
boost::shared_ptr<torrent> t = m_torrent.lock();
@ -2182,14 +2186,43 @@ namespace libtorrent
}
fill_send_buffer();
}
catch (std::exception& e)
/*
size_type diff = share_diff();
enum { block_limit = 2 }; // how many blocks difference is considered unfair
// if the peer has been choked, send the current piece
// as fast as possible
if (diff > block_limit*m_torrent->block_size() || m_torrent->is_seed() || is_choked())
{
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << "**ERROR**: " << e.what() << "\n";
#endif
m_ses.connection_failed(m_socket, remote(), e.what());
// if we have downloaded more than one piece more
// than we have uploaded OR if we are a seed
// have an unlimited upload rate
m_ul_bandwidth_quota.wanted = std::numeric_limits<int>::max();
}
else
{
float ratio = m_torrent->ratio();
// if we have downloaded too much, response with an
// upload rate of 10 kB/s more than we dowlload
// if we have uploaded too much, send with a rate of
// 10 kB/s less than we receive
int bias = 0;
if (diff > -block_limit*m_torrent->block_size())
{
bias = static_cast<int>(m_statistics.download_rate() * ratio) / 2;
if (bias < 10*1024) bias = 10*1024;
}
else
{
bias = -static_cast<int>(m_statistics.download_rate() * ratio) / 2;
}
m_ul_bandwidth_quota.wanted = static_cast<int>(m_statistics.download_rate()) + bias;
// the maximum send_quota given our download rate from this peer
if (m_ul_bandwidth_quota.wanted < 256) m_ul_bandwidth_quota.wanted = 256;
}
*/
}
void peer_connection::fill_send_buffer()

View File

@ -189,8 +189,7 @@ namespace libtorrent
// infinite loop, fighting to request the same blocks.
void request_a_block(torrent& t, peer_connection& c)
{
if (t.is_seed()) return;
assert(!t.is_seed());
assert(t.valid_metadata());
assert(c.peer_info_struct() != 0 || !dynamic_cast<bt_peer_connection*>(&c));
int num_requests = c.desired_queue_size()
@ -332,8 +331,9 @@ namespace libtorrent
policy::policy(torrent* t)
: m_torrent(t)
, m_num_unchoked(0)
, m_available_free_upload(0)
// , m_last_optimistic_disconnect(min_time())
, m_last_optimistic_disconnect(min_time())
{ assert(t); }
// disconnects and removes all peers that are now filtered
@ -375,7 +375,7 @@ namespace libtorrent
m_peers.erase(i++);
}
}
/*
// finds the peer that has the worst download rate
// and returns it. May return 0 if all peers are
// choked.
@ -457,7 +457,7 @@ namespace libtorrent
}
return unchoke_peer;
}
*/
policy::iterator policy::find_disconnect_candidate()
{
INVARIANT_CHECK;
@ -542,7 +542,7 @@ namespace libtorrent
return candidate;
}
/*
policy::iterator policy::find_seed_choke_candidate()
{
INVARIANT_CHECK;
@ -648,7 +648,7 @@ namespace libtorrent
--m_num_unchoked;
}
}
*/
void policy::pulse()
{
INVARIANT_CHECK;
@ -680,7 +680,7 @@ 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;
@ -692,9 +692,10 @@ namespace libtorrent
++num_connected_peers;
}
if (m_torrent->max_connections() != std::numeric_limits<int>::max())
if (m_torrent->m_connections_quota.given != std::numeric_limits<int>::max())
{
int max_connections = m_torrent->max_connections();
int max_connections = m_torrent->m_connections_quota.given;
if (num_connected_peers >= max_connections)
{
@ -722,7 +723,7 @@ namespace libtorrent
--num_connected_peers;
}
}
*/
// ------------------------
// upload shift
// ------------------------
@ -753,7 +754,7 @@ namespace libtorrent
, m_torrent->end()
, m_available_free_upload);
}
/*
// ------------------------
// seed choking policy
// ------------------------
@ -869,7 +870,6 @@ namespace libtorrent
while (m_num_unchoked < m_torrent->m_uploads_quota.given
&& unchoke_one_peer());
}
*/
}
int policy::count_choked() const
@ -902,8 +902,7 @@ namespace libtorrent
// override at a time
assert(c.remote() == c.get_socket()->remote_endpoint());
if (m_torrent->num_peers() >= m_torrent->max_connections()
&& m_torrent->session().num_connections() >= m_torrent->session().max_connections()
if (m_torrent->num_peers() >= m_torrent->m_connections_quota.given
&& c.remote().address() != m_torrent->current_tracker().address())
{
throw protocol_error("too many connections, refusing incoming connection"); // cause a disconnect
@ -985,7 +984,7 @@ namespace libtorrent
i->connection = &c;
assert(i->connection);
i->connected = time_now();
// m_last_optimistic_disconnect = time_now();
m_last_optimistic_disconnect = time_now();
}
void policy::peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid
@ -1173,38 +1172,14 @@ namespace libtorrent
// In that case we don't care if people are leeching, they
// can't pay for their downloads anyway.
if (c.is_choked()
&& m_torrent->session().num_uploads() < m_torrent->session().max_uploads()
&& m_num_unchoked < m_torrent->m_uploads_quota.given
&& (m_torrent->ratio() == 0
|| c.share_diff() >= -free_upload_amount
|| m_torrent->is_seed()))
{
m_torrent->session().unchoke_peer(c);
c.send_unchoke();
++m_num_unchoked;
}
#if defined(TORRENT_VERBOSE_LOGGING)
else if (c.is_choked())
{
std::string reason;
if (m_torrent->session().num_uploads() >= m_torrent->session().max_uploads())
{
reason = "the number of uploads ("
+ boost::lexical_cast<std::string>(m_torrent->session().num_uploads())
+ ") is more than or equal to the limit ("
+ boost::lexical_cast<std::string>(m_torrent->session().max_uploads())
+ ")";
}
else
{
reason = "the share ratio ("
+ boost::lexical_cast<std::string>(c.share_diff())
+ ") is <= free_upload_amount ("
+ boost::lexical_cast<std::string>(int(free_upload_amount))
+ ") and we are not seeding and the ratio ("
+ boost::lexical_cast<std::string>(m_torrent->ratio())
+ ")is non-zero";
}
(*c.m_logger) << time_now_string() << " DID NOT UNCHOKE [ " << reason << " ]\n";
}
#endif
}
// called when a peer is no longer interested in us
@ -1236,7 +1211,7 @@ namespace libtorrent
}
*/
}
/*
bool policy::unchoke_one_peer()
{
INVARIANT_CHECK;
@ -1265,7 +1240,7 @@ namespace libtorrent
p->connection->send_choke();
--m_num_unchoked;
}
*/
bool policy::connect_one_peer()
{
INVARIANT_CHECK;
@ -1281,7 +1256,7 @@ namespace libtorrent
try
{
p->connected = time_now();
p->connected = m_last_optimistic_disconnect = time_now();
p->connection = m_torrent->connect_to_peer(&*p);
if (p->connection == 0) return false;
p->connection->add_stat(p->prev_amount_download, p->prev_amount_upload);
@ -1321,7 +1296,6 @@ namespace libtorrent
// assert(c.is_disconnecting());
bool unchoked = false;
#warning extract policy::peer pointer from c
iterator i = std::find_if(
m_peers.begin()
, m_peers.end()
@ -1331,7 +1305,6 @@ namespace libtorrent
if (i == m_peers.end()) return;
assert(i->connection == &c);
i->connection = 0;
i->optimistically_unchoked = false;
i->connected = time_now();
if (!c.is_choked() && !m_torrent->is_aborted())
@ -1357,15 +1330,15 @@ namespace libtorrent
i->prev_amount_download += c.statistics().total_payload_download();
i->prev_amount_upload += c.statistics().total_payload_upload();
// if (unchoked)
// {
if (unchoked)
{
// if the peer that is diconnecting is unchoked
// then unchoke another peer in order to maintain
// the total number of unchoked peers
// --m_num_unchoked;
// if (m_torrent->is_seed()) seed_unchoke_one_peer();
// else unchoke_one_peer();
// }
--m_num_unchoked;
if (m_torrent->is_seed()) seed_unchoke_one_peer();
else unchoke_one_peer();
}
}
catch (std::exception& e)
{
@ -1403,6 +1376,7 @@ namespace libtorrent
void policy::check_invariant() const
{
if (m_torrent->is_aborted()) return;
int actual_unchoked = 0;
int connected_peers = 0;
int total_connections = 0;
@ -1431,7 +1405,10 @@ namespace libtorrent
++nonempty_connections;
if (!p.connection->is_disconnecting())
++connected_peers;
if (!p.connection->is_choked()) ++actual_unchoked;
}
// assert(actual_unchoked <= m_torrent->m_uploads_quota.given);
assert(actual_unchoked == m_num_unchoked);
int num_torrent_peers = 0;
for (torrent::const_peer_iterator i = m_torrent->begin();
@ -1498,7 +1475,6 @@ namespace libtorrent
, failcount(0)
, hashfails(0)
, seed(false)
, optimistically_unchoked(false)
, last_optimistically_unchoked(min_time())
, connected(min_time())
, trust_points(0)

View File

@ -68,6 +68,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert_types.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/file.hpp"
#include "libtorrent/allocate_resources.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/ip_filter.hpp"
#include "libtorrent/socket.hpp"

View File

@ -68,6 +68,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert_types.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/file.hpp"
#include "libtorrent/allocate_resources.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/ip_filter.hpp"
#include "libtorrent/socket.hpp"
@ -222,12 +223,6 @@ namespace detail
if (!m_ses.is_aborted())
{
m_ses.m_torrents.insert(std::make_pair(t->info_hash, t->torrent_ptr));
if (m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(torrent_checked_alert(
processing->torrent_ptr->get_handle()
, "torrent finished checking"));
}
if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(torrent_finished_alert(
@ -350,12 +345,6 @@ namespace detail
processing->torrent_ptr->files_checked(processing->unfinished_pieces);
m_ses.m_torrents.insert(std::make_pair(
processing->info_hash, processing->torrent_ptr));
if (m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(torrent_checked_alert(
processing->torrent_ptr->get_handle()
, "torrent finished checking"));
}
if (processing->torrent_ptr->is_seed()
&& m_ses.m_alerts.should_post(alert::info))
{
@ -516,12 +505,8 @@ namespace detail
, m_listen_interface(address::from_string(listen_interface), listen_port_range.first)
, m_external_listen_port(0)
, m_abort(false)
, m_max_uploads(8)
, m_max_connections(200)
, m_num_unchoked(0)
, m_unchoke_time_scaler(0)
, m_optimistic_unchoke_time_scaler(0)
, m_disconnect_time_scaler(0)
, m_max_uploads(-1)
, m_max_connections(-1)
, m_incoming_connection(false)
, m_last_tick(time_now())
#ifndef TORRENT_DISABLE_DHT
@ -836,10 +821,7 @@ namespace detail
assert(p->is_disconnecting());
connection_map::iterator i = m_connections.find(p->get_socket());
if (i != m_connections.end())
{
if (!i->second->is_choked()) --m_num_unchoked;
m_connections.erase(i);
}
}
void session_impl::set_peer_id(peer_id const& id)
@ -919,9 +901,7 @@ namespace detail
// round robin fashion, so that every torrent is
// equallt likely to connect to a peer
if (!m_torrents.empty()
&& m_half_open.free_slots()
&& num_connections() < m_max_connections)
if (!m_torrents.empty() && m_half_open.free_slots())
{
// this is the maximum number of connections we will
// attempt this tick
@ -938,13 +918,11 @@ namespace detail
{
torrent& t = *i->second;
if (t.want_more_peers())
{
if (t.try_connect_peer())
{
--max_connections;
steps_since_last_connect = 0;
}
}
++m_next_connect_torrent;
++steps_since_last_connect;
++i;
@ -998,7 +976,18 @@ namespace detail
continue;
}
c.keep_alive();
try
{
c.keep_alive();
}
catch (std::exception& exc)
{
#ifdef TORRENT_VERBOSE_LOGGING
(*c.m_logger) << "**ERROR**: " << exc.what() << "\n";
#endif
c.set_failed();
c.disconnect();
}
}
// check each torrent for tracker updates
@ -1030,148 +1019,30 @@ namespace detail
}
m_stat.second_tick(tick_interval);
// distribute the maximum upload rate among the torrents
// --------------------------------------------------------------
// unchoke set and optimistic unchoke calculations
// --------------------------------------------------------------
m_unchoke_time_scaler--;
if (m_unchoke_time_scaler <= 0 && !m_connections.empty())
assert(m_max_uploads >= -1);
assert(m_max_connections >= -1);
allocate_resources(m_max_uploads == -1
? std::numeric_limits<int>::max()
: m_max_uploads
, m_torrents
, &torrent::m_uploads_quota);
allocate_resources(m_max_connections == -1
? std::numeric_limits<int>::max()
: m_max_connections
, m_torrents
, &torrent::m_connections_quota);
for (std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i
= m_torrents.begin(); i != m_torrents.end(); ++i)
{
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->second.get();
torrent* t = p->associated_torrent().lock().get();
if (!p->peer_info_struct()
|| !p->is_peer_interested()
|| p->is_disconnecting()
|| p->is_connecting()
|| (p->share_diff() < -free_upload_amount
&& t && !t->is_seed()))
{
if (!i->second->is_choked())
i->second->send_choke();
continue;
}
peers.push_back(i->second.get());
}
// sort 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(&stat::total_payload_upload, bind(&peer_connection::statistics, _1))
< bind(&stat::total_payload_upload, bind(&peer_connection::statistics, _2)));
std::stable_sort(peers.begin(), peers.end()
, bind(&stat::download_payload_rate, bind(&peer_connection::statistics, _1))
> bind(&stat::download_payload_rate, bind(&peer_connection::statistics, _2)));
// reserve one upload slot for optimistic unchokes
int unchoke_set_size = m_max_uploads - 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;
assert(p);
if (unchoke_set_size > 0)
{
if (p->is_choked()) p->send_unchoke();
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;
}
--unchoke_set_size;
++m_num_unchoked;
}
else
{
if (!p->is_choked() && !p->peer_info_struct()->optimistically_unchoked)
p->send_choke();
}
}
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->second.get();
assert(p);
policy::peer* pi = p->peer_info_struct();
if (!pi) continue;
if (pi->optimistically_unchoked)
{
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())
{
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())
{
current_optimistic_unchoke->second->send_choke();
current_optimistic_unchoke->second->peer_info_struct()->optimistically_unchoked = false;
}
optimistic_unchoke_candidate->second->send_unchoke();
optimistic_unchoke_candidate->second->peer_info_struct()->optimistically_unchoked = true;
}
if (optimistic_unchoke_candidate != m_connections.end())
++m_num_unchoked;
}
}
// --------------------------------------------------------------
// disconnect peers when we have too many
// --------------------------------------------------------------
--m_disconnect_time_scaler;
if (m_disconnect_time_scaler <= 0)
{
m_disconnect_time_scaler = 60;
// every 60 seconds, disconnect the worst peer
// if we have reached the connection limit
if (num_connections() >= max_connections() && !m_torrents.empty())
{
torrent_map::iterator i = std::max_element(m_torrents.begin(), m_torrents.end()
, bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _1)));
assert(i != m_torrents.end());
i->second->get_policy().disconnect_one_peer();
}
#ifndef NDEBUG
i->second->check_invariant();
#endif
i->second->distribute_resources(tick_interval);
}
}
catch (std::exception& exc)
@ -1995,6 +1866,24 @@ namespace detail
m_bandwidth_manager[peer_connection::upload_channel]->throttle(bytes_per_second);
}
int session_impl::num_uploads() const
{
int uploads = 0;
mutex_t::scoped_lock l(m_mutex);
for (torrent_map::const_iterator i = m_torrents.begin()
, end(m_torrents.end()); i != end; i++)
{
uploads += i->second->get_policy().num_uploads();
}
return uploads;
}
int session_impl::num_connections() const
{
mutex_t::scoped_lock l(m_mutex);
return m_connections.size();
}
std::auto_ptr<alert> session_impl::pop_alert()
{
mutex_t::scoped_lock l(m_mutex);
@ -2089,25 +1978,17 @@ namespace detail
void session_impl::check_invariant(const char *place)
{
assert(place);
int unchokes = 0;
int num_optimistic = 0;
for (connection_map::iterator i = m_connections.begin();
i != m_connections.end(); ++i)
{
assert(i->second);
boost::shared_ptr<torrent> t = i->second->associated_torrent().lock();
if (!i->second->is_choked()) ++unchokes;
if (i->second->peer_info_struct()
&& i->second->peer_info_struct()->optimistically_unchoked)
++num_optimistic;
if (t)
{
assert(t->get_policy().has_connection(boost::get_pointer(i->second)));
}
}
assert(num_optimistic == 0 || num_optimistic == 1);
assert(m_num_unchoked == unchokes);
}
#endif

View File

@ -199,12 +199,18 @@ namespace libtorrent
, m_connections_initialized(true)
, m_settings(s)
, m_storage_constructor(sc)
, m_max_uploads(std::numeric_limits<int>::max())
, m_max_connections(std::numeric_limits<int>::max())
{
#ifndef NDEBUG
m_initial_done = 0;
#endif
m_uploads_quota.min = 0;
m_connections_quota.min = 2;
// this will be corrected the next time the main session
// distributes resources, i.e. on average in 0.5 seconds
m_connections_quota.given = 100;
m_uploads_quota.max = std::numeric_limits<int>::max();
m_connections_quota.max = std::numeric_limits<int>::max();
m_policy.reset(new policy(this));
}
@ -271,6 +277,13 @@ namespace libtorrent
if (name) m_name.reset(new std::string(name));
m_uploads_quota.min = 0;
m_connections_quota.min = 2;
// this will be corrected the next time the main session
// distributes resources, i.e. on average in 0.5 seconds
m_connections_quota.given = 100;
m_uploads_quota.max = std::numeric_limits<int>::max();
m_connections_quota.max = std::numeric_limits<int>::max();
if (tracker_url)
{
m_trackers.push_back(announce_entry(tracker_url));
@ -316,14 +329,6 @@ namespace libtorrent
INVARIANT_CHECK;
#if defined(TORRENT_VERBOSE_LOGGING)
for (peer_iterator i = m_connections.begin();
i != m_connections.end(); ++i)
{
(*i->second->m_logger) << "*** DESTRUCTING TORRENT\n";
}
#endif
assert(m_abort);
if (!m_connections.empty())
disconnect_all();
@ -1015,15 +1020,6 @@ namespace libtorrent
m_event = tracker_request::stopped;
// disconnect all peers and close all
// files belonging to the torrents
#if defined(TORRENT_VERBOSE_LOGGING)
for (peer_iterator i = m_connections.begin();
i != m_connections.end(); ++i)
{
(*i->second->m_logger) << "*** ABORTING TORRENT\n";
}
#endif
disconnect_all();
if (m_owning_storage.get()) m_storage->async_release_files();
m_owning_storage = 0;
@ -1894,7 +1890,7 @@ namespace libtorrent
void torrent::attach_peer(peer_connection* p)
{
// INVARIANT_CHECK;
INVARIANT_CHECK;
assert(p != 0);
assert(!p->is_local());
@ -1959,7 +1955,7 @@ namespace libtorrent
bool torrent::want_more_peers() const
{
return int(m_connections.size()) < m_max_connections
return int(m_connections.size()) < m_connections_quota.given
&& m_ses.m_half_open.free_slots()
&& !m_paused;
}
@ -2429,15 +2425,15 @@ namespace libtorrent
void torrent::set_max_uploads(int limit)
{
assert(limit >= -1);
if (limit < 0) limit = std::numeric_limits<int>::max();
m_max_uploads = limit;
if (limit == -1) limit = std::numeric_limits<int>::max();
m_uploads_quota.max = std::max(m_uploads_quota.min, limit);
}
void torrent::set_max_connections(int limit)
{
assert(limit >= -1);
if (limit < -1) limit = std::numeric_limits<int>::max();
m_max_connections = limit;
if (limit == -1) limit = std::numeric_limits<int>::max();
m_connections_quota.max = std::max(m_connections_quota.min, limit);
}
void torrent::set_peer_upload_limit(tcp::endpoint ip, int limit)
@ -2500,14 +2496,6 @@ namespace libtorrent
}
#endif
#if defined(TORRENT_VERBOSE_LOGGING)
for (peer_iterator i = m_connections.begin();
i != m_connections.end(); ++i)
{
(*i->second->m_logger) << "*** PAUSING TORRENT\n";
}
#endif
disconnect_all();
m_paused = true;
// tell the tracker that we stopped
@ -2540,6 +2528,10 @@ namespace libtorrent
#endif
m_paused = false;
m_uploads_quota.min = 0;
m_connections_quota.min = 2;
m_uploads_quota.max = std::numeric_limits<int>::max();
m_connections_quota.max = std::numeric_limits<int>::max();
// tell the tracker that we're back
m_event = tracker_request::started;
@ -2553,6 +2545,10 @@ namespace libtorrent
{
INVARIANT_CHECK;
m_connections_quota.used = (int)m_connections.size();
m_uploads_quota.used = m_policy->num_uploads();
m_uploads_quota.max = (int)m_connections.size();
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
@ -2565,6 +2561,10 @@ namespace libtorrent
{
// let the stats fade out to 0
m_stat.second_tick(tick_interval);
m_connections_quota.min = 0;
m_connections_quota.max = 0;
m_uploads_quota.min = 0;
m_uploads_quota.max = 0;
return;
}
@ -2623,13 +2623,6 @@ namespace libtorrent
}
accumulator += m_stat;
m_stat.second_tick(tick_interval);
m_time_scaler--;
if (m_time_scaler <= 0)
{
m_time_scaler = 10;
m_policy->pulse();
}
}
bool torrent::try_connect_peer()
@ -2638,6 +2631,18 @@ namespace libtorrent
return m_policy->connect_one_peer();
}
void torrent::distribute_resources(float tick_interval)
{
INVARIANT_CHECK;
m_time_scaler--;
if (m_time_scaler <= 0)
{
m_time_scaler = settings().unchoke_interval;
m_policy->pulse();
}
}
void torrent::async_verify_piece(int piece_index, boost::function<void(bool)> const& f)
{
INVARIANT_CHECK;
@ -2759,10 +2764,10 @@ namespace libtorrent
= m_trackers[m_last_working_tracker].url;
}
st.num_uploads = -1;
st.uploads_limit = m_max_uploads;
st.num_connections = int(m_connections.size());
st.connections_limit = m_max_connections;
st.num_uploads = m_uploads_quota.used;
st.uploads_limit = m_uploads_quota.given;
st.num_connections = m_connections_quota.used;
st.connections_limit = m_connections_quota.given;
// if we don't have any metadata, stop here
if (!valid_metadata())