The peer_request contains the values the client sent in its request message. piece is
diff --git a/docs/manual.rst b/docs/manual.rst
index fb7f55603..09950437b 100755
--- a/docs/manual.rst
+++ b/docs/manual.rst
@@ -29,18 +29,18 @@ The current state includes the following features:
* queues torrents for file check, instead of checking all of them in parallel.
* uses separate threads for checking files and for main downloader, with a fool-proof
thread-safe library interface. (i.e. There's no way for the user to cause a deadlock).
- * can limit the upload bandwidth usage and the maximum number of unchoked peers
- * piece-wise file allocation
+ * can limit the upload and download bandwidth usage and the maximum number of unchoked peers
+ * piece-wise, unordered, file allocation
* implements fair trade. User settable trade-ratio, must at least be 1:1,
but one can choose to trade 1 for 2 or any other ratio that isn't unfair to the other
- party.
+ party. (i.e. real tit for tat)
* fast resume support, a way to get rid of the costly piece check at the start
of a resumed torrent. Saves the storage state, piece_picker state as well as all local
peers in a separate fast-resume file.
* supports the extension protocol `described by Nolar`__. See extensions_.
* supports files > 2 gigabytes (currently only on windows).
* supports the ``no_peer_id=1`` extension that will ease the load off trackers.
- * supports the `udp-tracker protocol`__.
+ * supports the `udp-tracker protocol`__ by Olaf van der Spek.
* possibility to limit the number of connections.
* delays have messages if there's no other outgoing traffic to the peer, and doesn't
send have messages to peers that already has the piece. This saves bandwidth.
@@ -129,7 +129,7 @@ cygwin and msvc
---------------
Note that if you're building on windows using the ``msvc`` toolset, you cannot run it
-from a cygwin terminal, you'll have to run it from a cmd terminal. The same goes for
+from a cygwin terminal, you'll have to run it from a ``cmd`` terminal. The same goes for
cygwin, if you're building with gcc (mingw) you'll have to run it from a cygwin terminal.
Also, make sure the paths are correct in the different environments. In cygwin, the paths
(``BOOST_BUILD_PATH`` and ``BOOST_ROOT``) should be in the typical unix-format (e.g.
@@ -225,6 +225,7 @@ The ``session`` class has the following synopsis::
void set_http_settings(const http_settings& settings);
void set_upload_rate_limit(int bytes_per_second);
+ void set_download_rate_limit(int bytes_per_second);
bool is_listening() const;
unsigned short listen_port() const;
@@ -242,7 +243,7 @@ Once it's created, it will spawn the main thread that will do all the work.
The main thread will be idle as long it doesn't have any torrents to participate in.
You add torrents through the ``add_torrent()``-function where you give an
object representing the information found in the torrent file and the path where you
-want to save the files. The ``save_path`` will be prepended to the directory-
+want to save the files. The ``save_path`` will be prepended to the directory
structure in the torrent-file. ``add_torrent`` will throw duplicate_torrent_ exception
if the torrent already exists in the session.
@@ -266,6 +267,8 @@ fingerprint class.
``set_upload_rate_limit()`` set the maximum number of bytes allowed to be
sent to peers per second. This bandwidth is distributed among all the peers. If
you don't want to limit upload rate, you can set this to -1 (the default).
+``set_download_rate_limit()`` works the same way but for download rate instead
+of upload rate.
``is_listening()`` will tell you wether or not the session has successfully
opened a listening port. If it hasn't, this function will return false, and
@@ -374,10 +377,10 @@ or a string. This is its synopsis::
{
public:
- typedef std::map dictionary_type;
+ typedef std::list > dictionary_type;
typedef std::string string_type;
- typedef std::vector list_type;
- typedef implementation-defined integer_type;
+ typedef std::list list_type;
+ typedef size_type integer_type;
enum data_type
{
@@ -398,7 +401,6 @@ or a string. This is its synopsis::
entry();
entry(data_type t);
entry(const entry& e);
-
~entry();
void operator=(const entry& e);
@@ -407,7 +409,7 @@ or a string. This is its synopsis::
void operator=(const list_type&);
void operator=(const integer_type&);
- integer_type& integer()
+ integer_type& integer();
const integer_type& integer() const;
string_type& string();
const string_type& string() const;
@@ -416,6 +418,15 @@ or a string. This is its synopsis::
dictionary_type& dict();
const dictionary_type& dict() const;
+ // these functions requires that the entry
+ // is a dictionary, otherwise they will throw
+ entry& operator[](char const* key);
+ entry& operator[](std::string const& key);
+ const entry& operator[](char const* key) const;
+ const entry& operator[](std::string const& key) const;
+ entry* find_key(char const* key);
+ entry const* find_key(char const* key) const;
+
void print(std::ostream& os, int indent = 0) const;
};
@@ -586,11 +597,13 @@ Its declaration looks like this::
void force_reannounce();
void connect_peer(const address& adr) const;
- void set_ratio(float ratio);
void set_tracker_login(std::string const& username, std::string const& password);
+
+ void set_ratio(float ratio);
void set_max_uploads(int max_uploads);
void set_max_connections(int max_connections);
void set_upload_limit(int limit);
+ void set_download_limit(int limit);
void use_interface(const char* net_interface);
void pause();
@@ -634,6 +647,10 @@ as a standard client.
``set_upload_limit`` will limit the upload bandwidth used by this particular torrent to the
limit you set. It is given as the number of bytes per second the torrent is allowed to upload.
+``set_download_limit`` works the same way but for download bandwidth instead of upload bandwidth.
+Note that setting i higher limit on a torrent then the global limit (``session::set_upload_rate_limit``)
+will not override the global rate limit. The torrent can never upload more than the global rate
+limit.
``pause()``, and ``resume()`` will disconnect all peers and reconnect all peers respectively.
When a torrent is paused, it will however remember all share ratios to all peers and remember
@@ -1300,7 +1317,7 @@ to the torrent that this peer was a member of.
struct peer_ban_alert: alert
{
- peer_error_alert(
+ peer_ban_alert(
address const& pip
, torrent_handle h
, const std::string& msg);
@@ -1323,10 +1340,15 @@ is generated as severity level ``debug``.
struct peer_error_alert: alert
{
- peer_error_alert(const address& pid, const std::string& msg);
+ peer_error_alert(
+ address const& pip
+ , peer_id const& pid
+ , const std::string& msg);
+
virtual std::auto_ptr clone() const;
address ip;
+ peer_id id;
};
@@ -1343,16 +1365,18 @@ is a handle to the torrent the peer is a member of. ``
struct invalid_request_alert: alert
{
invalid_request_alert(
- const peer_request& r
- , const torrent_handle& h
- , const address& send
- , const std::string& msg);
+ peer_request const& r
+ , torrent_handle const& h
+ , address const& send
+ , peer_id const& pid
+ , std::string const& msg);
virtual std::auto_ptr clone() const;
torrent_handle handle;
address ip;
peer_request request;
+ peer_id id;
};
@@ -1361,7 +1385,7 @@ is a handle to the torrent the peer is a member of. ``
int piece;
int start;
int length;
- bool operator==(const peer_request& r);
+ bool operator==(peer_request const& r) const;
};
diff --git a/examples/client_test.cpp b/examples/client_test.cpp
index 211c3e021..d76285d03 100755
--- a/examples/client_test.cpp
+++ b/examples/client_test.cpp
@@ -245,7 +245,7 @@ int main(int argc, char* argv[])
std::make_pair(6881, 6889)
, fingerprint("LT", 0, 1, 0, 0));
- ses.set_upload_rate_limit(20 * 1024);
+ ses.set_upload_rate_limit(100000);
ses.set_http_settings(settings);
ses.set_severity_level(alert::debug);
@@ -345,16 +345,29 @@ int main(int argc, char* argv[])
a = ses.pop_alert();
while (a.get())
{
- torrent_finished_alert* p = dynamic_cast(a.get());
- if (p)
+ if (torrent_finished_alert* p = dynamic_cast(a.get()))
{
// limit the bandwidth for all seeding torrents
p->handle.set_max_connections(10);
p->handle.set_max_uploads(5);
- p->handle.set_upload_limit(30000);
+ p->handle.set_upload_limit(10000);
+ events.push_back(
+ p->handle.get_torrent_info().name() + ": " + a->msg());
}
+ else if (peer_error_alert* p = dynamic_cast(a.get()))
+ {
+ events.push_back(identify_client(p->id) + ": " + a->msg());
+ }
+ else if (invalid_request_alert* p = dynamic_cast(a.get()))
+ {
+ events.push_back(identify_client(p->id) + ": " + a->msg());
+ }
+ else
+ {
+ events.push_back(a->msg());
+ }
+
if (events.size() >= 10) events.pop_front();
- events.push_back(a->msg());
a = ses.pop_alert();
}
diff --git a/include/libtorrent/alert_types.hpp b/include/libtorrent/alert_types.hpp
index 5c6d87408..ce22f8056 100755
--- a/include/libtorrent/alert_types.hpp
+++ b/include/libtorrent/alert_types.hpp
@@ -90,15 +90,17 @@ namespace libtorrent
struct peer_error_alert: alert
{
- peer_error_alert(const address& pip, const std::string& msg)
+ peer_error_alert(address const& pip, peer_id const& pid, const std::string& msg)
: alert(alert::debug, msg)
, ip(pip)
+ , id(pid)
{}
virtual std::auto_ptr clone() const
{ return std::auto_ptr(new peer_error_alert(*this)); }
address ip;
+ peer_id id;
};
struct chat_message_alert: alert
@@ -122,14 +124,16 @@ namespace libtorrent
struct invalid_request_alert: alert
{
invalid_request_alert(
- const peer_request& r
- , const torrent_handle& h
- , const address& sender
- , const std::string& msg)
+ peer_request const& r
+ , torrent_handle const& h
+ , address const& sender
+ , peer_id const& pid
+ , std::string const& msg)
: alert(alert::debug, msg)
, handle(h)
, ip(sender)
, request(r)
+ , id(pid)
{}
virtual std::auto_ptr clone() const
@@ -138,6 +142,7 @@ namespace libtorrent
torrent_handle handle;
address ip;
peer_request request;
+ peer_id id;
};
struct torrent_finished_alert: alert
diff --git a/include/libtorrent/entry.hpp b/include/libtorrent/entry.hpp
index 4fd2fa957..4e9419192 100755
--- a/include/libtorrent/entry.hpp
+++ b/include/libtorrent/entry.hpp
@@ -107,10 +107,10 @@ namespace libtorrent
{
public:
- // we need a vector here to maintain the order
- // of elements. Since the info-hash is reconstructed
- // from an entry, it's important that the order is
- // preserved.
+ // we need a list here instead of a map, to maintain
+ // the order of elements. Since the info-hash is
+ // reconstructed from an entry, it's important that
+ // the order is preserved.
typedef std::list > dictionary_type;
typedef std::string string_type;
typedef std::list list_type;
@@ -125,76 +125,32 @@ namespace libtorrent
undefined_t
};
- data_type type() const { return m_type; }
+ data_type type() const;
entry(const dictionary_type&);
entry(const string_type&);
entry(const list_type&);
entry(const integer_type&);
- entry(): m_type(undefined_t) {}
- entry(data_type t): m_type(t) { construct(t); }
- entry(const entry& e) { copy(e); }
- ~entry() { destruct(); }
-
- void operator=(const entry& e)
- {
- destruct();
- copy(e);
- }
+ entry();
+ entry(data_type t);
+ entry(const entry& e);
+ ~entry();
+ void operator=(const entry& e);
void operator=(const dictionary_type&);
void operator=(const string_type&);
void operator=(const list_type&);
void operator=(const integer_type&);
- integer_type& integer()
- {
- if (m_type != int_t) throw type_error("invalid type requested from entry");
- return *reinterpret_cast(data);
- }
-
- const integer_type& integer() const
- {
- if (m_type != int_t) throw type_error("invalid type requested from entry");
- return *reinterpret_cast(data);
- }
-
- string_type& string()
- {
- if (m_type != string_t) throw type_error("invalid type requested from entry");
- return *reinterpret_cast(data);
- }
-
- const string_type& string() const
- {
- if (m_type != string_t) throw type_error("invalid type requested from entry");
- return *reinterpret_cast(data);
- }
-
- list_type& list()
- {
- if (m_type != list_t) throw type_error("invalid type requested from entry");
- return *reinterpret_cast(data);
- }
-
- const list_type& list() const
- {
- if (m_type != list_t) throw type_error("invalid type requested from entry");
- return *reinterpret_cast(data);
- }
-
- dictionary_type& dict()
- {
- if (m_type != dictionary_t) throw type_error("invalid type requested from entry");
- return *reinterpret_cast(data);
- }
-
- const dictionary_type& dict() const
- {
- if (m_type != dictionary_t) throw type_error("invalid type requested from entry");
- return *reinterpret_cast(data);
- }
+ integer_type& integer();
+ const integer_type& integer() const;
+ string_type& string();
+ const string_type& string() const;
+ list_type& list();
+ const list_type& list() const;
+ dictionary_type& dict();
+ const dictionary_type& dict() const;
// these functions requires that the entry
// is a dictionary, otherwise they will throw
@@ -246,6 +202,67 @@ namespace libtorrent
return os;
}
+ inline entry::data_type entry::type() const { return m_type; }
+
+ inline entry::entry(): m_type(undefined_t) {}
+ inline entry::entry(data_type t): m_type(t) { construct(t); }
+ inline entry::entry(const entry& e) { copy(e); }
+ inline entry::~entry() { destruct(); }
+
+ inline void entry::operator=(const entry& e)
+ {
+ destruct();
+ copy(e);
+ }
+
+ inline entry::integer_type& entry::integer()
+ {
+ if (m_type != int_t) throw type_error("invalid type requested from entry");
+ return *reinterpret_cast(data);
+ }
+
+ inline entry::integer_type const& entry::integer() const
+ {
+ if (m_type != int_t) throw type_error("invalid type requested from entry");
+ return *reinterpret_cast(data);
+ }
+
+ inline entry::string_type& entry::string()
+ {
+ if (m_type != string_t) throw type_error("invalid type requested from entry");
+ return *reinterpret_cast(data);
+ }
+
+ inline entry::string_type const& entry::string() const
+ {
+ if (m_type != string_t) throw type_error("invalid type requested from entry");
+ return *reinterpret_cast(data);
+ }
+
+ inline entry::list_type& entry::list()
+ {
+ if (m_type != list_t) throw type_error("invalid type requested from entry");
+ return *reinterpret_cast(data);
+ }
+
+ inline entry::list_type const& entry::list() const
+ {
+ if (m_type != list_t) throw type_error("invalid type requested from entry");
+ return *reinterpret_cast(data);
+ }
+
+ inline entry::dictionary_type& entry::dict()
+ {
+ if (m_type != dictionary_t) throw type_error("invalid type requested from entry");
+ return *reinterpret_cast(data);
+ }
+
+ inline entry::dictionary_type const& entry::dict() const
+ {
+ if (m_type != dictionary_t) throw type_error("invalid type requested from entry");
+ return *reinterpret_cast(data);
+ }
+
}
#endif // TORRENT_ENTRY_HPP_INCLUDED
diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp
index 940195bf7..a844f071c 100755
--- a/include/libtorrent/peer_connection.hpp
+++ b/include/libtorrent/peer_connection.hpp
@@ -117,7 +117,9 @@ namespace libtorrent
void receive_data();
// tells if this connection has data it want to send
- bool has_data() const;
+ // and has enough upload bandwidth quota left to send it.
+ bool can_write() const;
+ bool can_read() const;
bool is_seed() const;
@@ -171,13 +173,6 @@ namespace libtorrent
void disconnect();
bool is_disconnecting() const { return m_disconnecting; }
- // returns the send quota this peer has
- // left until will stop sending.
- // if the send_quota is -1, it means the
- // quota is unlimited.
- int send_quota_left() const;
- resource_request* upload_bandwidth_quota();
-
// This is called for every peer right after the upload
// bandwidth has been distributed among them
// It will reset the used bandwidth to 0 and
@@ -248,7 +243,9 @@ namespace libtorrent
// how much bandwidth we're using, how much we want,
// and how much we are allowed to use.
- resource_request m_upload_bandwidth_quota;
+ resource_request m_ul_bandwidth_quota;
+ resource_request m_dl_bandwidth_quota;
+ resource_request m_unchoked_quota;
private:
@@ -340,8 +337,8 @@ namespace libtorrent
boost::shared_ptr m_socket;
// upload bandwidth used this second.
- // Must not exceed m_upload_bandwidth_quota.given.
-// int m_upload_bandwidth_quota_used;
+ // Must not exceed m_ul_bandwidth_quota.given.
+// int m_ul_bandwidth_quota_used;
// this is the torrent this connection is
// associated with. If the connection is an
@@ -372,7 +369,8 @@ namespace libtorrent
// sent to this peer, we check this and
// if it's not added to the selector we
// add it. (this is done in send_buffer_updated())
- bool m_added_to_selector;
+ bool m_writability_monitored;
+ bool m_readability_monitored;
// remote peer's id
peer_id m_peer_id;
diff --git a/include/libtorrent/peer_request.hpp b/include/libtorrent/peer_request.hpp
index 2af894f62..6d12548c2 100644
--- a/include/libtorrent/peer_request.hpp
+++ b/include/libtorrent/peer_request.hpp
@@ -40,7 +40,7 @@ namespace libtorrent
int piece;
int start;
int length;
- bool operator==(const peer_request& r)
+ bool operator==(peer_request const& r) const
{ return piece == r.piece && start == r.start && length == r.length; }
};
}
diff --git a/include/libtorrent/resource_request.hpp b/include/libtorrent/resource_request.hpp
index 5823441b5..f831aa4db 100755
--- a/include/libtorrent/resource_request.hpp
+++ b/include/libtorrent/resource_request.hpp
@@ -44,6 +44,13 @@ namespace libtorrent
, given(0)
{}
+ int left() const
+ {
+ assert(given >= used);
+ return given - used;
+ }
+
+
// I'm right now actively using:
int used;
diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp
index d3f827109..23504f578 100755
--- a/include/libtorrent/session.hpp
+++ b/include/libtorrent/session.hpp
@@ -225,6 +225,7 @@ namespace libtorrent
// bytes per second. -1 means
// unlimited
int m_upload_rate;
+ int m_download_rate;
// handles delayed alerts
alert_manager m_alerts;
@@ -292,6 +293,7 @@ namespace libtorrent
void set_http_settings(const http_settings& s);
void set_upload_rate_limit(int bytes_per_second);
+ void set_download_rate_limit(int bytes_per_second);
// TODO: add a session_status that contain
// some indication of if the listen-port works
diff --git a/include/libtorrent/socket.hpp b/include/libtorrent/socket.hpp
index 9632e5623..bb4ca92c1 100755
--- a/include/libtorrent/socket.hpp
+++ b/include/libtorrent/socket.hpp
@@ -240,12 +240,21 @@ namespace libtorrent
void remove_writable(boost::shared_ptr s)
{ m_writable.erase(std::find(m_writable.begin(), m_writable.end(), s)); }
+ void remove_readable(boost::shared_ptr s)
+ { m_readable.erase(std::find(m_readable.begin(), m_readable.end(), s)); }
+
bool is_writability_monitored(boost::shared_ptr s)
{
return std::find(m_writable.begin(), m_writable.end(), s)
!= m_writable.end();
}
+ bool is_readability_monitored(boost::shared_ptr s)
+ {
+ return std::find(m_readable.begin(), m_readable.end(), s)
+ != m_readable.end();
+ }
+
void wait(int timeout
, std::vector >& readable
, std::vector >& writable
diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp
index e8983663c..af82dd9bd 100755
--- a/include/libtorrent/torrent.hpp
+++ b/include/libtorrent/torrent.hpp
@@ -92,27 +92,20 @@ namespace libtorrent
~torrent();
+ // this will flag the torrent as aborted. The main
+ // loop in session_impl will check for this state
+ // on all torrents once every second, and take
+ // the necessary actions then.
void abort() { m_abort = true; m_event = tracker_request::stopped; }
bool is_aborted() const { return m_abort; }
- // is called every second by session.
+ // 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();
- // returns true if it time for this torrent to make another
- // tracker request
- bool should_request() const
- {
- namespace time = boost::posix_time;
- return !m_paused &&
- m_next_request < time::second_clock::local_time();
- }
-
- void force_tracker_request()
- {
- namespace time = boost::posix_time;
- m_next_request = time::second_clock::local_time();
- }
-
+ // debug purpose only
void print(std::ostream& os) const;
void check_files(
@@ -132,13 +125,6 @@ namespace libtorrent
void use_interface(const char* net_interface);
peer_connection& connect_to_peer(const address& a);
- const torrent_info& torrent_file() const
- { return m_torrent_file; }
-
- policy& get_policy() { return *m_policy; }
-
- piece_manager& filesystem() { return m_storage; }
-
void set_ratio(float ratio)
{ assert(ratio >= 0.0f); m_ratio = ratio; }
@@ -169,10 +155,6 @@ namespace libtorrent
// the number of peers that belong to this torrent
int num_peers() const { return (int)m_connections.size(); }
- // returns true if this torrent has a connection
- // to a peer with the given peer_id
-// bool has_peer(const peer_id& id) const;
-
typedef std::map::iterator peer_iterator;
typedef std::map::const_iterator const_peer_iterator;
@@ -186,8 +168,10 @@ namespace libtorrent
// --------------------------------------------
// TRACKER MANAGEMENT
- // this is a callback called by the tracker_connection class
+ // these are callbacks called by the tracker_connection instance
+ // (either http_tracker_connection or udp_tracker_connection)
// when this torrent got a response from its tracker request
+ // or when a failure occured
virtual void tracker_response(std::vector& e, int interval);
virtual void tracker_request_timed_out();
virtual void tracker_request_error(int response_code, const std::string& str);
@@ -195,10 +179,32 @@ namespace libtorrent
// generates a request string for sending
// to the tracker
tracker_request generate_tracker_request();
- std::string tracker_password() const;
- boost::posix_time::ptime next_announce() const
- { return m_next_request; }
+ // if no password and username is set
+ // this will return an empty string, otherwise
+ // it will concatenate the login and password
+ // ready to be sent over http (but without
+ // base64 encoding).
+ std::string tracker_login() const;
+
+ // returns the absolute time when the next tracker
+ // announce will take place.
+ boost::posix_time::ptime next_announce() const;
+
+ // returns true if it is time for this torrent to make another
+ // tracker request
+ bool should_request() const;
+
+ // forcefully sets next_announce to the current time
+ void force_tracker_request();
+
+ // sets the username and password that will be sent to
+ // the tracker
+ void set_tracker_login(std::string const& name, std::string const& pw);
+
+ // the address of the tracker that we managed to
+ // announce ourself at the last time we tried to announce
+ const address& current_tracker() const;
// --------------------------------------------
// PIECE MANAGEMENT
@@ -242,9 +248,6 @@ namespace libtorrent
// all seeds and let the tracker know we're finished.
void completed();
- piece_picker& picker() { return m_picker; }
-
-
bool verify_piece(int piece_index);
// this is called from the peer_connection
@@ -266,18 +269,14 @@ namespace libtorrent
boost::filesystem::path save_path() const
{ return m_storage.save_path(); }
-
alert_manager& alerts() const;
+ piece_picker& picker() { return m_picker; }
+ policy& get_policy() { return *m_policy; }
+ piece_manager& filesystem() { return m_storage; }
+ torrent_info const& torrent_file() const { return m_torrent_file; }
+
torrent_handle get_handle() const;
- void set_tracker_login(std::string const& name, std::string const& pw)
- {
- m_username = name;
- m_password = pw;
- }
-
- const address& current_tracker() const;
-
// DEBUG
#ifndef NDEBUG
logger* spawn_logger(const char* title);
@@ -286,18 +285,20 @@ namespace libtorrent
void check_invariant();
#endif
+// --------------------------------------------
+ // RESOURCE MANAGEMENT
+
// this will distribute the given upload/download
- // quotas among the peers
+ // quotas and number of connections, among the peers
void distribute_resources();
- resource_request m_upload_bandwidth_quota;
+ resource_request m_ul_bandwidth_quota;
+ resource_request m_dl_bandwidth_quota;
+ resource_request m_unchoked_quota;
+ resource_request m_connections_quota;
- void set_upload_limit(int limit)
- {
- assert(limit >= -1);
- if (limit == -1) limit = std::numeric_limits::max();
- m_upload_bandwidth_limit = limit;
- }
+ void set_upload_limit(int limit);
+ void set_download_limit(int limit);
private:
@@ -391,8 +392,51 @@ namespace libtorrent
// the max number of bytes this torrent
// can upload per second
int m_upload_bandwidth_limit;
+ int m_download_bandwidth_limit;
};
+ inline boost::posix_time::ptime torrent::next_announce() const
+ { return m_next_request; }
+
+ // returns true if it is time for this torrent to make another
+ // tracker request
+ inline bool torrent::should_request() const
+ {
+ namespace time = boost::posix_time;
+ return !m_paused &&
+ m_next_request < time::second_clock::local_time();
+ }
+
+ inline void torrent::force_tracker_request()
+ {
+ namespace time = boost::posix_time;
+ m_next_request = time::second_clock::local_time();
+ }
+
+ inline void torrent::set_tracker_login(
+ std::string const& name
+ , std::string const& pw)
+ {
+ m_username = name;
+ m_password = pw;
+ }
+
+ inline void torrent::set_upload_limit(int limit)
+ {
+ assert(limit >= -1);
+ if (limit == -1) limit = std::numeric_limits::max();
+ if (limit < num_peers() * 10) limit = num_peers() * 10;
+ m_upload_bandwidth_limit = limit;
+ }
+
+ inline void torrent::set_download_limit(int limit)
+ {
+ assert(limit >= -1);
+ if (limit == -1) limit = std::numeric_limits::max();
+ if (limit < num_peers() * 10) limit = num_peers() * 10;
+ m_download_bandwidth_limit = limit;
+ }
+
}
#endif // TORRENT_TORRENT_HPP_INCLUDED
diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp
index b554a98bc..e79435d69 100755
--- a/src/http_tracker_connection.cpp
+++ b/src/http_tracker_connection.cpp
@@ -380,14 +380,6 @@ namespace libtorrent
}
return true;
}
- #ifndef NDEBUG
- if (requester())
- {
- requester()->debug_log(
- std::string("m_content_length = ")
- + boost::lexical_cast(m_content_length));
- }
- #endif
}
else if (line.substr(0, 18) == "Content-Encoding: ")
{
diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp
index 23793d0ce..1e3d2e4c5 100755
--- a/src/peer_connection.cpp
+++ b/src/peer_connection.cpp
@@ -92,7 +92,8 @@ namespace libtorrent
, m_attached_to_torrent(true)
, m_ses(ses)
, m_active(true)
- , m_added_to_selector(false)
+ , m_writability_monitored(false)
+ , m_readability_monitored(true)
, m_peer_interested(false)
, m_peer_choked(true)
, m_interesting(false)
@@ -110,8 +111,11 @@ namespace libtorrent
{
INVARIANT_CHECK;
- m_upload_bandwidth_quota.min = 10;
- m_upload_bandwidth_quota.max = 10;
+ m_ul_bandwidth_quota.min = 10;
+ m_ul_bandwidth_quota.max = 10;
+ m_dl_bandwidth_quota.min = 10;
+ m_dl_bandwidth_quota.max = std::numeric_limits::max();
+ m_dl_bandwidth_quota.given = 400;
assert(!m_socket->is_blocking());
assert(m_torrent != 0);
@@ -156,7 +160,8 @@ namespace libtorrent
, m_attached_to_torrent(0)
, m_ses(ses)
, m_active(false)
- , m_added_to_selector(false)
+ , m_writability_monitored(false)
+ , m_readability_monitored(true)
, m_peer_id()
, m_peer_interested(false)
, m_peer_choked(true)
@@ -172,7 +177,6 @@ namespace libtorrent
, m_disconnecting(false)
, m_became_uninterested(boost::posix_time::second_clock::local_time())
, m_became_uninteresting(boost::posix_time::second_clock::local_time())
-// , m_upload_bandwidth_quota_used(0)
{
INVARIANT_CHECK;
@@ -180,9 +184,13 @@ namespace libtorrent
// that are part of a torrent. Since this is an incoming
// connection, we have to give it some initial bandwidth
// to send the handshake
- m_upload_bandwidth_quota.min = 10;
- m_upload_bandwidth_quota.max = 400;
- m_upload_bandwidth_quota.given = 400;
+ m_ul_bandwidth_quota.min = 10;
+ m_ul_bandwidth_quota.max = 400;
+ m_ul_bandwidth_quota.given = 400;
+
+ m_dl_bandwidth_quota.min = 10;
+ m_dl_bandwidth_quota.max = std::numeric_limits::max();
+ m_dl_bandwidth_quota.given = 400;
assert(!m_socket->is_blocking());
@@ -280,22 +288,19 @@ namespace libtorrent
m_free_upload += free_upload;
}
- int peer_connection::send_quota_left() const
- {
- return m_upload_bandwidth_quota.given - m_upload_bandwidth_quota.used;
- }
-
void peer_connection::reset_upload_quota()
{
- m_upload_bandwidth_quota.used = 0;
+ m_ul_bandwidth_quota.used = 0;
+ m_dl_bandwidth_quota.used = 0;
+ if (!m_readability_monitored)
+ {
+ assert(!m_selector.is_readability_monitored(m_socket));
+ m_selector.monitor_readability(m_socket);
+ m_readability_monitored = true;
+ }
send_buffer_updated();
}
- resource_request* peer_connection::upload_bandwidth_quota()
- {
- return &m_upload_bandwidth_quota;
- }
-
void peer_connection::send_handshake()
{
INVARIANT_CHECK;
@@ -687,6 +692,7 @@ namespace libtorrent
r
, m_torrent->get_handle()
, m_socket->sender()
+ , m_peer_id
, "peer sent an illegal request, ignoring"));
}
}
@@ -797,8 +803,9 @@ namespace libtorrent
{
m_torrent->alerts().post_alert(
peer_error_alert(
- m_socket->sender()
- , "got a block that was not requested"));
+ m_socket->sender()
+ , m_peer_id
+ , "got a block that was not requested"));
}
#ifndef NDEBUG
(*m_logger) << " *** The block we just got was not requested ***\n";
@@ -864,9 +871,9 @@ namespace libtorrent
m_requests.erase(i);
}
- if (!has_data() && m_added_to_selector)
+ if (!can_write() && m_writability_monitored)
{
- m_added_to_selector = false;
+ m_writability_monitored = false;
m_selector.remove_writable(m_socket);
}
@@ -1312,7 +1319,9 @@ namespace libtorrent
INVARIANT_CHECK;
m_statistics.second_tick();
- m_upload_bandwidth_quota.used = (int)ceil(statistics().upload_rate());
+ m_ul_bandwidth_quota.used = std::min(
+ (int)ceil(statistics().upload_rate())
+ , m_ul_bandwidth_quota.given);
send_buffer_updated();
@@ -1329,9 +1338,9 @@ namespace libtorrent
// than we have uploaded OR if we are a seed
// have an unlimited upload rate
if(!m_send_buffer.empty() || (!m_requests.empty() && !is_choked()))
- m_upload_bandwidth_quota.max = std::numeric_limits::max();
+ m_ul_bandwidth_quota.max = std::numeric_limits::max();
else
- m_upload_bandwidth_quota.max = m_upload_bandwidth_quota.min;
+ m_ul_bandwidth_quota.max = m_ul_bandwidth_quota.min;
}
else
{
@@ -1355,8 +1364,8 @@ namespace libtorrent
upload_speed_limit = std::min(upload_speed_limit,
(double)std::numeric_limits::max());
- m_upload_bandwidth_quota.max
- = std::max((int)upload_speed_limit, m_upload_bandwidth_quota.min);
+ m_ul_bandwidth_quota.max
+ = std::max((int)upload_speed_limit, m_ul_bandwidth_quota.min);
}
/*
@@ -1371,7 +1380,7 @@ namespace libtorrent
// 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_upload_bandwidth_quota.wanted = std::numeric_limits::max();
+ m_ul_bandwidth_quota.wanted = std::numeric_limits::max();
}
else
{
@@ -1390,10 +1399,10 @@ namespace libtorrent
{
bias = -static_cast(m_statistics.download_rate() * ratio) / 2;
}
- m_upload_bandwidth_quota.wanted = static_cast(m_statistics.download_rate()) + bias;
+ m_ul_bandwidth_quota.wanted = static_cast(m_statistics.download_rate()) + bias;
// the maximum send_quota given our download rate from this peer
- if (m_upload_bandwidth_quota.wanted < 256) m_upload_bandwidth_quota.wanted = 256;
+ if (m_ul_bandwidth_quota.wanted < 256) m_ul_bandwidth_quota.wanted = 256;
}
*/
}
@@ -1410,10 +1419,16 @@ namespace libtorrent
assert(!m_socket->is_blocking());
assert(m_packet_size > 0);
assert(m_socket->is_readable());
+ assert(can_read());
+ assert(m_selector.is_readability_monitored(m_socket));
+
for(;;)
{
assert(m_packet_size > 0);
- int received = m_socket->receive(&m_recv_buffer[m_recv_pos], m_packet_size - m_recv_pos);
+ int max_receive = std::min(
+ m_dl_bandwidth_quota.left()
+ , m_packet_size - m_recv_pos);
+ int received = m_socket->receive(&m_recv_buffer[m_recv_pos], max_receive);
// connection closed
if (received == 0)
@@ -1438,6 +1453,14 @@ namespace libtorrent
m_last_receive = boost::posix_time::second_clock::local_time();
m_recv_pos += received;
+ m_dl_bandwidth_quota.used += received;
+ if (!can_read())
+ {
+ assert(m_readability_monitored);
+ assert(m_selector.is_readability_monitored(m_socket));
+ m_selector.remove_readable(m_socket);
+ m_readability_monitored = false;
+ }
switch(m_state)
{
@@ -1675,19 +1698,28 @@ namespace libtorrent
}
break;
}
+
+ // if we have used all our download quota,
+ // break the receive loop
+ if (!can_read()) break;
}
}
assert(m_packet_size > 0);
}
- bool peer_connection::has_data() const
+ bool peer_connection::can_write() const
{
// if we have requests or pending data to be sent or announcements to be made
// we want to send data
return ((!m_requests.empty() && !m_choked)
|| !m_send_buffer.empty())
- && send_quota_left() > 0;
+ && m_ul_bandwidth_quota.left() > 0;
+ }
+
+ bool peer_connection::can_read() const
+ {
+ return m_dl_bandwidth_quota.left() > 0;
}
// --------------------------
@@ -1700,7 +1732,7 @@ namespace libtorrent
INVARIANT_CHECK;
assert(m_socket->is_writable());
- assert(has_data());
+ assert(can_write());
// only add new piece-chunks if the send buffer is small enough
// otherwise there will be no end to how large it will be!
@@ -1766,15 +1798,15 @@ namespace libtorrent
m_announce_queue.clear();
}
- assert(m_upload_bandwidth_quota.used <= m_upload_bandwidth_quota.given);
+ assert(m_ul_bandwidth_quota.used <= m_ul_bandwidth_quota.given);
// send the actual buffer
if (!m_send_buffer.empty())
{
+ int amount_to_send
+ = std::min(m_ul_bandwidth_quota.left(), (int)m_send_buffer.size());
- int amount_to_send = (int)m_send_buffer.size();
- amount_to_send = std::min(send_quota_left(), amount_to_send);
- assert(amount_to_send>0);
+ assert(amount_to_send > 0);
// we have data that's scheduled for sending
int sent = m_socket->send(
@@ -1783,7 +1815,7 @@ namespace libtorrent
if (sent > 0)
{
- m_upload_bandwidth_quota.used += sent;
+ m_ul_bandwidth_quota.used += sent;
// manage the payload markers
int amount_payload = 0;
@@ -1840,14 +1872,14 @@ namespace libtorrent
m_last_sent = boost::posix_time::second_clock::local_time();
}
- assert(m_added_to_selector);
+ assert(m_writability_monitored);
send_buffer_updated();
}
#ifndef NDEBUG
void peer_connection::check_invariant() const
{
- assert(has_data() == m_selector.is_writability_monitored(m_socket));
+ assert(can_write() == m_selector.is_writability_monitored(m_socket));
/*
assert(m_num_pieces == std::count(
m_have_piece.begin()
@@ -1923,25 +1955,25 @@ namespace libtorrent
void peer_connection::send_buffer_updated()
{
- if (!has_data())
+ if (!can_write())
{
- if (m_added_to_selector)
+ if (m_writability_monitored)
{
m_selector.remove_writable(m_socket);
- m_added_to_selector = false;
+ m_writability_monitored = false;
}
assert(!m_selector.is_writability_monitored(m_socket));
return;
}
- assert(send_quota_left() > 0);
- assert(has_data());
- if (!m_added_to_selector)
+ assert(m_ul_bandwidth_quota.left() > 0);
+ assert(can_write());
+ if (!m_writability_monitored)
{
m_selector.monitor_writability(m_socket);
- m_added_to_selector = true;
+ m_writability_monitored = true;
}
- assert(m_added_to_selector);
+ assert(m_writability_monitored);
assert(m_selector.is_writability_monitored(m_socket));
}
diff --git a/src/policy.cpp b/src/policy.cpp
index fde900a14..042d8f769 100755
--- a/src/policy.cpp
+++ b/src/policy.cpp
@@ -748,6 +748,8 @@ namespace libtorrent
// it's probably just a NAT-check. Ignore the
// num connections constraint then.
// TODO: mske sure this works
+ // TODO: only allow _one_ connection to use this
+ // override at a time
if (m_torrent->num_peers() >= m_max_connections
&& c.get_socket()->sender().ip() != m_torrent->current_tracker().ip())
{
@@ -853,7 +855,7 @@ namespace libtorrent
if (m_torrent->alerts().should_post(alert::debug))
{
m_torrent->alerts().post_alert(
- peer_error_alert(remote, e.what()));
+ peer_error_alert(remote, id, e.what()));
}
}
catch(protocol_error& e)
@@ -861,7 +863,7 @@ namespace libtorrent
if (m_torrent->alerts().should_post(alert::debug))
{
m_torrent->alerts().post_alert(
- peer_error_alert(remote, e.what()));
+ peer_error_alert(remote, id, e.what()));
}
}
}
diff --git a/src/session.cpp b/src/session.cpp
index 313aa5c76..973bd3303 100755
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -271,6 +271,7 @@ namespace libtorrent { namespace detail
, m_listen_interface(listen_interface, listen_port_range.first)
, m_abort(false)
, m_upload_rate(-1)
+ , m_download_rate(-1)
, m_incoming_connection(false)
{
assert(listen_port_range.first > 0);
@@ -309,7 +310,6 @@ namespace libtorrent { namespace detail
{
m_connections.erase(m_disconnect_peer.back());
m_disconnect_peer.pop_back();
- assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
}
}
@@ -420,8 +420,6 @@ namespace libtorrent { namespace detail
#endif
boost::mutex::scoped_lock l(m_mutex);
- assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
-
if (m_abort)
{
m_tracker_manager.abort_all_requests();
@@ -467,7 +465,7 @@ namespace libtorrent { namespace detail
try
{
assert(m_selector.is_writability_monitored(p->first));
- assert(p->second->has_data());
+ assert(p->second->can_write());
assert(p->second->get_socket()->is_writable());
p->second->send_data();
}
@@ -486,7 +484,6 @@ namespace libtorrent { namespace detail
// pause the torrent
t->pause();
- assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
}
catch (std::exception& e)
{
@@ -495,13 +492,15 @@ namespace libtorrent { namespace detail
if (m_alerts.should_post(alert::debug))
{
m_alerts.post_alert(
- peer_error_alert(p->first->sender(), e.what()));
+ peer_error_alert(
+ p->first->sender()
+ , p->second->id()
+ , e.what()));
}
p->second->set_failed();
m_selector.remove(*i);
m_connections.erase(p);
- assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
}
}
}
@@ -573,7 +572,6 @@ namespace libtorrent { namespace detail
, e.what()));
}
- assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
t->pause();
}
catch (std::exception& e)
@@ -581,14 +579,16 @@ namespace libtorrent { namespace detail
if (m_alerts.should_post(alert::debug))
{
m_alerts.post_alert(
- peer_error_alert(p->first->sender(), e.what()));
+ peer_error_alert(
+ p->first->sender()
+ , p->second->id()
+ , e.what()));
}
// the connection wants to disconnect for some reason, remove it
// from the connection-list
p->second->set_failed();
m_selector.remove(*i);
m_connections.erase(p);
- assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
}
}
}
@@ -613,7 +613,8 @@ namespace libtorrent { namespace detail
m_alerts.post_alert(
peer_error_alert(
p->first->sender()
- , "socket received an exception"));
+ , p->second->id()
+ , "connection closed"));
}
m_selector.remove(*i);
@@ -622,7 +623,6 @@ namespace libtorrent { namespace detail
{
p->second->set_failed();
m_connections.erase(p);
- assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
}
}
@@ -659,12 +659,14 @@ namespace libtorrent { namespace detail
if (m_alerts.should_post(alert::debug))
{
m_alerts.post_alert(
- peer_error_alert(j->first->sender(), "connection timed out"));
+ peer_error_alert(
+ j->first->sender()
+ , j->second->id()
+ , "connection timed out"));
}
j->second->set_failed();
m_selector.remove(j->first);
m_connections.erase(j);
- assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
continue;
}
@@ -713,7 +715,13 @@ namespace libtorrent { namespace detail
? std::numeric_limits::max()
: m_upload_rate
, m_torrents
- , &torrent::m_upload_bandwidth_quota);
+ , &torrent::m_ul_bandwidth_quota);
+
+ allocate_resources(m_download_rate == -1
+ ? std::numeric_limits::max()
+ : m_download_rate
+ , m_torrents
+ , &torrent::m_dl_bandwidth_quota);
for (std::map >::iterator i
= m_torrents.begin(); i != m_torrents.end(); ++i)
@@ -795,15 +803,18 @@ namespace libtorrent { namespace detail
i != m_connections.end();
++i)
{
- if (i->second->has_data() != m_selector.is_writability_monitored(i->first))
+ if (i->second->can_write() != m_selector.is_writability_monitored(i->first)
+ || i->second->can_read() != m_selector.is_readability_monitored(i->first))
{
std::ofstream error_log("error.log", std::ios_base::app);
boost::shared_ptr p = i->second;
- error_log << "session_imple::check_invariant()\n"
- "peer_connection::has_data() != is_writability_monitored()\n";
- error_log << "peer_connection::has_data() " << p->has_data() << "\n";
- error_log << "peer_connection::send_quota_left " << p->send_quota_left() << "\n";
- error_log << "peer_connection::upload_bandwidth_quota()->given " << p->upload_bandwidth_quota()->given << "\n";
+ error_log << "selector::is_writability_monitored() " << m_selector.is_writability_monitored(i->first) << "\n";
+ error_log << "selector::is_readability_monitored() " << m_selector.is_readability_monitored(i->first) << "\n";
+ error_log << "peer_connection::can_write() " << p->can_write() << "\n";
+ error_log << "peer_connection::can_read() " << p->can_read() << "\n";
+ error_log << "peer_connection::ul_quota_left " << p->m_ul_bandwidth_quota.left() << "\n";
+ error_log << "peer_connection::dl_quota_left " << p->m_dl_bandwidth_quota.left() << "\n";
+ error_log << "peer_connection::m_ul_bandwidth_quota.given " << p->m_ul_bandwidth_quota.given << "\n";
error_log << "peer_connection::get_peer_id " << p->get_peer_id() << "\n";
error_log << "place: " << place << "\n";
error_log.flush();
@@ -1007,12 +1018,26 @@ namespace libtorrent
for (detail::session_impl::connection_map::iterator i
= m_impl.m_connections.begin();
- i != m_impl.m_connections.end();)
+ i != m_impl.m_connections.end(); ++i)
{
- i->second->upload_bandwidth_quota()->given = std::numeric_limits::max();
-// i->second->update_send_quota_left();
+ i->second->m_ul_bandwidth_quota.given = std::numeric_limits::max();
}
+ }
+ void session::set_download_rate_limit(int bytes_per_second)
+ {
+ assert(bytes_per_second > 0 || bytes_per_second == -1);
+ boost::mutex::scoped_lock l(m_impl.m_mutex);
+ m_impl.m_download_rate = bytes_per_second;
+ if (m_impl.m_download_rate != -1 || !m_impl.m_connections.empty())
+ return;
+
+ for (detail::session_impl::connection_map::iterator i
+ = m_impl.m_connections.begin();
+ i != m_impl.m_connections.end(); ++i)
+ {
+ i->second->m_dl_bandwidth_quota.given = std::numeric_limits::max();
+ }
}
std::auto_ptr session::pop_alert()
diff --git a/src/storage.cpp b/src/storage.cpp
index f344f8e88..67e2aa083 100755
--- a/src/storage.cpp
+++ b/src/storage.cpp
@@ -1189,8 +1189,9 @@ namespace libtorrent
}
assert(file_offset > current_offset);
- int skip_blocks = (file_offset - current_offset + m_info.piece_length() - 1)
- / m_info.piece_length();
+ int skip_blocks = static_cast(
+ (file_offset - current_offset + m_info.piece_length() - 1)
+ / m_info.piece_length());
for (int i = current_slot; i < current_slot + skip_blocks; ++i)
{
diff --git a/src/torrent.cpp b/src/torrent.cpp
index 4e577a730..1b81c67da 100755
--- a/src/torrent.cpp
+++ b/src/torrent.cpp
@@ -166,6 +166,7 @@ namespace libtorrent
, m_ratio(0.f)
, m_net_interface(net_interface.ip(), address::any_port)
, m_upload_bandwidth_limit(std::numeric_limits::max())
+ , m_download_bandwidth_limit(std::numeric_limits::max())
{
assert(torrent_file.begin_files() != torrent_file.end_files());
m_have_pieces.resize(torrent_file.num_pieces(), false);
@@ -404,7 +405,7 @@ namespace libtorrent
i->second->announce_piece(index);
}
- std::string torrent::tracker_password() const
+ std::string torrent::tracker_login() const
{
if (m_username.empty() && m_password.empty()) return "";
return m_username + ":" + m_password;
@@ -639,9 +640,13 @@ namespace libtorrent
m_policy->pulse();
}
- m_upload_bandwidth_quota.used = 0;
- m_upload_bandwidth_quota.max = 0;
- m_upload_bandwidth_quota.min = 0;
+ m_ul_bandwidth_quota.used = 0;
+ m_ul_bandwidth_quota.max = 0;
+ m_ul_bandwidth_quota.min = 0;
+
+ m_dl_bandwidth_quota.used = 0;
+ m_dl_bandwidth_quota.min = 0;
+ m_dl_bandwidth_quota.max = 0;
for (peer_iterator i = m_connections.begin();
i != m_connections.end();
@@ -649,26 +654,49 @@ namespace libtorrent
{
peer_connection* p = i->second;
m_stat += p->statistics();
+
+ // updates the peer connection's ul/dl bandwidth
+ // resource requests
p->second_tick();
- m_upload_bandwidth_quota.used += p->m_upload_bandwidth_quota.used;
- m_upload_bandwidth_quota.min += p->m_upload_bandwidth_quota.min;
- m_upload_bandwidth_quota.max = saturated_add(
- m_upload_bandwidth_quota.max
- , p->m_upload_bandwidth_quota.max);
+
+ m_ul_bandwidth_quota.used += p->m_ul_bandwidth_quota.used;
+ m_ul_bandwidth_quota.min += p->m_ul_bandwidth_quota.min;
+ m_dl_bandwidth_quota.used += p->m_dl_bandwidth_quota.used;
+ m_dl_bandwidth_quota.min += p->m_dl_bandwidth_quota.min;
+
+ m_ul_bandwidth_quota.max = saturated_add(
+ m_ul_bandwidth_quota.max
+ , p->m_ul_bandwidth_quota.max);
+
+ m_dl_bandwidth_quota.max = saturated_add(
+ m_dl_bandwidth_quota.max
+ , p->m_dl_bandwidth_quota.max);
+
}
- m_upload_bandwidth_quota.max
- = std::min(m_upload_bandwidth_quota.max, m_upload_bandwidth_limit);
+ m_ul_bandwidth_quota.max
+ = std::min(m_ul_bandwidth_quota.max, m_upload_bandwidth_limit);
+
+ m_dl_bandwidth_quota.max
+ = std::min(m_dl_bandwidth_quota.max, m_download_bandwidth_limit);
m_stat.second_tick();
}
void torrent::distribute_resources()
{
- allocate_resources(m_upload_bandwidth_quota.given
+ // distribute allowed upload among the peers
+ allocate_resources(m_ul_bandwidth_quota.given
, m_connections
- , &peer_connection::m_upload_bandwidth_quota);
+ , &peer_connection::m_ul_bandwidth_quota);
+ // distribute allowed download among the peers
+ allocate_resources(m_dl_bandwidth_quota.given
+ , m_connections
+ , &peer_connection::m_dl_bandwidth_quota);
+
+ // tell all peers to reset their used quota. This is
+ // a new second and they can again use up their quota
for (std::map::iterator i = m_connections.begin();
i != m_connections.end(); ++i)
{
diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp
index 2ce6caa3b..e665ea0db 100755
--- a/src/torrent_handle.cpp
+++ b/src/torrent_handle.cpp
@@ -446,15 +446,15 @@ namespace libtorrent
p.total_download = statistics.total_payload_download();
p.total_upload = statistics.total_payload_upload();
- if (peer->upload_bandwidth_quota()->given == std::numeric_limits::max())
+ if (peer->m_ul_bandwidth_quota.given == std::numeric_limits::max())
p.upload_limit = -1;
else
- p.upload_limit = peer->upload_bandwidth_quota()->given;
+ p.upload_limit = peer->m_ul_bandwidth_quota.given;
- if (peer->upload_bandwidth_quota()->max == std::numeric_limits::max())
+ if (peer->m_ul_bandwidth_quota.max == std::numeric_limits::max())
p.upload_ceiling = -1;
else
- p.upload_ceiling = peer->upload_bandwidth_quota()->max;
+ p.upload_ceiling = peer->m_ul_bandwidth_quota.given;
p.load_balancing = peer->total_free_upload();