00001 /* 00002 00003 Copyright (c) 2007, Arvid Norberg 00004 All rights reserved. 00005 00006 Redistribution and use in source and binary forms, with or without 00007 modification, are permitted provided that the following conditions 00008 are met: 00009 00010 * Redistributions of source code must retain the above copyright 00011 notice, this list of conditions and the following disclaimer. 00012 * Redistributions in binary form must reproduce the above copyright 00013 notice, this list of conditions and the following disclaimer in 00014 the documentation and/or other materials provided with the distribution. 00015 * Neither the name of the author nor the names of its 00016 contributors may be used to endorse or promote products derived 00017 from this software without specific prior written permission. 00018 00019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00020 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00021 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00022 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00023 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00024 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00025 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00026 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00027 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00028 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00029 POSSIBILITY OF SUCH DAMAGE. 00030 00031 */ 00032 00033 #ifndef TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED 00034 #define TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED 00035 00036 #include "libtorrent/socket.hpp" 00037 #include <boost/shared_ptr.hpp> 00038 #include <boost/intrusive_ptr.hpp> 00039 #include <boost/function.hpp> 00040 #include <boost/bind.hpp> 00041 #include <boost/integer_traits.hpp> 00042 #include <boost/thread/mutex.hpp> 00043 #include <deque> 00044 00045 namespace pt = boost::posix_time; 00046 using boost::weak_ptr; 00047 using boost::shared_ptr; 00048 using boost::intrusive_ptr; 00049 using boost::bind; 00050 00051 namespace libtorrent 00052 { 00053 00054 class peer_connection; 00055 class torrent; 00056 00057 // the maximum block of bandwidth quota to 00058 // hand out is 33kB. The block size may 00059 // be smaller on lower limits 00060 const int max_bandwidth_block_size = 33000; 00061 const int min_bandwidth_block_size = 4000; 00062 00063 #if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING 00064 namespace aux 00065 { 00066 struct session_impl; 00067 } 00068 #endif 00069 00070 struct history_entry 00071 { 00072 history_entry(intrusive_ptr<peer_connection> p, weak_ptr<torrent> t 00073 , int a, pt::ptime exp); 00074 pt::ptime expires_at; 00075 int amount; 00076 intrusive_ptr<peer_connection> peer; 00077 weak_ptr<torrent> tor; 00078 }; 00079 00080 struct bw_queue_entry 00081 { 00082 bw_queue_entry(boost::intrusive_ptr<peer_connection> const& pe, bool no_prio); 00083 boost::intrusive_ptr<peer_connection> peer; 00084 bool non_prioritized; 00085 }; 00086 00087 // member of peer_connection 00088 struct bandwidth_limit 00089 { 00090 static const int inf = boost::integer_traits<int>::const_max; 00091 00092 bandwidth_limit() 00093 : m_quota_left(0) 00094 , m_local_limit(inf) 00095 , m_current_rate(0) 00096 {} 00097 00098 void throttle(int limit) 00099 { 00100 m_local_limit = limit; 00101 } 00102 00103 int throttle() const 00104 { 00105 return m_local_limit; 00106 } 00107 00108 void assign(int amount) 00109 { 00110 assert(amount > 0); 00111 m_current_rate += amount; 00112 m_quota_left += amount; 00113 } 00114 00115 void use_quota(int amount) 00116 { 00117 assert(amount <= m_quota_left); 00118 m_quota_left -= amount; 00119 } 00120 00121 int quota_left() const 00122 { 00123 return (std::max)(m_quota_left, 0); 00124 } 00125 00126 void expire(int amount) 00127 { 00128 assert(amount >= 0); 00129 m_current_rate -= amount; 00130 } 00131 00132 int max_assignable() const 00133 { 00134 if (m_local_limit == inf) return inf; 00135 if (m_local_limit <= m_current_rate) return 0; 00136 return m_local_limit - m_current_rate; 00137 } 00138 00139 private: 00140 00141 // this is the amount of bandwidth we have 00142 // been assigned without using yet. i.e. 00143 // the bandwidth that we use up every time 00144 // we receive or send a message. Once this 00145 // hits zero, we need to request more 00146 // bandwidth from the torrent which 00147 // in turn will request bandwidth from 00148 // the bandwidth manager 00149 int m_quota_left; 00150 00151 // the local limit is the number of bytes 00152 // per window size we are allowed to use. 00153 int m_local_limit; 00154 00155 // the current rate is the number of 00156 // bytes we have been assigned within 00157 // the window size. 00158 int m_current_rate; 00159 }; 00160 00161 struct bandwidth_manager 00162 { 00163 bandwidth_manager(io_service& ios, int channel); 00164 00165 void throttle(int limit) 00166 { 00167 mutex_t::scoped_lock l(m_mutex); 00168 assert(limit >= 0); 00169 m_limit = limit; 00170 } 00171 00172 int throttle() const 00173 { 00174 mutex_t::scoped_lock l(m_mutex); 00175 return m_limit; 00176 } 00177 00178 // non prioritized means that, if there's a line for bandwidth, 00179 // others will cut in front of the non-prioritized peers. 00180 // this is used by web seeds 00181 void request_bandwidth(intrusive_ptr<peer_connection> peer 00182 , bool non_prioritized); 00183 00184 #ifndef NDEBUG 00185 void check_invariant() const; 00186 #endif 00187 #if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING 00188 aux::session_impl* m_ses; 00189 #endif 00190 00191 private: 00192 00193 void add_history_entry(history_entry const& e); 00194 void on_history_expire(asio::error_code const& e); 00195 void hand_out_bandwidth(); 00196 00197 typedef boost::mutex mutex_t; 00198 mutable mutex_t m_mutex; 00199 00200 // the io_service used for the timer 00201 io_service& m_ios; 00202 00203 // the timer that is waiting for the entries 00204 // in the history queue to expire (slide out 00205 // of the history window) 00206 deadline_timer m_history_timer; 00207 00208 // the rate limit (bytes per second) 00209 int m_limit; 00210 00211 // the sum of all recently handed out bandwidth blocks 00212 int m_current_quota; 00213 00214 // these are the consumers that want bandwidth 00215 std::deque<bw_queue_entry> m_queue; 00216 00217 // these are the consumers that have received bandwidth 00218 // that will expire 00219 std::deque<history_entry> m_history; 00220 00221 // this is the channel within the consumers 00222 // that bandwidth is assigned to (upload or download) 00223 int m_channel; 00224 }; 00225 00226 } 00227 00228 #endif
1.5.6