revert last...too many changes for now
This commit is contained in:
parent
476a72b0e4
commit
1973d7c9e3
|
@ -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(
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
Loading…
Reference in New Issue