diff --git a/libtorrent/include/libtorrent/alert_types.hpp b/libtorrent/include/libtorrent/alert_types.hpp index 48491bca4..e6ade9a26 100755 --- a/libtorrent/include/libtorrent/alert_types.hpp +++ b/libtorrent/include/libtorrent/alert_types.hpp @@ -261,6 +261,17 @@ namespace libtorrent { return std::auto_ptr(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 clone() const + { return std::auto_ptr(new torrent_checked_alert(*this)); } + }; + + struct TORRENT_EXPORT url_seed_alert: torrent_alert { url_seed_alert( diff --git a/libtorrent/include/libtorrent/allocate_resources.hpp b/libtorrent/include/libtorrent/allocate_resources.hpp deleted file mode 100644 index 3d8237914..000000000 --- a/libtorrent/include/libtorrent/allocate_resources.hpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - -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 -#include - -#include - -#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::max() it means there is an infinite - // supply of resources (so everyone can get what they want). - - void allocate_resources( - int resources - , std::map >& torrents - , resource_request torrent::* res); - - void allocate_resources( - int resources - , std::map& connections - , resource_request peer_connection::* res); - - // Used for global limits. - void allocate_resources( - int resources - , std::vector& _sessions - , resource_request session::* res); -} - - -#endif diff --git a/libtorrent/include/libtorrent/aux_/allocate_resources_impl.hpp b/libtorrent/include/libtorrent/aux_/allocate_resources_impl.hpp deleted file mode 100644 index 31865d40a..000000000 --- a/libtorrent/include/libtorrent/aux_/allocate_resources_impl.hpp +++ /dev/null @@ -1,328 +0,0 @@ -/* - -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_IMPL_HPP_INCLUDED -#define TORRENT_ALLOCATE_RESOURCES_IMPL_HPP_INCLUDED - -#include -#include - -#include - -#include "libtorrent/resource_request.hpp" -#include "libtorrent/peer_id.hpp" -#include "libtorrent/socket.hpp" -#include "libtorrent/size_type.hpp" - -#ifdef min -#undef min -#endif - -#ifdef max -#undef max -#endif - -namespace libtorrent -{ - - int saturated_add(int a, int b); - - namespace aux - { - // give num_resources to r, - // return how how many were actually accepted. - inline int give(resource_request& r, int num_resources) - { - assert(num_resources >= 0); - assert(r.given <= r.max); - - int accepted = (std::min)(num_resources, r.max - r.given); - assert(accepted >= 0); - - r.given += accepted; - assert(r.given <= r.max); - - return accepted; - } - - inline int div_round_up(int numerator, int denominator) - { - return (numerator + denominator - 1) / denominator; - } - -#ifndef NDEBUG - - template - class allocate_resources_contract_check - { - int m_resources; - It m_start; - It m_end; - resource_request T::* m_res; - - public: - allocate_resources_contract_check( - int resources - , It start - , It end - , resource_request T::* res) - : m_resources(resources) - , m_start(start) - , m_end(end) - , m_res(res) - { - assert(m_resources >= 0); - for (It i = m_start, end(m_end); i != end; ++i) - { - assert(((*i).*m_res).max >= 0); - assert(((*i).*m_res).given >= 0); - } - } - - ~allocate_resources_contract_check() - { - int sum_given = 0; - int sum_max = 0; - int sum_min = 0; - for (It i = m_start, end(m_end); i != end; ++i) - { - assert(((*i).*m_res).max >= 0); - assert(((*i).*m_res).min >= 0); - assert(((*i).*m_res).max >= ((*i).*m_res).min); - assert(((*i).*m_res).given >= 0); - assert(((*i).*m_res).given <= ((*i).*m_res).max); - - sum_given = saturated_add(sum_given, ((*i).*m_res).given); - sum_max = saturated_add(sum_max, ((*i).*m_res).max); - sum_min = saturated_add(sum_min, ((*i).*m_res).min); - } - if (sum_given != (std::min)(std::max(m_resources, sum_min), sum_max)) - { - std::cerr << sum_given << " " << m_resources << " " << sum_min << " " << sum_max << std::endl; - assert(false); - } - } - }; - -#endif - - template - void allocate_resources_impl( - int resources - , It start - , It end - , resource_request T::* res) - { - assert(resources >= 0); - #ifndef NDEBUG - allocate_resources_contract_check contract_check( - resources - , start - , end - , res); - #endif - - for (It i = start; i != end; ++i) - { - resource_request& r = (*i).*res; - r.leftovers = (std::max)(r.used - r.given, 0); - } - - if (resources == resource_request::inf) - { - // No competition for resources. - // Just give everyone what they want. - for (It i = start; i != end; ++i) - { - ((*i).*res).given = ((*i).*res).max; - } - return; - } - - // Resources are scarce - - int sum_max = 0; - int sum_min = 0; - // the number of consumer that saturated their - // quota last time slice - int num_saturated = 0; - // the total resources that those saturated their - // quota used. This is used to calculate the mean - // of the saturating consumers, in order to - // balance their quotas for the next time slice. - size_type saturated_sum = 0; - for (It i = start; i != end; ++i) - { - resource_request& r = (*i).*res; - sum_max = saturated_add(sum_max, r.max); - assert(r.min < resource_request::inf); - assert(r.min >= 0); - assert(r.min <= r.max); - sum_min += r.min; - - // a consumer that uses 95% or more of its assigned - // quota is considered saturating - size_type used = r.used; - if (r.given == 0) continue; - if (used * 20 / r.given >= 19) - { - ++num_saturated; - saturated_sum += r.given; - } - } - - if (sum_max <= resources) - { - // it turns out that there's no competition for resources - // after all. - for (It i = start; i != end; ++i) - { - ((*i).*res).given = ((*i).*res).max; - } - return; - } - - if (sum_min >= resources) - { - // the amount of resources is smaller than - // the minimum resources to distribute, so - // give everyone the minimum - for (It i = start; i != end; ++i) - { - ((*i).*res).given = ((*i).*res).min; - } - return; - } - - // now, the "used" field will be used as a target value. - // the algorithm following this loop will then scale the - // used values to fit the available resources and store - // the scaled values as given. So, the ratios of the - // used values will be maintained. - for (It i = start; i != end; ++i) - { - resource_request& r = (*i).*res; - - int target; - size_type used = r.used; - if (r.given > 0 && used * 20 / r.given >= 19) - { - assert(num_saturated > 0); - target = div_round_up(saturated_sum, num_saturated); - target += div_round_up(target, 10); - } - else - { - target = r.used; - } - if (target > r.max) target = r.max; - else if (target < r.min) target = r.min; - - // move 12.5% towards the the target value - r.used = r.given + div_round_up(target - r.given, 8); - r.given = r.min; - } - - - resources = (std::max)(resources, sum_min); - int resources_to_distribute = (std::min)(resources, sum_max) - sum_min; - assert(resources_to_distribute >= 0); -#ifndef NDEBUG - int prev_resources_to_distribute = resources_to_distribute; -#endif - while (resources_to_distribute > 0) - { - // in order to scale, we need to calculate the sum of - // all the used values. - size_type total_used = 0; - size_type max_used = 0; - for (It i = start; i != end; ++i) - { - resource_request& r = (*i).*res; - if (r.given == r.max) continue; - - assert(r.given < r.max); - - max_used = (std::max)(max_used, (size_type)r.used + 1); - total_used += (size_type)r.used + 1; - } - - - size_type kNumer = resources_to_distribute; - size_type kDenom = total_used; - assert(kNumer >= 0); - assert(kDenom >= 0); - assert(kNumer <= (std::numeric_limits::max)()); - - if (kNumer * max_used <= kDenom) - { - kNumer = 1; - kDenom = max_used; - assert(kDenom >= 0); - } - - for (It i = start; i != end && resources_to_distribute > 0; ++i) - { - resource_request& r = (*i).*res; - if (r.given == r.max) continue; - - assert(r.given < r.max); - - size_type used = (size_type)r.used + 1; - if (used < 1) used = 1; - size_type to_give = used * kNumer / kDenom; - if (to_give > resources_to_distribute) - to_give = resources_to_distribute; - assert(to_give >= 0); - assert(to_give <= resources_to_distribute); -#ifndef NDEBUG - int tmp = resources_to_distribute; -#endif - resources_to_distribute -= give(r, (int)to_give); - assert(resources_to_distribute <= tmp); - assert(resources_to_distribute >= 0); - } - - assert(resources_to_distribute >= 0); - assert(resources_to_distribute < prev_resources_to_distribute); -#ifndef NDEBUG - prev_resources_to_distribute = resources_to_distribute; -#endif - } - assert(resources_to_distribute == 0); - } - - } // namespace libtorrent::aux -} - - -#endif diff --git a/libtorrent/include/libtorrent/aux_/session_impl.hpp b/libtorrent/include/libtorrent/aux_/session_impl.hpp index 207016898..bb3b41705 100644 --- a/libtorrent/include/libtorrent/aux_/session_impl.hpp +++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp @@ -273,8 +273,20 @@ namespace libtorrent void set_max_connections(int limit); void set_max_uploads(int limit); - int num_uploads() const; - int num_connections() const; + 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) + { + torrent* t = c.associated_torrent().lock().get(); + assert(t); + t->unchoke_peer(c); + ++m_num_unchoked; + } session_status status() const; void set_peer_id(peer_id const& id); @@ -417,6 +429,28 @@ namespace libtorrent 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; diff --git a/libtorrent/include/libtorrent/bt_peer_connection.hpp b/libtorrent/include/libtorrent/bt_peer_connection.hpp index 4f13b2fcf..0fcba89a8 100755 --- a/libtorrent/include/libtorrent/bt_peer_connection.hpp +++ b/libtorrent/include/libtorrent/bt_peer_connection.hpp @@ -65,7 +65,6 @@ 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" diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp index 976e03794..8dfc2b805 100755 --- a/libtorrent/include/libtorrent/peer_connection.hpp +++ b/libtorrent/include/libtorrent/peer_connection.hpp @@ -64,7 +64,6 @@ 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" @@ -213,7 +212,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); + void second_tick(float tick_interval) throw(); boost::shared_ptr get_socket() const { return m_socket; } tcp::endpoint const& remote() const { return m_remote; } diff --git a/libtorrent/include/libtorrent/policy.hpp b/libtorrent/include/libtorrent/policy.hpp index 6c976d047..7a789ec8c 100755 --- a/libtorrent/include/libtorrent/policy.hpp +++ b/libtorrent/include/libtorrent/policy.hpp @@ -89,7 +89,7 @@ namespace libtorrent void new_connection(peer_connection& c); // the given connection was just closed - void connection_closed(const peer_connection& c); + void connection_closed(const peer_connection& c) throw(); // the peer has got at least one interesting piece void peer_is_interesting(peer_connection& c); @@ -155,6 +155,13 @@ 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; @@ -203,25 +210,18 @@ 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::iterator iterator; typedef std::list::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,8 +233,7 @@ 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(); @@ -242,10 +241,6 @@ 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; @@ -253,7 +248,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; }; } diff --git a/libtorrent/include/libtorrent/resource_request.hpp b/libtorrent/include/libtorrent/resource_request.hpp deleted file mode 100755 index 1e41b9cbb..000000000 --- a/libtorrent/include/libtorrent/resource_request.hpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - -Copyright (c) 2003, 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. - -*/ - -#ifndef TORRENT_RESOURCE_REQUEST_HPP_INCLUDED -#define TORRENT_RESOURCE_REQUEST_HPP_INCLUDED - -#include - -#ifdef min -#undef min -#endif - -#ifdef max -#undef max -#endif - -#include "libtorrent/config.hpp" - -namespace libtorrent -{ - struct TORRENT_EXPORT resource_request - { - resource_request() - : used(0) - , min(0) - , max(0) - , given(0) - , leftovers(0) - {} - - resource_request(int used_, int min_, int max_, int given_) - : used(used_) - , min(min_) - , max(max_) - , given(given_) - , leftovers(0) - {} - - int left() const - { - assert(given <= max); - assert(given >= min); - assert(used >= 0); - return (std::max)(given - used, 0); - } - - void reset() { used = leftovers; leftovers = 0; } - - static const int inf = boost::integer_traits::const_max; - - // right now I'm actively using this amount - int used; - - // given cannot be smaller than min - // and not greater than max. - int min; - int max; - - // Reply: Okay, you're allowed to use this amount (a compromise): - int given; - - // this is the amount of resources that exceeded the - // given limit. When the used field is reset (after resources - // have been distributed), it is reset to this number. - int leftovers; - }; -} - - -#endif diff --git a/libtorrent/include/libtorrent/session.hpp b/libtorrent/include/libtorrent/session.hpp index f721b3293..a123314ed 100755 --- a/libtorrent/include/libtorrent/session.hpp +++ b/libtorrent/include/libtorrent/session.hpp @@ -61,7 +61,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/version.hpp" #include "libtorrent/fingerprint.hpp" -#include "libtorrent/resource_request.hpp" #include "libtorrent/storage.hpp" #ifdef _MSC_VER @@ -266,12 +265,6 @@ 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 diff --git a/libtorrent/include/libtorrent/session_settings.hpp b/libtorrent/include/libtorrent/session_settings.hpp index e5bb9879a..3a145c687 100644 --- a/libtorrent/include/libtorrent/session_settings.hpp +++ b/libtorrent/include/libtorrent/session_settings.hpp @@ -105,7 +105,8 @@ namespace libtorrent , send_redundant_have(false) , lazy_bitfields(true) , inactivity_timeout(600) - , unchoke_interval(20) + , unchoke_interval(15) + , optimistic_unchoke_multiplier(4) , num_want(200) , initial_picker_threshold(4) , allowed_fast_set_size(10) @@ -242,6 +243,10 @@ 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; diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index 2eef2656b..6781465c0 100755 --- a/libtorrent/include/libtorrent/torrent.hpp +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -62,7 +62,6 @@ 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" @@ -154,10 +153,6 @@ 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 @@ -254,6 +249,15 @@ namespace libtorrent void remove_url_seed(std::string const& url) { m_web_seeds.erase(url); } + std::set url_seeds() const + { return m_web_seeds; } + + bool free_upload_slots() const + { return m_num_uploads < m_max_uploads; } + + void choke_peer(peer_connection& c); + bool unchoke_peer(peer_connection& c); + // used by peer_connection to attach itself to a torrent // since incoming connections don't know what torrent // they're a part of until they have received an info_hash. @@ -516,11 +520,6 @@ 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); @@ -530,7 +529,9 @@ 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 @@ -705,9 +706,9 @@ namespace libtorrent // determine the timeout until next try. int m_failed_trackers; - // 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. + // 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. int m_time_scaler; // the bitmask that says which pieces we have @@ -774,6 +775,15 @@ 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 number of unchoked peers in this torrent + int m_num_uploads; + + // the maximum number of connections for this torrent + int m_max_connections; #ifndef TORRENT_DISABLE_EXTENSIONS typedef std::list > extension_list_t; diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp index 3f7ae5bcc..31a39c38e 100755 --- a/libtorrent/include/libtorrent/torrent_handle.hpp +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_TORRENT_HANDLE_HPP_INCLUDED #include +#include #ifdef _MSC_VER #pragma warning(push, 1) @@ -273,7 +274,9 @@ namespace libtorrent std::vector const& trackers() const; void replace_trackers(std::vector const&) const; - void add_url_seed(std::string const& url); + void add_url_seed(std::string const& url) const; + void remove_url_seed(std::string const& url) const; + std::set url_seeds() const; bool has_metadata() const; const torrent_info& get_torrent_info() const; diff --git a/libtorrent/include/libtorrent/web_peer_connection.hpp b/libtorrent/include/libtorrent/web_peer_connection.hpp index b3ca73c4d..1290f14a1 100755 --- a/libtorrent/include/libtorrent/web_peer_connection.hpp +++ b/libtorrent/include/libtorrent/web_peer_connection.hpp @@ -65,7 +65,6 @@ 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" diff --git a/libtorrent/src/Makefile.am b/libtorrent/src/Makefile.am index fabe68b65..bc4fb7353 100644 --- a/libtorrent/src/Makefile.am +++ b/libtorrent/src/Makefile.am @@ -12,8 +12,7 @@ kademlia/rpc_manager.cpp \ kademlia/traversal_algorithm.cpp endif -libtorrent_la_SOURCES = allocate_resources.cpp \ -entry.cpp escape_string.cpp \ +libtorrent_la_SOURCES = entry.cpp escape_string.cpp \ peer_connection.cpp bt_peer_connection.cpp web_peer_connection.cpp \ natpmp.cpp piece_picker.cpp policy.cpp session.cpp session_impl.cpp sha1.cpp \ stat.cpp storage.cpp torrent.cpp torrent_handle.cpp pe_crypto.cpp \ @@ -28,8 +27,6 @@ $(kademlia_sources) noinst_HEADERS = \ $(top_srcdir)/include/libtorrent/alert.hpp \ $(top_srcdir)/include/libtorrent/alert_types.hpp \ -$(top_srcdir)/include/libtorrent/allocate_resources.hpp \ -$(top_srcdir)/include/libtorrent/aux_/allocate_resources_impl.hpp \ $(top_srcdir)/include/libtorrent/aux_/session_impl.hpp \ $(top_srcdir)/include/libtorrent/bandwidth_manager.hpp \ $(top_srcdir)/include/libtorrent/bencode.hpp \ @@ -71,7 +68,6 @@ $(top_srcdir)/include/libtorrent/peer_request.hpp \ $(top_srcdir)/include/libtorrent/piece_block_progress.hpp \ $(top_srcdir)/include/libtorrent/piece_picker.hpp \ $(top_srcdir)/include/libtorrent/policy.hpp \ -$(top_srcdir)/include/libtorrent/resource_request.hpp \ $(top_srcdir)/include/libtorrent/session.hpp \ $(top_srcdir)/include/libtorrent/size_type.hpp \ $(top_srcdir)/include/libtorrent/socket.hpp \ diff --git a/libtorrent/src/allocate_resources.cpp b/libtorrent/src/allocate_resources.cpp deleted file mode 100644 index deef06dc4..000000000 --- a/libtorrent/src/allocate_resources.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* - -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 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 . -//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 . - -#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 -#include -#include - -#if defined(_MSC_VER) && _MSC_VER < 1310 -#define for if (false) {} else for -#else -#include -#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 >::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::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 >& 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& 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::intrusive_ptr > const& p) - { - return *p.second; - } - - peer_connection& pick_peer2( - std::pair const& p) - { - return *p.second; - } - - torrent& deref(std::pair > const& p) - { - return *p.second; - } - - session& deref(session* p) - { - return *p; - } - } - - void allocate_resources( - int resources - , std::map >& c - , resource_request torrent::* res) - { - typedef std::map >::iterator orig_iter; - typedef std::pair > in_param; - typedef boost::transform_iterator 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& c - , resource_request peer_connection::* res) - { - typedef std::map::iterator orig_iter; - typedef std::pair in_param; - typedef boost::transform_iterator 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& _sessions - , resource_request session::* res) - { - typedef std::vector::iterator orig_iter; - typedef session* in_param; - typedef boost::transform_iterator new_iter; - - aux::allocate_resources_impl( - resources - , new_iter(_sessions.begin(), &aux::deref) - , new_iter(_sessions.end(), &aux::deref) - , res); - } - -#endif - -} // namespace libtorrent diff --git a/libtorrent/src/bt_peer_connection.cpp b/libtorrent/src/bt_peer_connection.cpp index 07ebf5431..2a4347778 100755 --- a/libtorrent/src/bt_peer_connection.cpp +++ b/libtorrent/src/bt_peer_connection.cpp @@ -1369,7 +1369,7 @@ namespace libtorrent assert(t->is_seed() == (std::count(bitfield.begin(), bitfield.end(), true) == num_pieces)); if (t->is_seed() && m_ses.settings().lazy_bitfields) { - num_lazy_pieces = std::min(50, num_pieces / 10); + num_lazy_pieces = (std::min)(50, num_pieces / 10); if (num_lazy_pieces < 1) num_lazy_pieces = 1; for (int i = 0; i < num_pieces; ++i) { @@ -1735,7 +1735,7 @@ namespace libtorrent if (m_sync_bytes_read >= 512) throw protocol_error("sync hash not found within 532 bytes"); - cut_receive_buffer(bytes_processed, std::min(packet_size(), (512+20) - m_sync_bytes_read)); + cut_receive_buffer(bytes_processed, (std::min)(packet_size(), (512+20) - m_sync_bytes_read)); assert(!packet_finished()); return; @@ -1873,7 +1873,7 @@ namespace libtorrent if (m_sync_bytes_read >= 512) throw protocol_error("sync verification constant not found within 520 bytes"); - cut_receive_buffer(bytes_processed, std::min(packet_size(), (512+8) - m_sync_bytes_read)); + cut_receive_buffer(bytes_processed, (std::min)(packet_size(), (512+8) - m_sync_bytes_read)); assert(!packet_finished()); return; diff --git a/libtorrent/src/http_tracker_connection.cpp b/libtorrent/src/http_tracker_connection.cpp index 936f8292a..8af09e6a6 100755 --- a/libtorrent/src/http_tracker_connection.cpp +++ b/libtorrent/src/http_tracker_connection.cpp @@ -250,7 +250,7 @@ namespace libtorrent assert(m_state == read_body); if (m_content_length >= 0) return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos - , m_recv_buffer.begin + std::min(m_recv_pos + , m_recv_buffer.begin + (std::min)(m_recv_pos , m_body_start_pos + m_content_length)); else return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos @@ -408,7 +408,7 @@ namespace libtorrent { m_send_buffer += "numwant="; m_send_buffer += boost::lexical_cast( - std::min(req.num_want, 999)); + (std::min)(req.num_want, 999)); m_send_buffer += '&'; } if (m_settings.announce_ip != address() && !url_has_argument(request, "ip")) diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index 86d4e1500..09fe0da85 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -109,8 +109,8 @@ namespace libtorrent , m_prefer_whole_pieces(false) , m_request_large_blocks(false) , m_non_prioritized(false) - , m_upload_limit(resource_request::inf) - , m_download_limit(resource_request::inf) + , m_upload_limit(bandwidth_limit::inf) + , m_download_limit(bandwidth_limit::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(resource_request::inf) - , m_download_limit(resource_request::inf) + , m_upload_limit(bandwidth_limit::inf) + , m_download_limit(bandwidth_limit::inf) , m_peer_info(peerinfo) , m_speed(slow) , m_remote_bytes_dled(0) @@ -441,8 +441,6 @@ namespace libtorrent void peer_connection::add_stat(size_type downloaded, size_type uploaded) { - INVARIANT_CHECK; - m_statistics.add_stat(downloaded, uploaded); } @@ -526,28 +524,21 @@ 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& t): m_t(&t) {} - ~disconnect_torrent() { if (m_t) m_t->reset(); } - void cancel() { m_t = 0; } - private: - boost::weak_ptr* m_t; - }; - + void peer_connection::attach_to_torrent(sha1_hash const& ih) { INVARIANT_CHECK; assert(!m_disconnecting); - m_torrent = m_ses.find_torrent(ih); - - boost::shared_ptr t = m_torrent.lock(); + assert(m_torrent.expired()); + boost::weak_ptr wpt = m_ses.find_torrent(ih); + boost::shared_ptr t = wpt.lock(); if (t && t->is_aborted()) { - m_torrent.reset(); +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << " *** the torrent has been aborted\n"; +#endif t.reset(); } @@ -555,12 +546,18 @@ namespace libtorrent { // we couldn't find the torrent! #ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << " couldn't find a torrent with the given info_hash: " << ih << "\n"; + (*m_logger) << " *** couldn't find a torrent with the given info_hash: " << ih << "\n"; + (*m_logger) << " torrents:\n"; + session_impl::torrent_map const& torrents = m_ses.m_torrents; + for (session_impl::torrent_map::const_iterator i = torrents.begin() + , end(torrents.end()); i != end; ++i) + { + (*m_logger) << " " << i->second->torrent_file().info_hash() << "\n"; + } #endif 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 @@ -571,21 +568,27 @@ 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); - disconnect.cancel(); + assert(!m_torrent.expired()); } // message handlers @@ -1543,7 +1546,7 @@ namespace libtorrent // if the peer has the piece and we want // to download it, request it - if (m_have_piece.size() > index + if (int(m_have_piece.size()) > index && m_have_piece[index] && t->has_picker() && t->picker().piece_priority(index) > 0) @@ -1656,7 +1659,7 @@ namespace libtorrent int block_offset = block.block_index * t->block_size(); int block_size - = std::min((int)t->torrent_file().piece_size(block.piece_index)-block_offset, + = (std::min)((int)t->torrent_file().piece_size(block.piece_index)-block_offset, t->block_size()); assert(block_size > 0); assert(block_size <= t->block_size()); @@ -1757,7 +1760,7 @@ namespace libtorrent piece_block block = m_request_queue.front(); int block_offset = block.block_index * t->block_size(); - int block_size = std::min((int)t->torrent_file().piece_size( + int block_size = (std::min)((int)t->torrent_file().piece_size( block.piece_index) - block_offset, t->block_size()); assert(block_size > 0); assert(block_size <= t->block_size()); @@ -1797,7 +1800,7 @@ namespace libtorrent #endif */ block_offset = block.block_index * t->block_size(); - block_size = std::min((int)t->torrent_file().piece_size( + block_size = (std::min)((int)t->torrent_file().piece_size( block.piece_index) - block_offset, t->block_size()); assert(block_size > 0); assert(block_size <= t->block_size()); @@ -1900,7 +1903,7 @@ namespace libtorrent void peer_connection::set_upload_limit(int limit) { assert(limit >= -1); - if (limit == -1) limit = resource_request::inf; + if (limit == -1) limit = std::numeric_limits::max(); if (limit < 10) limit = 10; m_upload_limit = limit; m_bandwidth_limit[upload_channel].throttle(m_upload_limit); @@ -1909,7 +1912,7 @@ namespace libtorrent void peer_connection::set_download_limit(int limit) { assert(limit >= -1); - if (limit == -1) limit = resource_request::inf; + if (limit == -1) limit = std::numeric_limits::max(); if (limit < 10) limit = 10; m_download_limit = limit; m_bandwidth_limit[download_channel].throttle(m_download_limit); @@ -1996,7 +1999,7 @@ namespace libtorrent p.pieces = get_bitfield(); ptime now = time_now(); p.last_request = now - m_last_request; - p.last_active = now - std::max(m_last_sent, m_last_receive); + p.last_active = now - (std::max)(m_last_sent, m_last_receive); // this will set the flags so that we can update them later p.flags = 0; @@ -2044,10 +2047,13 @@ namespace libtorrent if (m_packet_size >= m_recv_pos) m_recv_buffer.resize(m_packet_size); } - void peer_connection::second_tick(float tick_interval) + void peer_connection::second_tick(float tick_interval) throw() { INVARIANT_CHECK; + try + { + ptime now(time_now()); boost::shared_ptr t = m_torrent.lock(); @@ -2160,14 +2166,14 @@ namespace libtorrent if (t->ratio() != 1.f) soon_downloaded = (size_type)(soon_downloaded*(double)t->ratio()); - double upload_speed_limit = std::min((soon_downloaded - have_uploaded + double upload_speed_limit = (std::min)((soon_downloaded - have_uploaded + bias) / break_even_time, double(m_upload_limit)); - upload_speed_limit = std::min(upload_speed_limit, + upload_speed_limit = (std::min)(upload_speed_limit, (double)std::numeric_limits::max()); m_bandwidth_limit[upload_channel].throttle( - std::min(std::max((int)upload_speed_limit, 20) + (std::min)((std::max)((int)upload_speed_limit, 20) , m_upload_limit)); } @@ -2186,43 +2192,14 @@ namespace libtorrent } fill_send_buffer(); -/* - 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()) - { - // 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::max(); } - else + catch (std::exception& e) { - 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(m_statistics.download_rate() * ratio) / 2; - if (bias < 10*1024) bias = 10*1024; - } - else - { - bias = -static_cast(m_statistics.download_rate() * ratio) / 2; - } - 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_ul_bandwidth_quota.wanted < 256) m_ul_bandwidth_quota.wanted = 256; +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << "**ERROR**: " << e.what() << "\n"; +#endif + m_ses.connection_failed(m_socket, remote(), e.what()); } -*/ } void peer_connection::fill_send_buffer() diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index e5d625dff..4f2e6211a 100755 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -189,7 +189,8 @@ namespace libtorrent // infinite loop, fighting to request the same blocks. void request_a_block(torrent& t, peer_connection& c) { - assert(!t.is_seed()); + if (t.is_seed()) return; + assert(t.valid_metadata()); assert(c.peer_info_struct() != 0 || !dynamic_cast(&c)); int num_requests = c.desired_queue_size() @@ -298,6 +299,7 @@ namespace libtorrent assert(p.num_peers(*i) == 1); assert(p.is_requested(*i)); num_requests--; + if (num_requests == 0) break; } if (busy_pieces.empty() || num_requests == 0) @@ -331,9 +333,8 @@ 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 +376,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 +458,7 @@ namespace libtorrent } return unchoke_peer; } - +*/ policy::iterator policy::find_disconnect_candidate() { INVARIANT_CHECK; @@ -542,7 +543,7 @@ namespace libtorrent return candidate; } - +/* policy::iterator policy::find_seed_choke_candidate() { INVARIANT_CHECK; @@ -648,7 +649,7 @@ namespace libtorrent --m_num_unchoked; } } - +*/ void policy::pulse() { INVARIANT_CHECK; @@ -680,7 +681,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,10 +693,9 @@ namespace libtorrent ++num_connected_peers; } - if (m_torrent->m_connections_quota.given != std::numeric_limits::max()) + if (m_torrent->max_connections() != std::numeric_limits::max()) { - - int max_connections = m_torrent->m_connections_quota.given; + int max_connections = m_torrent->max_connections(); if (num_connected_peers >= max_connections) { @@ -723,7 +723,7 @@ namespace libtorrent --num_connected_peers; } } - +*/ // ------------------------ // upload shift // ------------------------ @@ -754,7 +754,7 @@ namespace libtorrent , m_torrent->end() , m_available_free_upload); } - +/* // ------------------------ // seed choking policy // ------------------------ @@ -870,6 +870,7 @@ namespace libtorrent while (m_num_unchoked < m_torrent->m_uploads_quota.given && unchoke_one_peer()); } +*/ } int policy::count_choked() const @@ -902,7 +903,8 @@ namespace libtorrent // override at a time assert(c.remote() == c.get_socket()->remote_endpoint()); - if (m_torrent->num_peers() >= m_torrent->m_connections_quota.given + if (m_torrent->num_peers() >= m_torrent->max_connections() + && m_torrent->session().num_connections() >= m_torrent->session().max_connections() && c.remote().address() != m_torrent->current_tracker().address()) { throw protocol_error("too many connections, refusing incoming connection"); // cause a disconnect @@ -984,7 +986,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 @@ -1172,14 +1174,38 @@ 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_num_unchoked < m_torrent->m_uploads_quota.given + && m_torrent->session().num_uploads() < m_torrent->session().max_uploads() && (m_torrent->ratio() == 0 || c.share_diff() >= -free_upload_amount || m_torrent->is_seed())) { - c.send_unchoke(); - ++m_num_unchoked; + m_torrent->session().unchoke_peer(c); } +#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(m_torrent->session().num_uploads()) + + ") is more than or equal to the limit (" + + boost::lexical_cast(m_torrent->session().max_uploads()) + + ")"; + } + else + { + reason = "the share ratio (" + + boost::lexical_cast(c.share_diff()) + + ") is <= free_upload_amount (" + + boost::lexical_cast(int(free_upload_amount)) + + ") and we are not seeding and the ratio (" + + boost::lexical_cast(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 @@ -1211,7 +1237,7 @@ namespace libtorrent } */ } - +/* bool policy::unchoke_one_peer() { INVARIANT_CHECK; @@ -1240,7 +1266,7 @@ namespace libtorrent p->connection->send_choke(); --m_num_unchoked; } - +*/ bool policy::connect_one_peer() { INVARIANT_CHECK; @@ -1256,7 +1282,7 @@ namespace libtorrent try { - p->connected = m_last_optimistic_disconnect = time_now(); + p->connected = 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); @@ -1289,33 +1315,30 @@ namespace libtorrent } // this is called whenever a peer connection is closed - void policy::connection_closed(const peer_connection& c) try + void policy::connection_closed(const peer_connection& c) throw() { INVARIANT_CHECK; -// assert(c.is_disconnecting()); - bool unchoked = false; + peer* p = c.peer_info_struct(); + // if we couldn't find the connection in our list, just ignore it. + if (p == 0) return; - iterator i = std::find_if( + assert(std::find_if( m_peers.begin() , m_peers.end() - , match_peer_connection(c)); + , match_peer_connection(c)) + != m_peers.end()); + assert(p->connection == &c); - // if we couldn't find the connection in our list, just ignore it. - if (i == m_peers.end()) return; - assert(i->connection == &c); - i->connection = 0; + p->connection = 0; + p->optimistically_unchoked = false; - i->connected = time_now(); - if (!c.is_choked() && !m_torrent->is_aborted()) - { - unchoked = true; - } + p->connected = time_now(); if (c.failed()) { - ++i->failcount; -// i->connected = time_now(); + ++p->failcount; +// p->connected = time_now(); } // if the share ratio is 0 (infinite), the @@ -1327,25 +1350,8 @@ namespace libtorrent assert(c.share_diff() < std::numeric_limits::max()); m_available_free_upload += c.share_diff(); } - i->prev_amount_download += c.statistics().total_payload_download(); - i->prev_amount_upload += c.statistics().total_payload_upload(); - - 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(); - } - } - catch (std::exception& e) - { -#ifndef NDEBUG - std::string err = e.what(); -#endif - assert(false); + p->prev_amount_download += c.statistics().total_payload_download(); + p->prev_amount_upload += c.statistics().total_payload_upload(); } void policy::peer_is_interesting(peer_connection& c) @@ -1376,7 +1382,6 @@ 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; @@ -1405,10 +1410,7 @@ 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(); @@ -1475,6 +1477,7 @@ namespace libtorrent , failcount(0) , hashfails(0) , seed(false) + , optimistically_unchoked(false) , last_optimistically_unchoked(min_time()) , connected(min_time()) , trust_points(0) diff --git a/libtorrent/src/session.cpp b/libtorrent/src/session.cpp index 485c90d62..6d6fa55b2 100755 --- a/libtorrent/src/session.cpp +++ b/libtorrent/src/session.cpp @@ -68,7 +68,6 @@ 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" diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index 81f48a3ce..7a893e8fe 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -68,7 +68,6 @@ 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" @@ -223,6 +222,12 @@ 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( @@ -345,6 +350,12 @@ 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)) { @@ -505,8 +516,12 @@ 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(-1) - , m_max_connections(-1) + , 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_incoming_connection(false) , m_last_tick(time_now()) #ifndef TORRENT_DISABLE_DHT @@ -821,7 +836,10 @@ 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) @@ -901,7 +919,9 @@ 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()) + if (!m_torrents.empty() + && m_half_open.free_slots() + && num_connections() < m_max_connections) { // this is the maximum number of connections we will // attempt this tick @@ -918,11 +938,13 @@ 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; @@ -976,18 +998,7 @@ namespace detail continue; } - 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(); - } + c.keep_alive(); } // check each torrent for tracker updates @@ -1019,30 +1030,173 @@ namespace detail } m_stat.second_tick(tick_interval); - // distribute the maximum upload rate among the torrents - assert(m_max_uploads >= -1); - assert(m_max_connections >= -1); - - allocate_resources(m_max_uploads == -1 - ? std::numeric_limits::max() - : m_max_uploads - , m_torrents - , &torrent::m_uploads_quota); - - allocate_resources(m_max_connections == -1 - ? std::numeric_limits::max() - : m_max_connections - , m_torrents - , &torrent::m_connections_quota); - - for (std::map >::iterator i - = m_torrents.begin(); i != m_torrents.end(); ++i) + // -------------------------------------------------------------- + // unchoke set and optimistic unchoke calculations + // -------------------------------------------------------------- + m_unchoke_time_scaler--; + if (m_unchoke_time_scaler <= 0 && !m_connections.empty()) { -#ifndef NDEBUG - i->second->check_invariant(); -#endif - i->second->distribute_resources(tick_interval); + m_unchoke_time_scaler = settings().unchoke_interval; + + std::vector 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() + || t == 0 + || !p->is_peer_interested() + || p->is_disconnecting() + || p->is_connecting() + || (p->share_diff() < -free_upload_amount + && !t->is_seed())) + { + if (!i->second->is_choked() && t) + t->choke_peer(*i->second); + 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::iterator i = peers.begin() + , end(peers.end()); i != end; ++i) + { + peer_connection* p = *i; + assert(p); + torrent* t = p->associated_torrent().lock().get(); + assert(t); + if (unchoke_set_size > 0) + { + if (p->is_choked()) + { + if (t->unchoke_peer(*p)) + { + --unchoke_set_size; + ++m_num_unchoked; + } + } + else + { + --unchoke_set_size; + ++m_num_unchoked; + } + + assert(p->peer_info_struct()); + if (p->peer_info_struct()->optimistically_unchoked) + { + // force a new optimistic unchoke + m_optimistic_unchoke_time_scaler = 0; + p->peer_info_struct()->optimistically_unchoked = false; + } + } + else + { + if (!p->is_choked() && !p->peer_info_struct()->optimistically_unchoked) + t->choke_peer(*p); + } + } + + 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; + torrent* t = p->associated_torrent().lock().get(); + if (!t) 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() + && t->free_upload_slots() + && p->is_choked()) + { + last_unchoke = pi->last_optimistically_unchoked; + optimistic_unchoke_candidate = i; + } + } + + if (optimistic_unchoke_candidate != m_connections.end() + && optimistic_unchoke_candidate != current_optimistic_unchoke) + { + if (current_optimistic_unchoke != m_connections.end()) + { + torrent* t = current_optimistic_unchoke->second->associated_torrent().lock().get(); + assert(t); + t->choke_peer(*current_optimistic_unchoke->second); + current_optimistic_unchoke->second->peer_info_struct()->optimistically_unchoked = false; + } + + torrent* t = optimistic_unchoke_candidate->second->associated_torrent().lock().get(); + assert(t); + bool ret = t->unchoke_peer(*optimistic_unchoke_candidate->second); + assert(ret); + 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(); + } } } catch (std::exception& exc) @@ -1832,6 +1986,7 @@ namespace detail { assert(limit > 0 || limit == -1); mutex_t::scoped_lock l(m_mutex); + if (limit <= 0) limit = std::numeric_limits::max(); m_max_uploads = limit; } @@ -1839,6 +1994,7 @@ namespace detail { assert(limit > 0 || limit == -1); mutex_t::scoped_lock l(m_mutex); + if (limit <= 0) limit = std::numeric_limits::max(); m_max_connections = limit; } @@ -1846,7 +2002,7 @@ namespace detail { assert(limit > 0 || limit == -1); mutex_t::scoped_lock l(m_mutex); - + if (limit <= 0) limit = std::numeric_limits::max(); m_half_open.limit(limit); } @@ -1854,7 +2010,7 @@ namespace detail { assert(bytes_per_second > 0 || bytes_per_second == -1); mutex_t::scoped_lock l(m_mutex); - if (bytes_per_second == -1) bytes_per_second = bandwidth_limit::inf; + if (bytes_per_second <= 0) bytes_per_second = bandwidth_limit::inf; m_bandwidth_manager[peer_connection::download_channel]->throttle(bytes_per_second); } @@ -1862,28 +2018,10 @@ namespace detail { assert(bytes_per_second > 0 || bytes_per_second == -1); mutex_t::scoped_lock l(m_mutex); - if (bytes_per_second == -1) bytes_per_second = bandwidth_limit::inf; + if (bytes_per_second <= 0) bytes_per_second = bandwidth_limit::inf; 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 session_impl::pop_alert() { mutex_t::scoped_lock l(m_mutex); @@ -1977,18 +2115,28 @@ namespace detail #ifndef NDEBUG void session_impl::check_invariant(const char *place) { + assert(m_max_connections > 0); + assert(m_max_uploads > 0); 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 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 @@ -2101,7 +2249,7 @@ namespace detail const std::string& bitmask = (*i)["bitmask"].string(); - const int num_bitmask_bytes = std::max(num_blocks_per_piece / 8, 1); + const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1); if ((int)bitmask.size() != num_bitmask_bytes) { error = "invalid size of bitmask (" + boost::lexical_cast(bitmask.size()) + ")"; @@ -2110,7 +2258,7 @@ namespace detail for (int j = 0; j < num_bitmask_bytes; ++j) { unsigned char bits = bitmask[j]; - int num_bits = std::min(num_blocks_per_piece - j*8, 8); + int num_bits = (std::min)(num_blocks_per_piece - j*8, 8); for (int k = 0; k < num_bits; ++k) { const int bit = j * 8 + k; diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index b23a2e858..8d738c669 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -2096,7 +2096,7 @@ namespace libtorrent , offset += stack_buffer_size) { m_storage->write(zeroes, pos, offset - , std::min(piece_size, stack_buffer_size)); + , (std::min)(piece_size, stack_buffer_size)); } written = true; } diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index 13309c1e7..8b977f0a2 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -199,22 +199,16 @@ namespace libtorrent , m_connections_initialized(true) , m_settings(s) , m_storage_constructor(sc) + , m_max_uploads(std::numeric_limits::max()) + , m_num_uploads(0) + , m_max_connections(std::numeric_limits::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::max(); - m_connections_quota.max = std::numeric_limits::max(); m_policy.reset(new policy(this)); } - torrent::torrent( session_impl& ses , aux::checker_impl& checker @@ -268,6 +262,9 @@ namespace libtorrent , m_connections_initialized(false) , m_settings(s) , m_storage_constructor(sc) + , m_max_uploads(std::numeric_limits::max()) + , m_num_uploads(0) + , m_max_connections(std::numeric_limits::max()) { #ifndef NDEBUG m_initial_done = 0; @@ -277,13 +274,6 @@ 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::max(); - m_connections_quota.max = std::numeric_limits::max(); if (tracker_url) { m_trackers.push_back(announce_entry(tracker_url)); @@ -329,6 +319,14 @@ 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(); @@ -1020,6 +1018,15 @@ 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; @@ -1383,6 +1390,27 @@ namespace libtorrent return req; } + void torrent::choke_peer(peer_connection& c) + { + INVARIANT_CHECK; + + assert(!c.is_choked()); + assert(m_num_uploads > 0); + c.send_choke(); + --m_num_uploads; + } + + bool torrent::unchoke_peer(peer_connection& c) + { + INVARIANT_CHECK; + + assert(c.is_choked()); + if (m_num_uploads >= m_max_uploads) return false; + c.send_unchoke(); + ++m_num_uploads; + return true; + } + void torrent::cancel_block(piece_block block) { for (peer_iterator i = m_connections.begin() @@ -1394,7 +1422,7 @@ namespace libtorrent void torrent::remove_peer(peer_connection* p) try { - INVARIANT_CHECK; +// INVARIANT_CHECK; assert(p != 0); @@ -1433,6 +1461,9 @@ namespace libtorrent } } + if (!p->is_choked()) + --m_num_uploads; + m_policy->connection_closed(*p); p->set_peer_info(0); m_connections.erase(i); @@ -1890,7 +1921,7 @@ namespace libtorrent void torrent::attach_peer(peer_connection* p) { - INVARIANT_CHECK; +// INVARIANT_CHECK; assert(p != 0); assert(!p->is_local()); @@ -1955,7 +1986,7 @@ namespace libtorrent bool torrent::want_more_peers() const { - return int(m_connections.size()) < m_connections_quota.given + return int(m_connections.size()) < m_max_connections && m_ses.m_half_open.free_slots() && !m_paused; } @@ -2122,7 +2153,7 @@ namespace libtorrent if ((unsigned)m_currently_trying_tracker >= m_trackers.size()) { int delay = tracker_retry_delay_min - + std::min(m_failed_trackers, (int)tracker_failed_max) + + (std::min)(m_failed_trackers, (int)tracker_failed_max) * (tracker_retry_delay_max - tracker_retry_delay_min) / tracker_failed_max; @@ -2354,6 +2385,7 @@ namespace libtorrent // size_type download = m_stat.total_payload_download(); // size_type done = boost::get<0>(bytes_done()); // assert(download >= done - m_initial_done); + int num_uploads = 0; std::map num_requests; for (const_peer_iterator i = begin(); i != end(); ++i) { @@ -2364,10 +2396,12 @@ namespace libtorrent for (std::deque::const_iterator i = p.download_queue().begin() , end(p.download_queue().end()); i != end; ++i) ++num_requests[*i]; + if (!p.is_choked()) ++num_uploads; torrent* associated_torrent = p.associated_torrent().lock().get(); if (associated_torrent != this) assert(false); } + assert(num_uploads == m_num_uploads); if (has_picker()) { @@ -2425,15 +2459,15 @@ namespace libtorrent void torrent::set_max_uploads(int limit) { assert(limit >= -1); - if (limit == -1) limit = std::numeric_limits::max(); - m_uploads_quota.max = std::max(m_uploads_quota.min, limit); + if (limit <= 0) limit = std::numeric_limits::max(); + m_max_uploads = limit; } void torrent::set_max_connections(int limit) { assert(limit >= -1); - if (limit == -1) limit = std::numeric_limits::max(); - m_connections_quota.max = std::max(m_connections_quota.min, limit); + if (limit <= 0) limit = std::numeric_limits::max(); + m_max_connections = limit; } void torrent::set_peer_upload_limit(tcp::endpoint ip, int limit) @@ -2455,7 +2489,7 @@ namespace libtorrent void torrent::set_upload_limit(int limit) { assert(limit >= -1); - if (limit == -1) limit = std::numeric_limits::max(); + if (limit <= 0) limit = std::numeric_limits::max(); if (limit < num_peers() * 10) limit = num_peers() * 10; m_bandwidth_limit[peer_connection::upload_channel].throttle(limit); } @@ -2470,7 +2504,7 @@ namespace libtorrent void torrent::set_download_limit(int limit) { assert(limit >= -1); - if (limit == -1) limit = std::numeric_limits::max(); + if (limit <= 0) limit = std::numeric_limits::max(); if (limit < num_peers() * 10) limit = num_peers() * 10; m_bandwidth_limit[peer_connection::download_channel].throttle(limit); } @@ -2496,6 +2530,14 @@ 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 @@ -2528,10 +2570,6 @@ namespace libtorrent #endif m_paused = false; - m_uploads_quota.min = 0; - m_connections_quota.min = 2; - m_uploads_quota.max = std::numeric_limits::max(); - m_connections_quota.max = std::numeric_limits::max(); // tell the tracker that we're back m_event = tracker_request::started; @@ -2545,10 +2583,6 @@ 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) @@ -2561,10 +2595,6 @@ 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,6 +2653,13 @@ 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() @@ -2631,18 +2668,6 @@ 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 const& f) { INVARIANT_CHECK; @@ -2696,7 +2721,7 @@ namespace libtorrent size_type done = 0; while (size > 0) { - size_type bytes_step = std::min(m_torrent_file.piece_size(ret.piece) + size_type bytes_step = (std::min)(m_torrent_file.piece_size(ret.piece) - ret.start, size); if (m_have_pieces[ret.piece]) done += bytes_step; ++ret.piece; @@ -2764,10 +2789,10 @@ namespace libtorrent = m_trackers[m_last_working_tracker].url; } - 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; + st.num_uploads = m_num_uploads; + st.uploads_limit = m_max_uploads; + st.num_connections = int(m_connections.size()); + st.connections_limit = m_max_connections; // if we don't have any metadata, stop here if (!valid_metadata()) @@ -2780,7 +2805,7 @@ namespace libtorrent // TODO: add a progress member to the torrent that will be used in this case // and that may be set by a plugin // if (m_metadata_size == 0) st.progress = 0.f; -// else st.progress = std::min(1.f, m_metadata_progress / (float)m_metadata_size); +// else st.progress = (std::min)(1.f, m_metadata_progress / (float)m_metadata_size); st.progress = 0.f; st.block_size = 0; diff --git a/libtorrent/src/torrent_handle.cpp b/libtorrent/src/torrent_handle.cpp index 4538e66e8..9dc1e6d26 100755 --- a/libtorrent/src/torrent_handle.cpp +++ b/libtorrent/src/torrent_handle.cpp @@ -453,14 +453,30 @@ namespace libtorrent , m_chk, m_info_hash, bind(&torrent::trackers, _1)); } - void torrent_handle::add_url_seed(std::string const& url) + void torrent_handle::add_url_seed(std::string const& url) const { INVARIANT_CHECK; - return call_member(m_ses, m_chk, m_info_hash + call_member(m_ses, m_chk, m_info_hash , bind(&torrent::add_url_seed, _1, url)); } + void torrent_handle::remove_url_seed(std::string const& url) const + { + INVARIANT_CHECK; + + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::remove_url_seed, _1, url)); + } + + std::set torrent_handle::url_seeds() const + { + INVARIANT_CHECK; + + return call_member >(m_ses, m_chk, m_info_hash + , bind(&torrent::url_seeds, _1)); + } + void torrent_handle::replace_trackers( std::vector const& urls) const { @@ -561,12 +577,12 @@ namespace libtorrent std::string bitmask; const int num_bitmask_bytes - = std::max(num_blocks_per_piece / 8, 1); + = (std::max)(num_blocks_per_piece / 8, 1); for (int j = 0; j < num_bitmask_bytes; ++j) { unsigned char v = 0; - int bits = std::min(num_blocks_per_piece - j*8, 8); + int bits = (std::min)(num_blocks_per_piece - j*8, 8); for (int k = 0; k < bits; ++k) v |= (i->info[j*8+k].state == piece_picker::block_info::state_finished) ? (1 << k) : 0; diff --git a/libtorrent/src/tracker_manager.cpp b/libtorrent/src/tracker_manager.cpp index 7bd511588..358ac3838 100755 --- a/libtorrent/src/tracker_manager.cpp +++ b/libtorrent/src/tracker_manager.cpp @@ -256,7 +256,7 @@ namespace libtorrent { // available input is 1,2 or 3 bytes // since we read 3 bytes at a time at most - int available_input = std::min(3, (int)std::distance(i, s.end())); + int available_input = (std::min)(3, (int)std::distance(i, s.end())); // clear input buffer std::fill(inbuf, inbuf+3, 0); @@ -305,7 +305,7 @@ namespace libtorrent m_start_time = time_now(); m_read_time = time_now(); - m_timeout.expires_at(std::min( + m_timeout.expires_at((std::min)( m_read_time + seconds(m_read_timeout) , m_start_time + seconds(m_completion_timeout))); m_timeout.async_wait(m_strand.wrap(bind( @@ -341,7 +341,7 @@ namespace libtorrent return; } - m_timeout.expires_at(std::min( + m_timeout.expires_at((std::min)( m_read_time + seconds(m_read_timeout) , m_start_time + seconds(m_completion_timeout))); m_timeout.async_wait(m_strand.wrap( diff --git a/libtorrent/src/web_peer_connection.cpp b/libtorrent/src/web_peer_connection.cpp index 6c6745f30..efd9633e7 100755 --- a/libtorrent/src/web_peer_connection.cpp +++ b/libtorrent/src/web_peer_connection.cpp @@ -180,7 +180,7 @@ namespace libtorrent const int block_size = t->block_size(); while (size > 0) { - int request_size = std::min(block_size, size); + int request_size = (std::min)(block_size, size); peer_request pr = {r.piece, r.start + r.length - size , request_size}; m_requests.push_back(pr); @@ -510,7 +510,7 @@ namespace libtorrent // m_piece as buffer. int piece_size = int(m_piece.size()); - int copy_size = std::min(std::min(front_request.length - piece_size + int copy_size = (std::min)(std::min(front_request.length - piece_size , recv_buffer.left()), int(range_end - range_start - m_received_body)); m_piece.resize(piece_size + copy_size); assert(copy_size > 0); @@ -568,7 +568,7 @@ namespace libtorrent && (m_received_body + recv_buffer.left() >= range_end - range_start)) { int piece_size = int(m_piece.size()); - int copy_size = std::min(std::min(m_requests.front().length - piece_size + int copy_size = (std::min)(std::min(m_requests.front().length - piece_size , recv_buffer.left()), int(range_end - range_start - m_received_body)); assert(copy_size >= 0); if (copy_size > 0)