Bug Summary

File:rootdir/src/Statistics.cpp
Warning:line 434, column 6
This statement is never executed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Statistics.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/src -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -D USE_WX_EXTENSIONS -I /usr/include/upnp -D ENABLE_UPNP=1 -I /usr/lib/x86_64-linux-gnu/wx/include/gtk3-unicode-3.2 -I /usr/include/wx-3.2 -D _FILE_OFFSET_BITS=64 -D WXUSINGDLL -D __WXGTK__ -D ENABLE_IP2COUNTRY=1 -I ./libs -I libs -I ./include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-register -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-01-05-184004-17430-1 -x c++ Statistics.cpp
1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5// Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6// Copyright (c) 2005-2011 Dévai Tamás ( gonosztopi@amule.org )
7//
8// Any parts of this program derived from the xMule, lMule or eMule project,
9// or contributed by third-party developers are copyrighted by their
10// respective authors.
11//
12// This program is free software; you can redistribute it and/or modify
13// it under the terms of the GNU General Public License as published by
14// the Free Software Foundation; either version 2 of the License, or
15// (at your option) any later version.
16//
17// This program is distributed in the hope that it will be useful,
18// but WITHOUT ANY WARRANTY; without even the implied warranty of
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20// GNU General Public License for more details.
21//
22// You should have received a copy of the GNU General Public License
23// along with this program; if not, write to the Free Software
24// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25//
26
27#include "Statistics.h" // Interface declarations
28
29#include <protocol/ed2k/ClientSoftware.h>
30
31#include <ec/cpp/ECTag.h> // Needed for CECTag
32
33#ifndef CLIENT_GUI
34 #ifndef AMULE_DAEMON
35 #include <common/Format.h> // Needed for CFormat
36 #endif
37 #include "CFile.h" // Needed for CFile access
38 #include <common/Path.h> // Needed for JoinPaths
39 #include <wx/config.h> // Needed for wxConfig
40 #include "DataToText.h" // Needed for GetSoftName()
41 #include "ListenSocket.h" // (tree, GetAverageConnections)
42 #include "ServerList.h" // Needed for CServerList (tree)
43 #include <cmath> // Needed for std::floor
44 #include "updownclient.h" // Needed for CUpDownClient
45#else
46 #include "GetTickCount.h" // Needed for GetTickCount64()
47 #include <ec/cpp/RemoteConnect.h> // Needed for CRemoteConnect
48#endif
49
50#include "amule.h" // Needed for theApp
51#include <wx/intl.h>
52#include "Logger.h"
53#include "Preferences.h" // Needed for thePrefs
54
55#ifdef __BSD__
56 // glibc -> bsd libc
57 #define round rint
58#else
59 #define round(x)floor(x+0.5) floor(x+0.5)
60#endif /* __BSD__ */
61
62
63#ifndef CLIENT_GUI
64
65/*----- CPreciseRateCounter -----*/
66
67void CPreciseRateCounter::CalculateRate(uint64_t now)
68{
69 wxMutexLocker lock(m_mutex);
70
71 m_total += m_tmp_sum;
72 m_byte_history.push_back(m_tmp_sum);
73 m_tick_history.push_back(now);
74 m_tmp_sum = 0;
75
76 uint64_t timespan = now - m_tick_history.front();
77
78 // Checking maximal timespan, but make sure not to remove
79 // the extra node in m_tick_history.
80 while (timespan > m_timespan && !m_byte_history.empty()) {
81 m_total -= m_byte_history.front();
82 m_byte_history.pop_front();
83 m_tick_history.pop_front();
84 timespan = now - m_tick_history.front();
85 }
86
87 // Count rate/average
88 if (m_count_average) {
89 if (!m_byte_history.empty()) {
90 m_rate = m_total / (double)m_byte_history.size();
91 }
92 } else {
93 if (timespan > 0) {
94 m_rate = m_total / (timespan / 1000.0);
95 }
96 }
97
98 if (m_rate > m_max_rate) {
99 m_max_rate = m_rate;
100 }
101}
102
103
104/*----- CStatTreeItemRateCounter -----*/
105
106#ifndef AMULE_DAEMON
107wxString CStatTreeItemRateCounter::GetDisplayString() const
108{
109 return CFormat(wxGetTranslation(m_label)) % CastItoSpeed(m_show_maxrate ? (uint32)m_max_rate : (uint32)m_rate);
110}
111#endif
112
113void CStatTreeItemRateCounter::AddECValues(CECTag* tag) const
114{
115 CECTag value(EC_TAG_STAT_NODE_VALUE, m_show_maxrate ? (uint32)m_max_rate : (uint32)m_rate);
116 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_SPEED));
117 tag->AddTag(value);
118}
119
120
121/*----- CStatTreeItemPeakConnections -----*/
122
123#ifndef AMULE_DAEMON
124wxString CStatTreeItemPeakConnections::GetDisplayString() const
125{
126 return CFormat(wxGetTranslation(m_label)) % theStats::GetPeakConnections();
127}
128#endif
129
130void CStatTreeItemPeakConnections::AddECValues(CECTag* tag) const
131{
132 tag->AddTag(CECTag(EC_TAG_STAT_NODE_VALUE, (uint64)theStats::GetPeakConnections()));
133}
134
135
136/*----- CStatistics -----*/
137
138// Static variables
139
140// Rate counters
141CPreciseRateCounter* CStatistics::s_upOverheadRate;
142CPreciseRateCounter* CStatistics::s_downOverheadRate;
143CStatTreeItemRateCounter* CStatistics::s_uploadrate;
144CStatTreeItemRateCounter* CStatistics::s_downloadrate;
145
146#else /* CLIENT_GUI */
147
148uint64 CStatistics::s_start_time;
149uint64 CStatistics::s_statData[sdTotalItems];
150
151#endif /* !CLIENT_GUI / CLIENT_GUI */
152
153// Tree root
154CStatTreeItemBase* CStatistics::s_statTree;
155
156#ifndef CLIENT_GUI
157// Uptime
158CStatTreeItemTimer* CStatistics::s_uptime;
159
160// Upload
161CStatTreeItemUlDlCounter* CStatistics::s_sessionUpload;
162CStatTreeItemPacketTotals* CStatistics::s_totalUpOverhead;
163CStatTreeItemPackets* CStatistics::s_fileReqUpOverhead;
164CStatTreeItemPackets* CStatistics::s_sourceXchgUpOverhead;
165CStatTreeItemPackets* CStatistics::s_serverUpOverhead;
166CStatTreeItemPackets* CStatistics::s_kadUpOverhead;
167CStatTreeItemCounter* CStatistics::s_cryptUpOverhead;
168CStatTreeItemNativeCounter* CStatistics::s_activeUploads;
169CStatTreeItemNativeCounter* CStatistics::s_waitingUploads;
170CStatTreeItemCounter* CStatistics::s_totalSuccUploads;
171CStatTreeItemCounter* CStatistics::s_totalFailedUploads;
172CStatTreeItemCounter* CStatistics::s_totalUploadTime;
173
174// Download
175CStatTreeItemUlDlCounter* CStatistics::s_sessionDownload;
176CStatTreeItemPacketTotals* CStatistics::s_totalDownOverhead;
177CStatTreeItemPackets* CStatistics::s_fileReqDownOverhead;
178CStatTreeItemPackets* CStatistics::s_sourceXchgDownOverhead;
179CStatTreeItemPackets* CStatistics::s_serverDownOverhead;
180CStatTreeItemPackets* CStatistics::s_kadDownOverhead;
181CStatTreeItemCounter* CStatistics::s_cryptDownOverhead;
182CStatTreeItemCounter* CStatistics::s_foundSources;
183CStatTreeItemNativeCounter* CStatistics::s_activeDownloads;
184
185// Connection
186CStatTreeItemReconnects* CStatistics::s_reconnects;
187CStatTreeItemTimer* CStatistics::s_sinceFirstTransfer;
188CStatTreeItemTimer* CStatistics::s_sinceConnected;
189CStatTreeItemCounterMax* CStatistics::s_activeConnections;
190CStatTreeItemMaxConnLimitReached* CStatistics::s_limitReached;
191CStatTreeItemSimple* CStatistics::s_avgConnections;
192
193// Clients
194CStatTreeItemHiddenCounter* CStatistics::s_clients;
195CStatTreeItemCounter* CStatistics::s_unknown;
196//CStatTreeItem CStatistics::s_lowID;
197//CStatTreeItem CStatistics::s_secIdentOnOff;
198#ifdef __DEBUG__
199CStatTreeItemNativeCounter* CStatistics::s_hasSocket;
200#endif
201CStatTreeItemNativeCounter* CStatistics::s_filtered;
202CStatTreeItemNativeCounter* CStatistics::s_banned;
203
204// Servers
205CStatTreeItemSimple* CStatistics::s_workingServers;
206CStatTreeItemSimple* CStatistics::s_failedServers;
207CStatTreeItemNativeCounter* CStatistics::s_totalServers;
208CStatTreeItemNativeCounter* CStatistics::s_deletedServers;
209CStatTreeItemNativeCounter* CStatistics::s_filteredServers;
210CStatTreeItemSimple* CStatistics::s_usersOnWorking;
211CStatTreeItemSimple* CStatistics::s_filesOnWorking;
212CStatTreeItemSimple* CStatistics::s_totalUsers;
213CStatTreeItemSimple* CStatistics::s_totalFiles;
214CStatTreeItemSimple* CStatistics::s_serverOccupation;
215
216// Shared files
217CStatTreeItemCounter* CStatistics::s_numberOfShared;
218CStatTreeItemCounter* CStatistics::s_sizeOfShare;
219
220// Kad
221uint64_t CStatistics::s_kadNodesTotal;
222uint16_t CStatistics::s_kadNodesCur;
223
224// Totals
225uint64_t CStatistics::s_totalSent;
226uint64_t CStatistics::s_totalReceived;
227
228bool CStatistics::s_statsNeedSave;
229
230
231CStatistics::CStatistics()
232 : m_graphRunningAvgDown(thePrefs::GetStatsAverageMinutes() * 60 * 1000, true),
233 m_graphRunningAvgUp(thePrefs::GetStatsAverageMinutes() * 60 * 1000, true),
234 m_graphRunningAvgKad(thePrefs::GetStatsAverageMinutes() * 60 * 1000, true)
235{
236 uint64 start_time = GetTickCount64();
237
238 // Init graphs
239
240 average_minutes = thePrefs::GetStatsAverageMinutes();
241
242 HR hr = {0.0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0, 0, 0};
243 hrInit = hr;
244 nHistRanges = 7; // =ceil(log(max_update_delay)/log(2))
245 nPointsPerRange = GetPointsPerRange();
246 bitsHistClockMask = (1 << (nHistRanges-1)) - 1;
247 aposRecycle = new listPOS[nHistRanges];
248 listPOS *ppos = aposRecycle+nHistRanges-1;
249 for (int i=nHistRanges; i>0; --i) { // permanently allocated history list
250 listHR.push_back(hr);
251 *ppos-- = --listHR.end();
252 for (int j=nPointsPerRange; j>1; --j)
253 listHR.push_back(hr);
254 }
255
256 // Init rate counters outside the tree
257
258 s_upOverheadRate = new CPreciseRateCounter(5000);
259 s_downOverheadRate = new CPreciseRateCounter(5000);
260
261 // Init Tree
262
263 InitStatsTree();
264 s_uptime->SetStartTime(start_time);
265
266 // Load saved statistics
267 Load();
268 s_statsNeedSave = false;
269}
270
271
272CStatistics::~CStatistics()
273{
274 // clearing listHR frees the memory occupied by the nodes
275 listHR.clear();
276 delete [] aposRecycle;
277
278 delete s_statTree;
279
280 // delete items not in the tree
281 delete s_totalUploadTime;
282
283 // delete rate counters outside the tree
284 delete s_upOverheadRate;
285 delete s_downOverheadRate;
286}
287
288
289static uint64_t ReadUInt64FromCfg(wxConfigBase* cfg, const wxString& key)
290{
291 wxString buffer;
292
293 cfg->Read(key, &buffer, wxT("0")L"0");
294
295 uint64 tmp = 0;
296 for (unsigned int i = 0; i < buffer.Length(); ++i) {
297 if ((buffer[i] >= wxChar('0')) &&(buffer[i] <= wxChar('9'))) {
298 tmp = tmp * 10 + (buffer[i] - wxChar('0'));
299 } else {
300 tmp = 0;
301 break;
302 }
303 }
304
305 return tmp;
306}
307
308void CStatistics::Load()
309{
310 CFile f;
311
312 s_totalSent = 0;
313 s_totalReceived = 0;
314 try {
315 CPath path(JoinPaths(thePrefs::GetConfigDir(), wxT("statistics.dat")L"statistics.dat"));
316 if (path.FileExists() && f.Open(path)) {
317 uint8_t version = f.ReadUInt8();
318 if (version == 0) {
319 s_totalSent = f.ReadUInt64();
320 s_totalReceived = f.ReadUInt64();
321 }
322 }
323 } catch (const CSafeIOException& e) {
324 AddLogLineN(e.what())theLogger.AddLogLine(L"Statistics.cpp", 324, false, logStandard
, e.what())
;
325 }
326
327 // Load old values from config
328 bool cfgChanged = false;
329 wxConfigBase* cfg = wxConfigBase::Get();
330 if (cfg->HasEntry(wxT("/Statistics/TotalUploadedBytes")L"/Statistics/TotalUploadedBytes")) {
331 s_totalSent += ReadUInt64FromCfg(cfg, wxT("/Statistics/TotalUploadedBytes")L"/Statistics/TotalUploadedBytes");
332 cfg->DeleteEntry(wxT("/Statistics/TotalUploadedBytes")L"/Statistics/TotalUploadedBytes");
333 cfgChanged = true;
334 }
335 if (cfg->HasEntry(wxT("/Statistics/TotalDownloadedBytes")L"/Statistics/TotalDownloadedBytes")) {
336 s_totalReceived += ReadUInt64FromCfg(cfg, wxT("/Statistics/TotalDownloadedBytes")L"/Statistics/TotalDownloadedBytes");
337 cfg->DeleteEntry(wxT("/Statistics/TotalDownloadedBytes")L"/Statistics/TotalDownloadedBytes");
338 cfgChanged = true;
339 }
340 if (cfgChanged) {
341 cfg->Flush();
342 s_statsNeedSave = s_totalSent > 0 || s_totalReceived > 0;
343 Save();
344 }
345}
346
347
348void CStatistics::Save()
349{
350 if (s_statsNeedSave) {
351 CFile f;
352
353 if (f.Open(JoinPaths(thePrefs::GetConfigDir(), wxT("statistics.dat")L"statistics.dat"), CFile::write)) {
354 f.WriteUInt8(0); /* version */
355 f.WriteUInt64(s_totalSent);
356 f.WriteUInt64(s_totalReceived);
357 }
358 s_statsNeedSave = false;
359 }
360}
361
362void CStatistics::CalculateRates()
363{
364 uint64_t now = GetTickCount64();
365 s_downOverheadRate->CalculateRate(now);
366 s_upOverheadRate->CalculateRate(now);
367 s_downloadrate->CalculateRate(now);
368 s_uploadrate->CalculateRate(now);
369}
370
371
372
373/* ------------------------------- GRAPHS ---------------------------- */
374
375/*
376History List
377
378 The basic idea here is that we want to keep as much history as we can without paying
379a high price in terms of memory space. Because we keep the history for display purposes,
380we can take advantage of the fact that when the period shown in the graphs is long
381then each pixel represents a long period. So as the most recent history we keep one
382window full of points at a resolution of 1 second, the next window full at 2 seconds,
383the next at 4 seconds and so on, up to the maximum desired. This way there is always
384at least one sample point per pixel for any update delay set by the user, and the
385memory required grows with the *log* of the total time period covered.
386 The history is kept in a doubly-linked list, with the most recent snapshot at the tail.
387The number of nodes in the list is fixed, and there are no calls to RemoveHead() and
388AddTail() which would add overhead and contribute to memory fragmentation. Instead,
389every second when a new point gets recorded, one of the existing nodes is recycled;
390it is disjoined from its present place, put at the tail of the list, and then gets
391filled with new data. [Emilio Sandoz]
392 This unfortunately does not work with stl classes, as none of them supports moving
393a node to another place, so we have to erase and re-add nodes.
394*/
395
396void CStatistics::RecordHistory()
397{ // First we query and compute some values, then we store them in the history list
398
399 // A few comments about the use of double and float in computations:
400 // Even on a hi-res screen our graphs will have 10 bits of resolution at most,
401 // so the 24 bits resolution of a float on 32 bit Intel processors is more than
402 // enough for all displayed values. Rate computations however, and especially
403 // running average computations, use differences (delta bytes/ delta time), and
404 // for long uptimes the difference between two timestamps can lose too much
405 // accuracy because the large mantissa causes less significant bits to be dropped
406 // (same for the difference between two cumulative byte counts). [We don't store
407 // these values as integers because they will be used in floating point calculations,
408 // and we want to perform the conversion only once). Therefore timestamps and
409 // Kbyte counts are stored in the history as doubles, while computed values use
410 // float (to save space and execution time).
411
412/*
413 Store values; first determine the node to be recycled (using the bits in iClock)
414
415 oldest records ----------------- listHR ------------------ youngest records
416
417 O-[Range 2^n sec]-O- ... -O-[Range 4 sec]-O-[Range 2 sec]-O-[Range 1 sec]-O
418 | | | | > every 2 secs -^
419 | | ... | >--------------- every 4 secs -^
420 | | >------------------------ recycle every 8 secs -^
421 | | ...
422 | >-the node at this position is recycled every 2^n secs -^
423 >-------------------(ditto for the oldest node at the head of the list) --^
424 ^ ^
425 aposRecycle[nHistRanges-1] ... aposRecycle[0] Tail
426*/
427 listPOS *ppos;
428 static int iClock;
429 int iClockPrev = iClock++;
430 int bits = (iClockPrev^iClock) & iClock; // identify the highest changed bit
431 if (bits <= bitsHistClockMask) {
432 ppos = aposRecycle;
433 while ((bits /= 2) != 0) // count to the highest bit that was just toggled to 1
434 ++ppos;
This statement is never executed
435 // recycle one node and jump over the next to move it to the next higher range
436 listHR.push_back(**ppos);
437 *ppos = ++listHR.erase(*ppos);
438 } else {
439 ppos = aposRecycle+nHistRanges-1;
440 // recycle the node at the head; there is no higher range to move nodes into
441 listHR.push_back(**ppos);
442 *ppos = listHR.erase(*ppos);
443 }
444
445 // now save the latest data point in this node
446 listPOS phr = --listHR.end();
447 phr->kBytesSent = GetSessionSentBytes() / 1024.0;
448 phr->kBytesReceived = GetSessionReceivedBytes() / 1024.0;
449 phr->kBpsUpCur = GetUploadRate() / 1024.0;
450 phr->kBpsDownCur = GetDownloadRate() / 1024.0;
451 phr->cntUploads = GetActiveUploadsCount();
452 phr->cntConnections = GetActiveConnections();
453 phr->cntDownloads = GetDownloadingSources();
454 phr->sTimestamp = GetUptimeMillis() / 1000.0;
455
456 s_kadNodesTotal += s_kadNodesCur;
457 phr->kadNodesTotal = s_kadNodesTotal;
458 phr->kadNodesCur = s_kadNodesCur;
459}
460
461
462unsigned CStatistics::GetHistory( // Assemble arrays of sample points for a graph
463 unsigned cntPoints, // number of sample points to assemble
464 double sStep, // time difference between sample points
465 double sFinal, // latest allowed timestamp
466 const std::vector<float *> &ppf,// an array of pointers to arrays of floats for the result
467 StatsGraphType which_graph) // the graph which will receive the points
468{
469 if (sStep==0.0 || cntPoints==0) {
470 return(0);
471 }
472
473 float *pf1 = ppf[0];
474 float *pf2 = ppf[1];
475 float *pf3 = ppf[2];
476 unsigned cntFilled = 0;
477 listRPOS pos = listHR.rbegin();
478
479 // start of list should be an integer multiple of the sampling period for samples
480 // to be consistent when the graphs are resized horizontally
481 double sTarget;
482 if (sFinal >= 0.0) {
483 sTarget = sFinal;
484 } else {
485 sTarget = sStep==1.0 ?
486 pos->sTimestamp :
487 std::floor(pos->sTimestamp/sStep) * sStep;
488 }
489
490 HR **ahr = NULL__null, **pphr = NULL__null;
491 bool bRateGraph = (which_graph != GRAPH_CONN); // rate graph or connections graph?
492 if (bRateGraph) {
493 ahr = new HR* [cntPoints];
494 pphr = ahr;
495 }
496
497 while (pos != listHR.rend()) {
498 if (pos->sTimestamp > sTarget) {
499 ++pos;
500 continue;
501 }
502 if (bRateGraph) { // assemble an array of pointers for ComputeAverages
503 *pphr++ = &(*pos);
504 } else { // or build the arrays if possible
505 *pf1++ = (float)pos->cntUploads;
506 *pf2++ = (float)pos->cntConnections;
507 *pf3++ = (float)pos->cntDownloads;
508 }
509 if (++cntFilled == cntPoints) { // enough points
510 break;
511 }
512 if (pos->sTimestamp == 0.0) { // reached beginning of uptime
513 break;
514 }
515 if ((sTarget -= sStep) <= 0.0) { // don't overshoot the beginning
516 if (bRateGraph) {
517 *pphr++ = &hrInit;
518 } else {
519 *pf1++ = *pf2++ = *pf3++ = 0.0;
520 }
521 ++cntFilled;
522 break;
523 }
524 }
525
526 if (bRateGraph) {
527 if (cntFilled > 0) {
528 ComputeAverages(pphr, pos, cntFilled, sStep, ppf, which_graph);
529 }
530 delete[] ahr;
531 }
532
533 return cntFilled;
534}
535
536
537unsigned CStatistics::GetHistoryForWeb( // Assemble arrays of sample points for the webserver
538 unsigned cntPoints, // maximum number of sample points to assemble
539 double sStep, // time difference between sample points
540 double *sStart, // earliest allowed timestamp
541 uint32 **graphData) // a pointer to a pointer that will point to the graph data array
542{
543 if (*sStart < 0.0) {
544 *sStart = 0.0;
545 }
546 if (sStep==0.0 || cntPoints==0)
547 return(0);
548 unsigned cntFilled = 0;
549 listRPOS pos = listHR.rbegin();
550 double LastTimeStamp = pos->sTimestamp;
551 double sTarget = LastTimeStamp;
552
553 HR **pphr = new HR *[cntPoints];
554
555 while (pos != listHR.rend()) {
556 if (pos->sTimestamp > sTarget) {
557 ++pos; // find next history record
558 continue;
559 }
560 pphr[cntFilled] = &(*pos);
561 if (++cntFilled == cntPoints) // enough points
562 break;
563 if (pos->sTimestamp <= *sStart) // reached beginning of requested time
564 break;
565 if ((sTarget -= sStep) <= 0.0) { // don't overshoot the beginning
566 pphr[cntFilled++] = NULL__null;
567 break;
568 }
569 }
570
571 if (cntFilled) {
572 *graphData = new uint32 [4 * cntFilled];
573 if (*graphData) {
574 for (unsigned int i = 0; i < cntFilled; i++) {
575 HR *phr = pphr[cntFilled - i - 1];
576 if (phr) {
577 (*graphData)[4 * i ] = ENDIAN_HTONL((uint32)(phr->kBpsDownCur * 1024.0))( ((wxUint32) ( (((wxUint32) ((uint32)(phr->kBpsDownCur * 1024.0
)) & (wxUint32) 0x000000ffU) << 24) | (((wxUint32) (
(uint32)(phr->kBpsDownCur * 1024.0)) & (wxUint32) 0x0000ff00U
) << 8) | (((wxUint32) ((uint32)(phr->kBpsDownCur * 1024.0
)) & (wxUint32) 0x00ff0000U) >> 8) | (((wxUint32) (
(uint32)(phr->kBpsDownCur * 1024.0)) & (wxUint32) 0xff000000U
) >> 24))) )
;
578 (*graphData)[4 * i + 1] = ENDIAN_HTONL((uint32)(phr->kBpsUpCur * 1024.0))( ((wxUint32) ( (((wxUint32) ((uint32)(phr->kBpsUpCur * 1024.0
)) & (wxUint32) 0x000000ffU) << 24) | (((wxUint32) (
(uint32)(phr->kBpsUpCur * 1024.0)) & (wxUint32) 0x0000ff00U
) << 8) | (((wxUint32) ((uint32)(phr->kBpsUpCur * 1024.0
)) & (wxUint32) 0x00ff0000U) >> 8) | (((wxUint32) (
(uint32)(phr->kBpsUpCur * 1024.0)) & (wxUint32) 0xff000000U
) >> 24))) )
;
579 (*graphData)[4 * i + 2] = ENDIAN_HTONL((uint32)phr->cntConnections)( ((wxUint32) ( (((wxUint32) ((uint32)phr->cntConnections)
& (wxUint32) 0x000000ffU) << 24) | (((wxUint32) ((
uint32)phr->cntConnections) & (wxUint32) 0x0000ff00U) <<
8) | (((wxUint32) ((uint32)phr->cntConnections) & (wxUint32
) 0x00ff0000U) >> 8) | (((wxUint32) ((uint32)phr->cntConnections
) & (wxUint32) 0xff000000U) >> 24))) )
;
580 (*graphData)[4 * i + 3] = ENDIAN_HTONL((uint32)phr->kadNodesCur)( ((wxUint32) ( (((wxUint32) ((uint32)phr->kadNodesCur) &
(wxUint32) 0x000000ffU) << 24) | (((wxUint32) ((uint32
)phr->kadNodesCur) & (wxUint32) 0x0000ff00U) << 8
) | (((wxUint32) ((uint32)phr->kadNodesCur) & (wxUint32
) 0x00ff0000U) >> 8) | (((wxUint32) ((uint32)phr->kadNodesCur
) & (wxUint32) 0xff000000U) >> 24))) )
;
581 } else {
582 (*graphData)[4 * i] = (*graphData)[4 * i + 1] = 0;
583 (*graphData)[4 * i + 2] = (*graphData)[4 * i + 3] = 0;
584 }
585 }
586 }
587 } else {
588 *graphData = NULL__null;
589 }
590
591 delete [] pphr;
592
593 *sStart = LastTimeStamp;
594
595 return cntFilled;
596}
597
598
599void CStatistics::ComputeAverages(
600 HR **pphr, // pointer to (end of) array of assembled history records
601 listRPOS pos, // position in history list from which to backtrack
602 unsigned cntFilled, // number of points in the sample data
603 double sStep, // time difference between two samples
604 const std::vector<float *> &ppf,// an array of pointers to arrays of floats with sample data
605 StatsGraphType which_graph) // the graph which will receive the points
606{
607 double sTarget, kValueRun;
608 uint64 avgTime = average_minutes * 60;
609 unsigned nBtPoints = (unsigned)(avgTime / sStep);
610
611 CPreciseRateCounter* runningAvg = NULL__null;
612 switch (which_graph) {
613 case GRAPH_DOWN: runningAvg = &m_graphRunningAvgDown; break;
614 case GRAPH_UP: runningAvg = &m_graphRunningAvgUp; break;
615 case GRAPH_KAD: runningAvg = &m_graphRunningAvgKad; break;
616 default:
617 wxCHECK_RET(false, wxT("ComputeAverages called with unsupported graph type."))if ( false ) {} else { do { if ( wxTheAssertHandler &&
(wxOnAssert("Statistics.cpp", 617, __FUNCTION__, "\"false\""
, L"ComputeAverages called with unsupported graph type."), wxTrapInAssert
) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while
( (void)0, 0 ); return; } struct wxDummyCheckStruct617
;
618 }
619
620 runningAvg->m_timespan = avgTime * 1000;
621 runningAvg->m_tick_history.clear();
622 runningAvg->m_byte_history.clear();
623 runningAvg->m_total = 0;
624 runningAvg->m_tmp_sum = 0;
625
626 if (pos == listHR.rend()) {
627 sTarget = 0.0;
628 } else {
629 sTarget = std::max(0.0, pos->sTimestamp - sStep);
630 }
631
632 while (nBtPoints--) {
633 while (pos != listHR.rend() && pos->sTimestamp > sTarget) ++pos; // find next history record
634 if (pos != listHR.rend()) {
635 runningAvg->m_tick_history.push_front((uint64)(pos->sTimestamp * 1000.0));
636
637 uint32 value = 0;
638 switch (which_graph) {
639 case GRAPH_DOWN:
640 value = (uint32)(pos->kBpsDownCur * 1024.0);
641 break;
642 case GRAPH_UP:
643 value = (uint32)(pos->kBpsUpCur * 1024.0);
644 break;
645 case GRAPH_KAD:
646 value = (uint32)(pos->kadNodesCur * 1024.0);
647 break;
648 default:
649 wxCHECK_RET(false, wxT("ComputeAverages called with unsupported graph type."))if ( false ) {} else { do { if ( wxTheAssertHandler &&
(wxOnAssert("Statistics.cpp", 649, __FUNCTION__, "\"false\""
, L"ComputeAverages called with unsupported graph type."), wxTrapInAssert
) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while
( (void)0, 0 ); return; } struct wxDummyCheckStruct649
;
650 }
651
652 runningAvg->m_byte_history.push_front(value);
653 runningAvg->m_total += value;
654 } else {
655 break;
656 }
657 if ((sTarget -= sStep) < 0.0) {
658 break;
659 }
660 };
661
662 // now compute averages in returned arrays, starting with the earliest values
663 float *pf1 = ppf[0] + cntFilled - 1; // holds session avg
664 float *pf2 = ppf[1] + cntFilled - 1; // holds running avg
665 float *pf3 = ppf[2] + cntFilled - 1; // holds current rate
666
667 for (int cnt=cntFilled; cnt>0; cnt--, pf1--, pf2--, pf3--) {
668 HR *phr = *(--pphr);
669 if (which_graph == GRAPH_DOWN) {
670 kValueRun = phr->kBytesReceived;
671 *pf3 = phr->kBpsDownCur;
672 } else if (which_graph == GRAPH_UP) {
673 kValueRun = phr->kBytesSent;
674 *pf3 = phr->kBpsUpCur;
675 } else {
676 kValueRun = phr->kadNodesTotal;
677 *pf3 = phr->kadNodesCur;
678 }
679
680 *pf1 = kValueRun / phr->sTimestamp;
681 (*runningAvg) += (uint32)(*pf3 * 1024.0);
682 runningAvg->CalculateRate((uint64)(phr->sTimestamp * 1000.0));
683 *pf2 = (float)(runningAvg->GetRate() / 1024.0);
684 }
685}
686
687
688GraphUpdateInfo CStatistics::GetPointsForUpdate()
689{
690 GraphUpdateInfo update;
691 listPOS phr = --listHR.end();
692 update.timestamp = (double) phr->sTimestamp;
693
694 m_graphRunningAvgDown += (uint32)(phr->kBpsDownCur * 1024.0);
695 m_graphRunningAvgUp += (uint32)(phr->kBpsUpCur * 1024.0);
696 // Note: kadNodesCur is multiplied by 1024 since the value is done
697 // in other places, so we simply follow suit here to avoid trouble.
698 m_graphRunningAvgKad += (uint32)(phr->kadNodesCur * 1024.0);
699 m_graphRunningAvgDown.CalculateRate((uint64)(phr->sTimestamp * 1000.0));
700 m_graphRunningAvgUp.CalculateRate((uint64)(phr->sTimestamp * 1000.0));
701 m_graphRunningAvgKad.CalculateRate((uint64)(phr->sTimestamp * 1000.0));
702
703 update.downloads[0] = phr->kBytesReceived / phr->sTimestamp;
704 update.downloads[1] = m_graphRunningAvgDown.GetRate() / 1024.0;
705 update.downloads[2] = phr->kBpsDownCur;
706
707 update.uploads[0] = phr->kBytesSent / phr->sTimestamp;
708 update.uploads[1] = m_graphRunningAvgUp.GetRate() / 1024.0;
709 update.uploads[2] = phr->kBpsUpCur;
710
711 update.connections[0] = (float)phr->cntUploads;
712 update.connections[1] = (float)phr->cntConnections;
713 update.connections[2] = (float)phr->cntDownloads;
714
715 update.kadnodes[0] = phr->kadNodesTotal / phr->sTimestamp;
716 update.kadnodes[1] = m_graphRunningAvgKad.GetRate() / 1024.0;
717 update.kadnodes[2] = phr->kadNodesCur;
718
719 return update;
720}
721
722
723/* ------------------------------- TREE ---------------------------- */
724
725void CStatistics::InitStatsTree()
726{
727 s_statTree = new CStatTreeItemBase(wxTRANSLATE("Statistics")"Statistics");
728
729 CStatTreeItemBase* tmpRoot1;
730 CStatTreeItemBase* tmpRoot2;
731
732 s_uptime = static_cast<CStatTreeItemTimer*>(s_statTree->AddChild(new CStatTreeItemTimer(wxTRANSLATE("Uptime: %s")"Uptime: %s")));
733
734 tmpRoot1 = s_statTree->AddChild(new CStatTreeItemBase(wxTRANSLATE("Transfer")"Transfer", stSortChildren));
735
736 tmpRoot2 = tmpRoot1->AddChild(new CStatTreeItemBase(wxTRANSLATE("Uploads")"Uploads"), 2);
737 s_sessionUpload = static_cast<CStatTreeItemUlDlCounter*>(tmpRoot2->AddChild(new CStatTreeItemUlDlCounter(wxTRANSLATE("Uploaded Data (Session (Total)): %s")"Uploaded Data (Session (Total)): %s", theStats::GetTotalSentBytes, stSortChildren | stSortByValue)));
738 // Children will be added on-the-fly
739 s_totalUpOverhead = static_cast<CStatTreeItemPacketTotals*>(tmpRoot2->AddChild(new CStatTreeItemPacketTotals(wxTRANSLATE("Total Overhead (Packets): %s")"Total Overhead (Packets): %s")));
740 s_fileReqUpOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("File Request Overhead (Packets): %s")"File Request Overhead (Packets): %s")));
741 s_totalUpOverhead->AddPacketCounter(s_fileReqUpOverhead);
742 s_sourceXchgUpOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Source Exchange Overhead (Packets): %s")"Source Exchange Overhead (Packets): %s")));
743 s_totalUpOverhead->AddPacketCounter(s_sourceXchgUpOverhead);
744 s_serverUpOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Server Overhead (Packets): %s")"Server Overhead (Packets): %s")));
745 s_totalUpOverhead->AddPacketCounter(s_serverUpOverhead);
746 s_kadUpOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Kad Overhead (Packets): %s")"Kad Overhead (Packets): %s")));
747 s_totalUpOverhead->AddPacketCounter(s_kadUpOverhead);
748 s_cryptUpOverhead = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Crypt overhead (UDP): %s")"Crypt overhead (UDP): %s")));
749 s_cryptUpOverhead->SetDisplayMode(dmBytes);
750 s_activeUploads = static_cast<CStatTreeItemNativeCounter*>(tmpRoot2->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Active Uploads: %s")"Active Uploads: %s")));
751 s_waitingUploads = static_cast<CStatTreeItemNativeCounter*>(tmpRoot2->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Waiting Uploads: %s")"Waiting Uploads: %s")));
752 s_totalSuccUploads = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Total successful upload sessions: %s")"Total successful upload sessions: %s")));
753 s_totalFailedUploads = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Total failed upload sessions: %s")"Total failed upload sessions: %s")));
754 s_totalUploadTime = new CStatTreeItemCounter(wxEmptyString);
755 tmpRoot2->AddChild(new CStatTreeItemAverage(wxTRANSLATE("Average upload time: %s")"Average upload time: %s", s_totalUploadTime, s_totalSuccUploads, dmTime));
756
757 tmpRoot2 = tmpRoot1->AddChild(new CStatTreeItemBase(wxTRANSLATE("Downloads")"Downloads"), 1);
758 s_sessionDownload = static_cast<CStatTreeItemUlDlCounter*>(tmpRoot2->AddChild(new CStatTreeItemUlDlCounter(wxTRANSLATE("Downloaded Data (Session (Total)): %s")"Downloaded Data (Session (Total)): %s", theStats::GetTotalReceivedBytes, stSortChildren | stSortByValue)));
759 // Children will be added on-the-fly
760 s_totalDownOverhead = static_cast<CStatTreeItemPacketTotals*>(tmpRoot2->AddChild(new CStatTreeItemPacketTotals(wxTRANSLATE("Total Overhead (Packets): %s")"Total Overhead (Packets): %s")));
761 s_fileReqDownOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("File Request Overhead (Packets): %s")"File Request Overhead (Packets): %s")));
762 s_totalDownOverhead->AddPacketCounter(s_fileReqDownOverhead);
763 s_sourceXchgDownOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Source Exchange Overhead (Packets): %s")"Source Exchange Overhead (Packets): %s")));
764 s_totalDownOverhead->AddPacketCounter(s_sourceXchgDownOverhead);
765 s_serverDownOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Server Overhead (Packets): %s")"Server Overhead (Packets): %s")));
766 s_totalDownOverhead->AddPacketCounter(s_serverDownOverhead);
767 s_kadDownOverhead = static_cast<CStatTreeItemPackets*>(tmpRoot2->AddChild(new CStatTreeItemPackets(wxTRANSLATE("Kad Overhead (Packets): %s")"Kad Overhead (Packets): %s")));
768 s_totalDownOverhead->AddPacketCounter(s_kadDownOverhead);
769 s_cryptDownOverhead = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Crypt overhead (UDP): %s")"Crypt overhead (UDP): %s")));
770 s_cryptDownOverhead->SetDisplayMode(dmBytes);
771 s_foundSources = static_cast<CStatTreeItemCounter*>(tmpRoot2->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Found Sources: %s")"Found Sources: %s", stSortChildren | stSortByValue)));
772 s_activeDownloads = static_cast<CStatTreeItemNativeCounter*>(tmpRoot2->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Active Downloads (chunks): %s")"Active Downloads (chunks): %s")));
773
774 tmpRoot1->AddChild(new CStatTreeItemRatio(wxTRANSLATE("Session UL:DL Ratio (Total): %s")"Session UL:DL Ratio (Total): %s", s_sessionUpload, s_sessionDownload, theStats::GetTotalSentBytes, theStats::GetTotalReceivedBytes), 3);
775
776 tmpRoot1 = s_statTree->AddChild(new CStatTreeItemBase(wxTRANSLATE("Connection")"Connection"));
777 tmpRoot1->AddChild(new CStatTreeItemAverageSpeed(wxTRANSLATE("Average download rate (Session): %s")"Average download rate (Session): %s", s_sessionDownload, s_uptime));
778 tmpRoot1->AddChild(new CStatTreeItemAverageSpeed(wxTRANSLATE("Average upload rate (Session): %s")"Average upload rate (Session): %s", s_sessionUpload, s_uptime));
779 s_downloadrate = static_cast<CStatTreeItemRateCounter*>(tmpRoot1->AddChild(new CStatTreeItemRateCounter(wxTRANSLATE("Max download rate (Session): %s")"Max download rate (Session): %s", true, 30000)));
780 s_uploadrate = static_cast<CStatTreeItemRateCounter*>(tmpRoot1->AddChild(new CStatTreeItemRateCounter(wxTRANSLATE("Max upload rate (Session): %s")"Max upload rate (Session): %s", true, 30000)));
781 s_reconnects = static_cast<CStatTreeItemReconnects*>(tmpRoot1->AddChild(new CStatTreeItemReconnects(wxTRANSLATE("Reconnects: %i")"Reconnects: %i")));
782 s_sinceFirstTransfer = static_cast<CStatTreeItemTimer*>(tmpRoot1->AddChild(new CStatTreeItemTimer(wxTRANSLATE("Time Since First Transfer: %s")"Time Since First Transfer: %s", stHideIfZero)));
783 s_sinceConnected = static_cast<CStatTreeItemTimer*>(tmpRoot1->AddChild(new CStatTreeItemTimer(wxTRANSLATE("Connected To Server Since: %s")"Connected To Server Since: %s")));
784 s_activeConnections = static_cast<CStatTreeItemCounterMax*>(tmpRoot1->AddChild(new CStatTreeItemCounterMax(wxTRANSLATE("Active Connections (estimate): %i")"Active Connections (estimate): %i")));
785 s_limitReached = static_cast<CStatTreeItemMaxConnLimitReached*>(tmpRoot1->AddChild(new CStatTreeItemMaxConnLimitReached(wxTRANSLATE("Max Connection Limit Reached: %s")"Max Connection Limit Reached: %s")));
786 s_avgConnections = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Average Connections (estimate): %g")"Average Connections (estimate): %g")));
787 s_avgConnections->SetValue(0.0);
788 tmpRoot1->AddChild(new CStatTreeItemPeakConnections(wxTRANSLATE("Peak Connections (estimate): %i")"Peak Connections (estimate): %i"));
789
790 s_clients = static_cast<CStatTreeItemHiddenCounter*>(s_statTree->AddChild(new CStatTreeItemHiddenCounter(wxTRANSLATE("Clients")"Clients", stSortChildren | stSortByValue)));
791 s_unknown = static_cast<CStatTreeItemCounter*>(s_clients->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Unknown: %s")"Unknown: %s"), 6));
792 //s_lowID = static_cast<CStatTreeItem*>(s_clients->AddChild(new CStatTreeItem(wxTRANSLATE("LowID: %u (%.2f%% Total %.2f%% Known)")), 5));
793 //s_secIdentOnOff = static_cast<CStatTreeItem*>(s_clients->AddChild(new CStatTreeItem(wxTRANSLATE("SecIdent On/Off: %u (%.2f%%) : %u (%.2f%%)")), 4));
794#ifdef __DEBUG__
795 s_hasSocket = static_cast<CStatTreeItemNativeCounter*>(s_clients->AddChild(new CStatTreeItemNativeCounter(wxT("HasSocket: %s")L"HasSocket: %s"), 3));
796#endif
797 s_filtered = static_cast<CStatTreeItemNativeCounter*>(s_clients->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Filtered: %s")"Filtered: %s"), 2));
798 s_banned = static_cast<CStatTreeItemNativeCounter*>(s_clients->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Banned: %s")"Banned: %s"), 1));
799 s_clients->AddChild(new CStatTreeItemTotalClients(wxTRANSLATE("Total: %i Known: %i")"Total: %i Known: %i", s_clients, s_unknown), 0x80000000);
800
801 // TODO: Use counters?
802 tmpRoot1 = s_statTree->AddChild(new CStatTreeItemBase(wxTRANSLATE("Servers")"Servers"));
803 s_workingServers = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Working Servers: %i")"Working Servers: %i")));
804 s_failedServers = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Failed Servers: %i")"Failed Servers: %i")));
805 s_totalServers = static_cast<CStatTreeItemNativeCounter*>(tmpRoot1->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Total: %s")"Total: %s")));
806 s_deletedServers = static_cast<CStatTreeItemNativeCounter*>(tmpRoot1->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Deleted Servers: %s")"Deleted Servers: %s")));
807 s_filteredServers = static_cast<CStatTreeItemNativeCounter*>(tmpRoot1->AddChild(new CStatTreeItemNativeCounter(wxTRANSLATE("Filtered Servers: %s")"Filtered Servers: %s")));
808 s_usersOnWorking = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Users on Working Servers: %llu")"Users on Working Servers: %llu")));
809 s_filesOnWorking = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Files on Working Servers: %llu")"Files on Working Servers: %llu")));
810 s_totalUsers = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Total Users: %llu")"Total Users: %llu")));
811 s_totalFiles = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Total Files: %llu")"Total Files: %llu")));
812 s_serverOccupation = static_cast<CStatTreeItemSimple*>(tmpRoot1->AddChild(new CStatTreeItemSimple(wxTRANSLATE("Server Occupation: %.2f%%")"Server Occupation: %.2f%%")));
813 s_serverOccupation->SetValue(0.0);
814
815 tmpRoot1 = s_statTree->AddChild(new CStatTreeItemBase(wxTRANSLATE("Shared Files")"Shared Files"));
816 s_numberOfShared = static_cast<CStatTreeItemCounter*>(tmpRoot1->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Number of Shared Files: %s")"Number of Shared Files: %s")));
817 s_sizeOfShare = static_cast<CStatTreeItemCounter*>(tmpRoot1->AddChild(new CStatTreeItemCounter(wxTRANSLATE("Total size of Shared Files: %s")"Total size of Shared Files: %s")));
818 s_sizeOfShare->SetDisplayMode(dmBytes);
819 tmpRoot1->AddChild(new CStatTreeItemAverage(wxTRANSLATE("Average file size: %s")"Average file size: %s", s_sizeOfShare, s_numberOfShared, dmBytes));
820}
821
822
823void CStatistics::UpdateStatsTree()
824{
825 // get sort orders right
826 s_sessionUpload->ReSortChildren();
827 s_sessionDownload->ReSortChildren();
828 s_clients->ReSortChildren();
829 s_foundSources->ReSortChildren();
830 // TODO: sort OS_Info subtrees.
831
832 s_avgConnections->SetValue(theApp->listensocket->GetAverageConnections());
833
834 // get serverstats
835 // TODO: make these realtime, too
836 uint32 servfail;
837 uint32 servuser;
838 uint32 servfile;
839 uint32 servtuser;
840 uint32 servtfile;
841 float servocc;
842 theApp->serverlist->GetStatus(servfail, servuser, servfile, servtuser, servtfile, servocc);
843 s_workingServers->SetValue((uint64)((*s_totalServers)-servfail));
844 s_failedServers->SetValue((uint64)servfail);
845 s_usersOnWorking->SetValue((uint64)servuser);
846 s_filesOnWorking->SetValue((uint64)servfile);
847 s_totalUsers->SetValue((uint64)servtuser);
848 s_totalFiles->SetValue((uint64)servtfile);
849 s_serverOccupation->SetValue(servocc);
850}
851
852
853void CStatistics::AddSourceOrigin(unsigned origin)
854{
855 CStatTreeItemCounter* counter = static_cast<CStatTreeItemCounter*>(s_foundSources->GetChildById(0x0100 + origin));
856 if (counter) {
857 ++(*counter);
858 } else {
859 counter = new CStatTreeItemCounter(OriginToText(origin) + wxT(": %s")L": %s", stHideIfZero | stShowPercent);
860 ++(*counter);
861 s_foundSources->AddChild(counter, 0x0100 + origin);
862 }
863}
864
865void CStatistics::RemoveSourceOrigin(unsigned origin)
866{
867 CStatTreeItemCounter* counter = static_cast<CStatTreeItemCounter*>(s_foundSources->GetChildById(0x0100 + origin));
868 wxASSERT(counter)do { if ( counter ) { } else if ( wxTheAssertHandler &&
(wxOnAssert("Statistics.cpp", 868, __FUNCTION__, "counter", (
const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
869 --(*counter);
870}
871
872static uint32 GetSoftID(uint8 SoftType)
873{
874 // prevent appearing multiple tree entries with the same name
875 // this should be kept in sync with GetSoftName().
876 switch (SoftType) {
877 case SO_OLDEMULE:
878 return 0x0100 + SO_EMULE;
879 case SO_NEW_SHAREAZA:
880 case SO_NEW2_SHAREAZA:
881 return 0x0100 + SO_SHAREAZA;
882 case SO_NEW2_MLDONKEY:
883 return 0x0100 + SO_NEW_MLDONKEY;
884 default:
885 return 0x0100 + SoftType;
886 }
887}
888
889void CStatistics::AddDownloadFromSoft(uint8 SoftType, uint32 bytes)
890{
891 AddReceivedBytes(bytes);
892
893 uint32 id = GetSoftID(SoftType);
894
895 if (s_sessionDownload->HasChildWithId(id)) {
896 (*static_cast<CStatTreeItemCounter*>(s_sessionDownload->GetChildById(id))) += bytes;
897 } else {
898 CStatTreeItemCounter* tmp = new CStatTreeItemCounter(GetSoftName(SoftType) + wxT(": %s")L": %s");
899 tmp->SetDisplayMode(dmBytes);
900 (*tmp) += bytes;
901 s_sessionDownload->AddChild(tmp, id);
902 }
903}
904
905void CStatistics::AddUploadToSoft(uint8 SoftType, uint32 bytes)
906{
907 uint32 id = GetSoftID(SoftType);
908
909 if (s_sessionUpload->HasChildWithId(id)) {
910 (*static_cast<CStatTreeItemCounter*>(s_sessionUpload->GetChildById(id))) += bytes;
911 } else {
912 CStatTreeItemCounter* tmp = new CStatTreeItemCounter(GetSoftName(SoftType) + wxT(": %s")L": %s");
913 tmp->SetDisplayMode(dmBytes);
914 (*tmp) += bytes;
915 s_sessionUpload->AddChild(tmp, id);
916 }
917}
918
919inline bool SupportsOSInfo(unsigned clientSoft)
920{
921 return (clientSoft == SO_AMULE) || (clientSoft == SO_HYDRANODE) || (clientSoft == SO_NEW2_MLDONKEY);
922}
923
924// Do some random black magic to strings to get a relatively unique number for them.
925static uint32 GetIdFromString(const wxString& str)
926{
927 uint32 id = 0;
928 for (unsigned i = 0; i < str.Length(); ++i) {
929 unsigned old_id = id;
930 id += (uint32)str.GetChar(i);
931 id <<= 2;
932 id ^= old_id;
933 id -= old_id;
934 }
935 return (((id >> 1) + id) | 0x00000100) & 0x7fffffff;
936}
937
938void CStatistics::AddKnownClient(CUpDownClient *pClient)
939{
940 ++(*s_clients);
941
942 uint32 clientSoft = pClient->GetClientSoft();
943 uint32 id = GetSoftID(clientSoft);
944
945 CStatTreeItemCounter *client;
946
947 if (s_clients->HasChildWithId(id)) {
948 client = static_cast<CStatTreeItemCounter*>(s_clients->GetChildById(id));
949 ++(*client);
950 } else {
951 uint32 flags = stSortChildren | stShowPercent | stHideIfZero;
952 if (!SupportsOSInfo(clientSoft)) {
953 flags |= stCapChildren;
954 }
955 client = new CStatTreeItemCounter(GetSoftName(clientSoft) + wxT(": %s")L": %s", flags);
956 ++(*client);
957 s_clients->AddChild(client, id);
958 if (SupportsOSInfo(clientSoft)) {
959 client->AddChild(new CStatTreeItemBase(wxTRANSLATE("Version")"Version", stSortChildren | stCapChildren), 2);
960 client->AddChild(new CStatTreeItemBase(wxTRANSLATE("Operating System")"Operating System", stSortChildren | stSortByValue), 1);
961 }
962 }
963
964 CStatTreeItemBase *versionRoot = SupportsOSInfo(clientSoft) ? client->GetChildById(2) : client;
965 uint32 clientVersion = pClient->GetVersion();
966
967 if (versionRoot->HasChildWithId(clientVersion)) {
968 CStatTreeItemCounter *version = static_cast<CStatTreeItemCounter*>(versionRoot->GetChildById(clientVersion));
969 ++(*version);
970 } else {
971 const wxString& versionStr = pClient->GetVersionString();
972 CStatTreeItemCounter *version = new CStatTreeItemCounter((versionStr.IsEmpty() ? wxString(wxTRANSLATE("Unknown")"Unknown") : versionStr) + wxT(": %s")L": %s", stShowPercent | stHideIfZero);
973 ++(*version);
974 versionRoot->AddChild(version, clientVersion, SupportsOSInfo(clientSoft));
975 }
976
977 if (SupportsOSInfo(clientSoft)) {
978 const wxString& OSInfo = pClient->GetClientOSInfo();
979 uint32 OS_ID = OSInfo.IsEmpty() ? 0 : GetIdFromString(OSInfo);
980 CStatTreeItemBase* OSRoot = client->GetChildById(1);
981 CStatTreeItemCounter* OSNode = static_cast<CStatTreeItemCounter*>(OSRoot->GetChildById(OS_ID));
982 if (OSNode) {
983 ++(*OSNode);
984 } else {
985 OSNode = new CStatTreeItemCounter((OS_ID ? OSInfo : wxString(wxTRANSLATE("Not Received")"Not Received")) + wxT(": %s")L": %s", stShowPercent | stHideIfZero);
986 ++(*OSNode);
987 OSRoot->AddChild(OSNode, OS_ID, true);
988 }
989 }
990}
991
992void CStatistics::RemoveKnownClient(uint32 clientSoft, uint32 clientVersion, const wxString& OSInfo)
993{
994 --(*s_clients);
995
996 uint32 id = GetSoftID(clientSoft);
997
998 CStatTreeItemCounter *client = static_cast<CStatTreeItemCounter*>(s_clients->GetChildById(id));
999 wxASSERT(client)do { if ( client ) { } else if ( wxTheAssertHandler &&
(wxOnAssert("Statistics.cpp", 999, __FUNCTION__, "client", (
const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
1000 --(*client);
1001
1002 CStatTreeItemBase *versionRoot = SupportsOSInfo(clientSoft) ? client->GetChildById(2) : client;
1003
1004 CStatTreeItemCounter *version = static_cast<CStatTreeItemCounter*>(versionRoot->GetChildById(clientVersion));
1005 wxASSERT(version)do { if ( version ) { } else if ( wxTheAssertHandler &&
(wxOnAssert("Statistics.cpp", 1005, __FUNCTION__, "version",
(const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
1006 --(*version);
1007
1008 if (SupportsOSInfo(clientSoft)) {
1009 uint32 OS_ID = OSInfo.IsEmpty() ? 0 : GetIdFromString(OSInfo);
1010 CStatTreeItemCounter* OSNode = static_cast<CStatTreeItemCounter*>(client->GetChildById(1)->GetChildById(OS_ID));
1011 wxASSERT(OSNode)do { if ( OSNode ) { } else if ( wxTheAssertHandler &&
(wxOnAssert("Statistics.cpp", 1011, __FUNCTION__, "OSNode", (
const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false
; asm volatile ("int $3"); } } while ( (void)0, 0 )
;
1012 --(*OSNode);
1013 }
1014}
1015
1016#else /* CLIENT_GUI */
1017
1018CStatistics::CStatistics(CRemoteConnect &conn)
1019 : m_conn(conn)
1020{
1021 s_start_time = GetTickCount64();
1022
1023 // Init Tree
1024 s_statTree = new CStatTreeItemBase(_("Statistics")wxGetTranslation(("Statistics")), 0);
1025
1026 // Clear stat data container
1027 for (int i = 0; i < sdTotalItems; ++i) {
1028 s_statData[i] = 0;
1029 }
1030}
1031
1032
1033CStatistics::~CStatistics()
1034{
1035 delete s_statTree;
1036}
1037
1038
1039void CStatistics::UpdateStats(const CECPacket* stats)
1040{
1041 s_statData[sdUpload] = stats->GetTagByNameSafe(EC_TAG_STATS_UL_SPEED)->GetInt();
1042 s_statData[sdUpOverhead] = stats->GetTagByNameSafe(EC_TAG_STATS_UP_OVERHEAD)->GetInt();
1043 s_statData[sdDownload] = stats->GetTagByNameSafe(EC_TAG_STATS_DL_SPEED)->GetInt();
1044 s_statData[sdDownOverhead] = stats->GetTagByNameSafe(EC_TAG_STATS_DOWN_OVERHEAD)->GetInt();
1045 s_statData[sdWaitingClients] = stats->GetTagByNameSafe(EC_TAG_STATS_UL_QUEUE_LEN)->GetInt();
1046 s_statData[sdBannedClients] = stats->GetTagByNameSafe(EC_TAG_STATS_BANNED_COUNT)->GetInt();
1047 s_statData[sdED2KUsers] = stats->GetTagByNameSafe(EC_TAG_STATS_ED2K_USERS)->GetInt();
1048 s_statData[sdKadUsers] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_USERS)->GetInt();
1049 s_statData[sdED2KFiles] = stats->GetTagByNameSafe(EC_TAG_STATS_ED2K_FILES)->GetInt();
1050 s_statData[sdKadFiles] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_FILES)->GetInt();
1051 s_statData[sdKadFirewalledUDP] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_FIREWALLED_UDP)->GetInt();
1052 s_statData[sdKadIndexedSources] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_SOURCES)->GetInt();
1053 s_statData[sdKadIndexedKeywords] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_KEYWORDS)->GetInt();
1054 s_statData[sdKadIndexedNotes] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_NOTES)->GetInt();
1055 s_statData[sdKadIndexedLoad] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_INDEXED_LOAD)->GetInt();
1056 s_statData[sdKadIPAdress] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_IP_ADRESS)->GetInt();
1057 s_statData[sdKadNodes] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_NODES)->GetInt();
1058 s_statData[sdBuddyStatus] = stats->GetTagByNameSafe(EC_TAG_STATS_BUDDY_STATUS)->GetInt();
1059 s_statData[sdBuddyIP] = stats->GetTagByNameSafe(EC_TAG_STATS_BUDDY_IP)->GetInt();
1060 s_statData[sdBuddyPort] = stats->GetTagByNameSafe(EC_TAG_STATS_BUDDY_PORT)->GetInt();
1061 s_statData[sdKadInLanMode] = stats->GetTagByNameSafe(EC_TAG_STATS_KAD_IN_LAN_MODE)->GetInt();
1062 s_statData[sdTotalSentBytes] = stats->GetTagByNameSafe(EC_TAG_STATS_TOTAL_SENT_BYTES)->GetInt();
1063 s_statData[sdTotalReceivedBytes] = stats->GetTagByNameSafe(EC_TAG_STATS_TOTAL_RECEIVED_BYTES)->GetInt();
1064 s_statData[sdSharedFileCount] = stats->GetTagByNameSafe(EC_TAG_STATS_SHARED_FILE_COUNT)->GetInt();
1065
1066 const CECTag * LoggerTag = stats->GetTagByName(EC_TAG_STATS_LOGGER_MESSAGE);
1067 if (LoggerTag) {
1068 for (CECTag::const_iterator it = LoggerTag->begin(); it != LoggerTag->end(); ++it) {
1069 theApp->AddRemoteLogLine(it->GetStringData());
1070 }
1071 }
1072}
1073
1074
1075void CStatistics::UpdateStatsTree()
1076{}
1077
1078
1079void CStatistics::RebuildStatTreeRemote(const CECTag * tag)
1080{
1081 delete s_statTree;
1082 s_statTree = new CStatTreeItemBase(tag);
1083}
1084
1085
1086uint64 CStatistics::GetUptimeMillis()
1087{
1088 return GetTickCount64() - s_start_time;
1089}
1090
1091
1092uint64 CStatistics::GetUptimeSeconds()
1093{
1094 return (GetTickCount64() - s_start_time) / 1000;
1095}
1096
1097#endif /* !CLIENT_GUI */
1098
1099// File_checked_for_headers