1 /* 2 3 Copyright (c) 2003-2018, Arvid Norberg 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions 8 are met: 9 10 * Redistributions of source code must retain the above copyright 11 notice, this list of conditions and the following disclaimer. 12 * Redistributions in binary form must reproduce the above copyright 13 notice, this list of conditions and the following disclaimer in 14 the documentation and/or other materials provided with the distribution. 15 * Neither the name of the author nor the names of its 16 contributors may be used to endorse or promote products derived 17 from this software without specific prior written permission. 18 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 POSSIBILITY OF SUCH DAMAGE. 30 31 */ 32 33 #ifndef TORRENT_STAT_HPP_INCLUDED 34 #define TORRENT_STAT_HPP_INCLUDED 35 36 #include <algorithm> 37 #include <limits> 38 #include <cstdint> 39 40 #include "libtorrent/config.hpp" 41 #include "libtorrent/assert.hpp" 42 43 namespace libtorrent { 44 45 class TORRENT_EXTRA_EXPORT stat_channel 46 { 47 public: 48 stat_channel()49 stat_channel() 50 : m_total_counter(0) 51 , m_counter(0) 52 , m_5_sec_average(0) 53 {} 54 operator +=(stat_channel const & s)55 void operator+=(stat_channel const& s) 56 { 57 TORRENT_ASSERT(m_counter < (std::numeric_limits<std::int32_t>::max)() - s.m_counter); 58 m_counter += s.m_counter; 59 TORRENT_ASSERT(m_total_counter < (std::numeric_limits<std::int64_t>::max)() - s.m_counter); 60 m_total_counter += s.m_counter; 61 } 62 add(int count)63 void add(int count) 64 { 65 TORRENT_ASSERT(count >= 0); 66 67 TORRENT_ASSERT(m_counter < (std::numeric_limits<std::int32_t>::max)() - count); 68 m_counter += count; 69 TORRENT_ASSERT(m_total_counter < (std::numeric_limits<std::int64_t>::max)() - count); 70 m_total_counter += count; 71 } 72 73 // should be called once every second 74 void second_tick(int tick_interval_ms); rate() const75 std::int32_t rate() const { return m_5_sec_average; } low_pass_rate() const76 std::int32_t low_pass_rate() const { return m_5_sec_average; } 77 total() const78 std::int64_t total() const { return m_total_counter; } 79 offset(std::int64_t c)80 void offset(std::int64_t c) 81 { 82 TORRENT_ASSERT(m_total_counter < (std::numeric_limits<std::int64_t>::max)() - c); 83 m_total_counter += c; 84 } 85 counter() const86 std::int32_t counter() const { return m_counter; } 87 clear()88 void clear() 89 { 90 m_counter = 0; 91 m_5_sec_average = 0; 92 m_total_counter = 0; 93 } 94 95 private: 96 97 // total counters 98 std::int64_t m_total_counter; 99 100 // the accumulator for this second. 101 std::int32_t m_counter; 102 103 // sliding average 104 std::int32_t m_5_sec_average; 105 }; 106 107 class TORRENT_EXTRA_EXPORT stat 108 { 109 public: operator +=(const stat & s)110 void operator+=(const stat& s) 111 { 112 for (int i = 0; i < num_channels; ++i) 113 m_stat[i] += s.m_stat[i]; 114 } 115 sent_syn(bool ipv6)116 void sent_syn(bool ipv6) 117 { 118 m_stat[upload_ip_protocol].add(ipv6 ? 60 : 40); 119 } 120 received_synack(bool ipv6)121 void received_synack(bool ipv6) 122 { 123 // we received SYN-ACK and also sent ACK back 124 m_stat[download_ip_protocol].add(ipv6 ? 60 : 40); 125 m_stat[upload_ip_protocol].add(ipv6 ? 60 : 40); 126 } 127 received_bytes(int bytes_payload,int bytes_protocol)128 void received_bytes(int bytes_payload, int bytes_protocol) 129 { 130 TORRENT_ASSERT(bytes_payload >= 0); 131 TORRENT_ASSERT(bytes_protocol >= 0); 132 133 m_stat[download_payload].add(bytes_payload); 134 m_stat[download_protocol].add(bytes_protocol); 135 } 136 sent_bytes(int bytes_payload,int bytes_protocol)137 void sent_bytes(int bytes_payload, int bytes_protocol) 138 { 139 TORRENT_ASSERT(bytes_payload >= 0); 140 TORRENT_ASSERT(bytes_protocol >= 0); 141 142 m_stat[upload_payload].add(bytes_payload); 143 m_stat[upload_protocol].add(bytes_protocol); 144 } 145 146 // and IP packet was received or sent 147 // account for the overhead caused by it trancieve_ip_packet(int bytes_transferred,bool ipv6)148 void trancieve_ip_packet(int bytes_transferred, bool ipv6) 149 { 150 // one TCP/IP packet header for the packet 151 // sent or received, and one for the ACK 152 // The IPv4 header is 20 bytes 153 // and IPv6 header is 40 bytes 154 const int header = (ipv6 ? 40 : 20) + 20; 155 const int mtu = 1500; 156 const int packet_size = mtu - header; 157 const int overhead = (std::max)(1, (bytes_transferred + packet_size - 1) / packet_size) * header; 158 m_stat[download_ip_protocol].add(overhead); 159 m_stat[upload_ip_protocol].add(overhead); 160 } 161 upload_ip_overhead() const162 int upload_ip_overhead() const { return m_stat[upload_ip_protocol].counter(); } download_ip_overhead() const163 int download_ip_overhead() const { return m_stat[download_ip_protocol].counter(); } 164 165 // should be called once every second second_tick(int tick_interval_ms)166 void second_tick(int tick_interval_ms) 167 { 168 for (int i = 0; i < num_channels; ++i) 169 m_stat[i].second_tick(tick_interval_ms); 170 } 171 low_pass_upload_rate() const172 int low_pass_upload_rate() const 173 { 174 return m_stat[upload_payload].low_pass_rate() 175 + m_stat[upload_protocol].low_pass_rate() 176 + m_stat[upload_ip_protocol].low_pass_rate(); 177 } 178 low_pass_download_rate() const179 int low_pass_download_rate() const 180 { 181 return m_stat[download_payload].low_pass_rate() 182 + m_stat[download_protocol].low_pass_rate() 183 + m_stat[download_ip_protocol].low_pass_rate(); 184 } 185 upload_rate() const186 int upload_rate() const 187 { 188 return m_stat[upload_payload].rate() 189 + m_stat[upload_protocol].rate() 190 + m_stat[upload_ip_protocol].rate(); 191 } 192 download_rate() const193 int download_rate() const 194 { 195 return m_stat[download_payload].rate() 196 + m_stat[download_protocol].rate() 197 + m_stat[download_ip_protocol].rate(); 198 } 199 total_upload() const200 std::int64_t total_upload() const 201 { 202 return m_stat[upload_payload].total() 203 + m_stat[upload_protocol].total() 204 + m_stat[upload_ip_protocol].total(); 205 } 206 total_download() const207 std::int64_t total_download() const 208 { 209 return m_stat[download_payload].total() 210 + m_stat[download_protocol].total() 211 + m_stat[download_ip_protocol].total(); 212 } 213 upload_payload_rate() const214 int upload_payload_rate() const 215 { return m_stat[upload_payload].rate(); } download_payload_rate() const216 int download_payload_rate() const 217 { return m_stat[download_payload].rate(); } 218 total_payload_upload() const219 std::int64_t total_payload_upload() const 220 { return m_stat[upload_payload].total(); } total_payload_download() const221 std::int64_t total_payload_download() const 222 { return m_stat[download_payload].total(); } 223 total_protocol_upload() const224 std::int64_t total_protocol_upload() const 225 { return m_stat[upload_protocol].total(); } total_protocol_download() const226 std::int64_t total_protocol_download() const 227 { return m_stat[download_protocol].total(); } 228 total_transfer(int channel) const229 std::int64_t total_transfer(int channel) const 230 { return m_stat[channel].total(); } transfer_rate(int channel) const231 int transfer_rate(int channel) const 232 { return m_stat[channel].rate(); } 233 234 // this is used to offset the statistics when a 235 // peer_connection is opened and have some previous 236 // transfers from earlier connections. add_stat(std::int64_t downloaded,std::int64_t uploaded)237 void add_stat(std::int64_t downloaded, std::int64_t uploaded) 238 { 239 m_stat[download_payload].offset(downloaded); 240 m_stat[upload_payload].offset(uploaded); 241 } 242 last_payload_downloaded() const243 int last_payload_downloaded() const 244 { return m_stat[download_payload].counter(); } last_payload_uploaded() const245 int last_payload_uploaded() const 246 { return m_stat[upload_payload].counter(); } last_protocol_downloaded() const247 int last_protocol_downloaded() const 248 { return m_stat[download_protocol].counter(); } last_protocol_uploaded() const249 int last_protocol_uploaded() const 250 { return m_stat[upload_protocol].counter(); } 251 252 // these are the channels we keep stats for 253 enum 254 { 255 // TODO: 3 everything but payload counters and rates could probably be 256 // removed from here 257 upload_payload, 258 upload_protocol, 259 download_payload, 260 download_protocol, 261 upload_ip_protocol, 262 download_ip_protocol, 263 num_channels 264 }; 265 clear()266 void clear() 267 { 268 for (int i = 0; i < num_channels; ++i) 269 m_stat[i].clear(); 270 } 271 operator [](int i) const272 stat_channel const& operator[](int i) const 273 { 274 TORRENT_ASSERT(i >= 0 && i < num_channels); 275 return m_stat[i]; 276 } 277 278 private: 279 280 stat_channel m_stat[num_channels]; 281 }; 282 283 } 284 285 #endif // TORRENT_STAT_HPP_INCLUDED 286