1 // libTorrent - BitTorrent library
2 // Copyright (C) 2005-2011, Jari Sundell
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 //
18 // In addition, as a special exception, the copyright holders give
19 // permission to link the code of portions of this program with the
20 // OpenSSL library under certain conditions as described in each
21 // individual source file, and distribute linked combinations
22 // including the two.
23 //
24 // You must obey the GNU General Public License in all respects for
25 // all of the code used other than OpenSSL.  If you modify file(s)
26 // with this exception, you may extend this exception to your version
27 // of the file(s), but you are not obligated to do so.  If you do not
28 // wish to do so, delete this exception statement from your version.
29 // If you delete this exception statement from all source files in the
30 // program, then also delete it here.
31 //
32 // Contact:  Jari Sundell <jaris@ifi.uio.no>
33 //
34 //           Skomakerveien 33
35 //           3185 Skoppum, NORWAY
36 
37 #include "config.h"
38 
39 #include <rak/timer.h>
40 
41 #include "net/throttle_internal.h"
42 #include "net/throttle_list.h"
43 
44 #include "globals.h"
45 
46 #include "exceptions.h"
47 #include "throttle.h"
48 
49 namespace torrent {
50 
51 // Plans:
52 //
53 // Make ThrottleList do a callback when it needs more? This would
54 // allow us to remove us from the task scheduler when we're full. Also
55 // this would let us be abit more flexible with the interval.
56 
57 Throttle*
create_throttle()58 Throttle::create_throttle() {
59   ThrottleInternal* throttle = new ThrottleInternal(ThrottleInternal::flag_root);
60 
61   throttle->m_maxRate = 0;
62   throttle->m_throttleList = new ThrottleList();
63 
64   return throttle;
65 }
66 
67 void
destroy_throttle(Throttle * throttle)68 Throttle::destroy_throttle(Throttle* throttle) {
69   delete throttle->m_ptr()->m_throttleList;
70   delete throttle->m_ptr();
71 }
72 
73 Throttle*
create_slave()74 Throttle::create_slave() {
75   return m_ptr()->create_slave();
76 }
77 
78 bool
is_throttled()79 Throttle::is_throttled() {
80   return m_maxRate != 0 && m_maxRate != std::numeric_limits<uint32_t>::max();
81 }
82 
83 void
set_max_rate(uint32_t v)84 Throttle::set_max_rate(uint32_t v) {
85   if (v == m_maxRate)
86     return;
87 
88   if (v > (1 << 30))
89     throw input_error("Throttle rate must be between 0 and 2^30.");
90 
91   uint32_t oldRate = m_maxRate;
92   m_maxRate = v;
93 
94   m_throttleList->set_min_chunk_size(calculate_min_chunk_size());
95   m_throttleList->set_max_chunk_size(calculate_max_chunk_size());
96 
97   if (!m_ptr()->is_root())
98     return;
99 
100   if (oldRate == 0)
101     m_ptr()->enable();
102   else if (m_maxRate == 0)
103     m_ptr()->disable();
104 }
105 
106 const Rate*
rate() const107 Throttle::rate() const {
108   return m_throttleList->rate_slow();
109 }
110 
111 uint32_t
calculate_min_chunk_size() const112 Throttle::calculate_min_chunk_size() const {
113   // Just for each modification, make this into a function, rather
114   // than if-else chain.
115   if (m_maxRate <= (8 << 10))
116     return (1 << 9);
117 
118   else if (m_maxRate <= (32 << 10))
119     return (2 << 9);
120 
121   else if (m_maxRate <= (64 << 10))
122     return (3 << 9);
123 
124   else if (m_maxRate <= (128 << 10))
125     return (4 << 9);
126 
127   else if (m_maxRate <= (512 << 10))
128     return (8 << 9);
129 
130   else if (m_maxRate <= (2048 << 10))
131     return (16 << 9);
132 
133   else
134     return (32 << 9);
135 }
136 
137 uint32_t
calculate_max_chunk_size() const138 Throttle::calculate_max_chunk_size() const {
139   // Make this return a lower value for very low throttle settings.
140   return calculate_min_chunk_size() * 4;
141 }
142 
143 uint32_t
calculate_interval() const144 Throttle::calculate_interval() const {
145   uint32_t rate = m_throttleList->rate_slow()->rate();
146 
147   if (rate < 1024)
148     return 10 * 100000;
149 
150   // At least two max chunks per tick.
151   uint32_t interval = (5 * m_throttleList->max_chunk_size()) / rate;
152 
153   if (interval == 0)
154     return 1 * 100000;
155   else if (interval > 10)
156     return 10 * 100000;
157   else
158     return interval * 100000;
159 }
160 
161 }
162