Skip to content

Commit 6819001

Browse files
committed
feat: Add RsCumulativeTrafficStats for cumulative traffic tracking per peer/service
1 parent 9d60a62 commit 6819001

4 files changed

Lines changed: 329 additions & 3 deletions

File tree

src/retroshare/rsconfig.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,48 @@ struct RSTrafficClue : RsSerializable
212212
}
213213
};
214214

215+
/*!
216+
* \brief Cumulative traffic statistics for tracking all-time data transfer
217+
* Used to persist and display per-peer and per-service data usage
218+
*/
219+
struct RsCumulativeTrafficStats : RsSerializable
220+
{
221+
uint64_t bytesIn; //< Total bytes received
222+
uint64_t bytesOut; //< Total bytes sent
223+
uint32_t countIn; //< Number of incoming packets
224+
uint32_t countOut; //< Number of outgoing packets
225+
rstime_t firstSeen; //< Timestamp of first recorded traffic
226+
rstime_t lastSeen; //< Timestamp of most recent traffic
227+
228+
RsCumulativeTrafficStats() :
229+
bytesIn(0), bytesOut(0), countIn(0), countOut(0),
230+
firstSeen(0), lastSeen(0) {}
231+
232+
RsCumulativeTrafficStats& operator+=(const RsCumulativeTrafficStats& other) {
233+
bytesIn += other.bytesIn;
234+
bytesOut += other.bytesOut;
235+
countIn += other.countIn;
236+
countOut += other.countOut;
237+
if (firstSeen == 0 || (other.firstSeen != 0 && other.firstSeen < firstSeen))
238+
firstSeen = other.firstSeen;
239+
if (other.lastSeen > lastSeen)
240+
lastSeen = other.lastSeen;
241+
return *this;
242+
}
243+
244+
void clear() { bytesIn = bytesOut = countIn = countOut = 0; firstSeen = lastSeen = 0; }
245+
246+
// RsSerializable interface
247+
void serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext &ctx) {
248+
RS_SERIAL_PROCESS(bytesIn);
249+
RS_SERIAL_PROCESS(bytesOut);
250+
RS_SERIAL_PROCESS(countIn);
251+
RS_SERIAL_PROCESS(countOut);
252+
RS_SERIAL_PROCESS(firstSeen);
253+
RS_SERIAL_PROCESS(lastSeen);
254+
}
255+
};
256+
215257
struct RsConfigNetStatus : RsSerializable
216258
{
217259
RsConfigNetStatus() : netLocalOk(true)
@@ -338,6 +380,39 @@ class RsServerConfig
338380
*/
339381
virtual int getTrafficInfo(std::list<RSTrafficClue>& out_lst,std::list<RSTrafficClue>& in_lst) = 0 ;
340382

383+
/**
384+
* @brief getCumulativeTrafficByPeer returns cumulative traffic stats grouped by peer
385+
* @jsonapi{development}
386+
* @param[out] stats map of peer ID to cumulative traffic stats
387+
* @return returns true on success
388+
*/
389+
virtual bool getCumulativeTrafficByPeer(std::map<RsPeerId, RsCumulativeTrafficStats>& stats) = 0;
390+
391+
/**
392+
* @brief getCumulativeTrafficByService returns cumulative traffic stats grouped by service
393+
* @jsonapi{development}
394+
* @param[out] stats map of service ID to cumulative traffic stats
395+
* @return returns true on success
396+
*/
397+
virtual bool getCumulativeTrafficByService(std::map<uint16_t, RsCumulativeTrafficStats>& stats) = 0;
398+
399+
/**
400+
* @brief clearCumulativeTraffic clears all cumulative traffic statistics
401+
* @jsonapi{development}
402+
* @param[in] clearPeerStats if true, clears per-peer stats
403+
* @param[in] clearServiceStats if true, clears per-service stats
404+
* @return returns true on success
405+
*/
406+
virtual bool clearCumulativeTraffic(bool clearPeerStats = true, bool clearServiceStats = true) = 0;
407+
408+
/**
409+
* @brief getTotalCumulativeTraffic returns the total cumulative traffic across all peers/services
410+
* @jsonapi{development}
411+
* @param[out] stats total cumulative traffic stats
412+
* @return returns true on success
413+
*/
414+
virtual bool getTotalCumulativeTraffic(RsCumulativeTrafficStats& stats) = 0;
415+
341416
/* From RsInit */
342417

343418
// NOT IMPLEMENTED YET!

src/rsitems/rstrafficstatsitems.h

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*******************************************************************************
2+
* libretroshare/src/rsitems: rstrafficstatsitems.h *
3+
* *
4+
* libretroshare: retroshare core library *
5+
* *
6+
* Copyright (C) 2024 *
7+
* *
8+
* This program is free software: you can redistribute it and/or modify *
9+
* it under the terms of the GNU Lesser General Public License as *
10+
* published by the Free Software Foundation, either version 3 of the *
11+
* License, or (at your option) any later version. *
12+
* *
13+
* This program is distributed in the hope that it will be useful, *
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16+
* GNU Lesser General Public License for more details. *
17+
* *
18+
* You should have received a copy of the GNU Lesser General Public License *
19+
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
20+
* *
21+
*******************************************************************************/
22+
#ifndef RS_TRAFFIC_STATS_ITEMS_H
23+
#define RS_TRAFFIC_STATS_ITEMS_H
24+
25+
#include <map>
26+
27+
#include "rsitems/rsitem.h"
28+
#include "rsitems/rsserviceids.h"
29+
#include "retroshare/rsconfig.h"
30+
#include "serialiser/rsserializer.h"
31+
#include "serialiser/rstypeserializer.h"
32+
33+
// Use BANDWIDTH_CONTROL service type for config items
34+
const uint8_t RS_PKT_SUBTYPE_TRAFFIC_STATS_ITEM = 0x10;
35+
36+
/**************************************************************************/
37+
38+
class RsTrafficStatsConfigItem : public RsItem
39+
{
40+
public:
41+
RsTrafficStatsConfigItem() : RsItem(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_BWCTRL, RS_PKT_SUBTYPE_TRAFFIC_STATS_ITEM)
42+
{}
43+
44+
virtual ~RsTrafficStatsConfigItem() {}
45+
46+
virtual void clear()
47+
{
48+
peerStats.clear();
49+
serviceStats.clear();
50+
}
51+
52+
void serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx)
53+
{
54+
RsTypeSerializer::serial_process(j, ctx, peerStats, "peerStats");
55+
RsTypeSerializer::serial_process(j, ctx, serviceStats, "serviceStats");
56+
}
57+
58+
std::map<RsPeerId, RsCumulativeTrafficStats> peerStats;
59+
std::map<uint16_t, RsCumulativeTrafficStats> serviceStats;
60+
};
61+
62+
class RsTrafficStatsSerialiser : public RsServiceSerializer
63+
{
64+
public:
65+
RsTrafficStatsSerialiser() : RsServiceSerializer(RS_SERVICE_TYPE_BWCTRL) {}
66+
virtual ~RsTrafficStatsSerialiser() {}
67+
68+
RsItem *create_item(uint16_t service, uint8_t item_sub_id) const
69+
{
70+
if (service != RS_SERVICE_TYPE_BWCTRL)
71+
return nullptr;
72+
73+
switch (item_sub_id)
74+
{
75+
case RS_PKT_SUBTYPE_TRAFFIC_STATS_ITEM:
76+
return new RsTrafficStatsConfigItem();
77+
default:
78+
return nullptr;
79+
}
80+
}
81+
};
82+
83+
/**************************************************************************/
84+
85+
#endif /* RS_TRAFFIC_STATS_ITEMS_H */

src/rsserver/p3serverconfig.cc

Lines changed: 149 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <retroshare/rsturtle.h>
2323
#include "rsserver/p3serverconfig.h"
2424
#include "services/p3bwctrl.h"
25+
#include "rsitems/rstrafficstatsitems.h"
2526

2627
#include "pqi/authgpg.h"
2728
#include "pqi/authssl.h"
@@ -37,7 +38,7 @@ static constexpr float DEFAULT_UPLOAD_KB_RATE = 10000.0;
3738
static constexpr float MIN_MINIMAL_RATE = 5.0;
3839

3940

40-
p3ServerConfig::p3ServerConfig(p3PeerMgr *peerMgr, p3LinkMgr *linkMgr, p3NetMgr *netMgr, pqihandler *pqih, p3GeneralConfig *genCfg)
41+
p3ServerConfig::p3ServerConfig(p3PeerMgr *peerMgr, p3LinkMgr *linkMgr, p3NetMgr *netMgr, pqihandler *pqih, p3GeneralConfig *genCfg, p3ConfigMgr *cfgMgr)
4142
: mPeerMgr(peerMgr), mLinkMgr(linkMgr), mNetMgr(netMgr), mPqiHandler(pqih)
4243
, mGeneralConfig(genCfg)
4344
, configMtx("p3ServerConfig")
@@ -46,6 +47,9 @@ p3ServerConfig::p3ServerConfig(p3PeerMgr *peerMgr, p3LinkMgr *linkMgr, p3NetMgr
4647
, mRateDownloadWhenIdle(DEFAULT_DOWNLOAD_KB_RATE), mRateUploadWhenIdle(DEFAULT_UPLOAD_KB_RATE)
4748
, mIsIdle(false), mOpMode(RsOpMode::FULL)
4849
{
50+
// Register with config manager for persistence
51+
if (cfgMgr)
52+
cfgMgr->addConfiguration("traffic_stats.cfg", this);
4953
}
5054

5155
void p3ServerConfig::load_config()
@@ -184,6 +188,108 @@ int p3ServerConfig::getTrafficInfo(std::list<RSTrafficClue>& out_lst,std::list<R
184188
return 0 ;
185189
}
186190

191+
bool p3ServerConfig::getCumulativeTrafficByPeer(std::map<RsPeerId, RsCumulativeTrafficStats>& stats)
192+
{
193+
RsStackMutex stack(configMtx);
194+
195+
// First, update cumulative stats from current traffic clues
196+
std::list<RSTrafficClue> out_lst, in_lst;
197+
if (rsBandwidthControl)
198+
{
199+
rsBandwidthControl->ExtractTrafficInfo(out_lst, in_lst);
200+
201+
rstime_t now = time(nullptr);
202+
203+
// Accumulate outgoing traffic
204+
for (const auto& clue : out_lst)
205+
{
206+
auto& peerStats = mCumulativeTrafficByPeer[clue.peer_id];
207+
peerStats.bytesOut += clue.size;
208+
peerStats.countOut += clue.count;
209+
if (peerStats.firstSeen == 0) peerStats.firstSeen = now;
210+
peerStats.lastSeen = now;
211+
}
212+
213+
// Accumulate incoming traffic
214+
for (const auto& clue : in_lst)
215+
{
216+
auto& peerStats = mCumulativeTrafficByPeer[clue.peer_id];
217+
peerStats.bytesIn += clue.size;
218+
peerStats.countIn += clue.count;
219+
if (peerStats.firstSeen == 0) peerStats.firstSeen = now;
220+
peerStats.lastSeen = now;
221+
}
222+
}
223+
224+
stats = mCumulativeTrafficByPeer;
225+
return true;
226+
}
227+
228+
bool p3ServerConfig::getCumulativeTrafficByService(std::map<uint16_t, RsCumulativeTrafficStats>& stats)
229+
{
230+
RsStackMutex stack(configMtx);
231+
232+
// First, update cumulative stats from current traffic clues
233+
std::list<RSTrafficClue> out_lst, in_lst;
234+
if (rsBandwidthControl)
235+
{
236+
rsBandwidthControl->ExtractTrafficInfo(out_lst, in_lst);
237+
238+
rstime_t now = time(nullptr);
239+
240+
// Accumulate outgoing traffic by service
241+
for (const auto& clue : out_lst)
242+
{
243+
auto& serviceStats = mCumulativeTrafficByService[clue.service_id];
244+
serviceStats.bytesOut += clue.size;
245+
serviceStats.countOut += clue.count;
246+
if (serviceStats.firstSeen == 0) serviceStats.firstSeen = now;
247+
serviceStats.lastSeen = now;
248+
}
249+
250+
// Accumulate incoming traffic by service
251+
for (const auto& clue : in_lst)
252+
{
253+
auto& serviceStats = mCumulativeTrafficByService[clue.service_id];
254+
serviceStats.bytesIn += clue.size;
255+
serviceStats.countIn += clue.count;
256+
if (serviceStats.firstSeen == 0) serviceStats.firstSeen = now;
257+
serviceStats.lastSeen = now;
258+
}
259+
}
260+
261+
stats = mCumulativeTrafficByService;
262+
return true;
263+
}
264+
265+
bool p3ServerConfig::clearCumulativeTraffic(bool clearPeerStats, bool clearServiceStats)
266+
{
267+
RsStackMutex stack(configMtx);
268+
269+
if (clearPeerStats)
270+
mCumulativeTrafficByPeer.clear();
271+
272+
if (clearServiceStats)
273+
mCumulativeTrafficByService.clear();
274+
275+
return true;
276+
}
277+
278+
bool p3ServerConfig::getTotalCumulativeTraffic(RsCumulativeTrafficStats& stats)
279+
{
280+
RsStackMutex stack(configMtx);
281+
282+
stats.clear();
283+
284+
// Sum up all peer stats
285+
for (const auto& pair : mCumulativeTrafficByPeer)
286+
{
287+
stats += pair.second;
288+
}
289+
290+
return true;
291+
}
292+
187293
int p3ServerConfig::getTotalBandwidthRates(RsConfigDataRates &rates)
188294
{
189295
if (rsBandwidthControl)
@@ -562,3 +668,45 @@ void p3ServerConfig::setIsIdle(bool isIdle)
562668
mIsIdle = isIdle;
563669
}
564670

671+
/********************* p3Config persistence methods *******/
672+
673+
RsSerialiser *p3ServerConfig::setupSerialiser()
674+
{
675+
RsSerialiser *rss = new RsSerialiser();
676+
rss->addSerialType(new RsTrafficStatsSerialiser());
677+
return rss;
678+
}
679+
680+
bool p3ServerConfig::saveList(bool &cleanup, std::list<RsItem *>& items)
681+
{
682+
cleanup = true;
683+
684+
RsTrafficStatsConfigItem *item = new RsTrafficStatsConfigItem();
685+
{
686+
RsStackMutex stack(configMtx);
687+
item->peerStats = mCumulativeTrafficByPeer;
688+
item->serviceStats = mCumulativeTrafficByService;
689+
}
690+
items.push_back(item);
691+
692+
return true;
693+
}
694+
695+
bool p3ServerConfig::loadList(std::list<RsItem *>& load)
696+
{
697+
RsStackMutex stack(configMtx);
698+
699+
for (auto it = load.begin(); it != load.end(); ++it)
700+
{
701+
RsTrafficStatsConfigItem *item = dynamic_cast<RsTrafficStatsConfigItem*>(*it);
702+
if (item)
703+
{
704+
mCumulativeTrafficByPeer = item->peerStats;
705+
mCumulativeTrafficByService = item->serviceStats;
706+
}
707+
delete *it;
708+
}
709+
load.clear();
710+
711+
return true;
712+
}

0 commit comments

Comments
 (0)