+
+
+
+ | Username |
+ Network |
+ In |
+ Out |
+ Total |
+
+
+
+ LOOP TrafficLoop ?>
+
+ | VAR Username ?> |
+ VAR Network ?> |
+ VAR In ?> |
+ VAR Out ?> |
+ VAR Total ?> |
+
ENDLOOP ?>
diff --git a/modules/webadmin.cpp b/modules/webadmin.cpp
index 6d6ca7ed..8922b24b 100644
--- a/modules/webadmin.cpp
+++ b/modules/webadmin.cpp
@@ -78,7 +78,7 @@ public:
vParams.push_back(make_pair("user", ""));
AddSubPage(std::make_shared
("settings", "Global Settings", CWebSubPage::F_ADMIN));
AddSubPage(std::make_shared("edituser", "Your Settings", vParams));
- AddSubPage(std::make_shared("traffic", "Traffic Info", CWebSubPage::F_ADMIN));
+ AddSubPage(std::make_shared("traffic", "Traffic Info", vParams));
AddSubPage(std::make_shared("listusers", "Manage Users", CWebSubPage::F_ADMIN));
}
@@ -573,7 +573,7 @@ public:
return true;
} else if (sPageName == "listusers" && spSession->IsAdmin()) {
return ListUsersPage(WebSock, Tmpl);
- } else if (sPageName == "traffic" && spSession->IsAdmin()) {
+ } else if (sPageName == "traffic") {
return TrafficPage(WebSock, Tmpl);
} else if (sPageName == "index") {
return true;
@@ -1431,6 +1431,7 @@ public:
}
bool TrafficPage(CWebSock& WebSock, CTemplate& Tmpl) {
+ std::shared_ptr spSession = WebSock.GetSession();
Tmpl["Title"] = "Traffic Info";
Tmpl["Uptime"] = CZNC::Get().GetUptime();
@@ -1441,6 +1442,11 @@ public:
for (const auto& it : msUsers) {
CUser* pUser = it.second;
+
+ if (!spSession->IsAdmin() && spSession->GetUser() != it.second) {
+ continue;
+ }
+
vector vNetworks = pUser->GetNetworks();
for (const CIRCNetwork* pNetwork : vNetworks) {
@@ -1469,12 +1475,27 @@ public:
CZNC::TrafficStatsMap traffic = CZNC::Get().GetTrafficStats(Users, ZNC, Total);
for (const auto& it : traffic) {
+ if (!spSession->IsAdmin() && !spSession->GetUser()->GetUserName().Equals(it.first)) {
+ continue;
+ }
+
CTemplate& l = Tmpl.AddRow("TrafficLoop");
l["Username"] = it.first;
l["In"] = CString::ToByteStr(it.second.first);
l["Out"] = CString::ToByteStr(it.second.second);
l["Total"] = CString::ToByteStr(it.second.first + it.second.second);
+
+ CZNC::TrafficStatsPair NetworkTotal;
+ CZNC::TrafficStatsMap NetworkTraffic = CZNC::Get().GetNetworkTrafficStats(it.first, NetworkTotal);
+ for (const auto& it2 : NetworkTraffic) {
+ CTemplate& l2 = Tmpl.AddRow("TrafficLoop");
+
+ l2["Network"] = it2.first;
+ l2["In"] = CString::ToByteStr(it2.second.first);
+ l2["Out"] = CString::ToByteStr(it2.second.second);
+ l2["Total"] = CString::ToByteStr(it2.second.first + it2.second.second);
+ }
}
Tmpl["UserIn"] = CString::ToByteStr(Users.first);
diff --git a/src/IRCNetwork.cpp b/src/IRCNetwork.cpp
index 6342280e..facc8669 100644
--- a/src/IRCNetwork.cpp
+++ b/src/IRCNetwork.cpp
@@ -143,7 +143,9 @@ CIRCNetwork::CIRCNetwork(CUser *pUser, const CString& sName)
m_NoticeBuffer(),
m_pPingTimer(nullptr),
m_pJoinTimer(nullptr),
- m_uJoinDelay(0)
+ m_uJoinDelay(0),
+ m_uBytesRead(0),
+ m_uBytesWritten(0)
{
SetUser(pUser);
@@ -301,6 +303,7 @@ CIRCNetwork::~CIRCNetwork() {
}
m_vQueries.clear();
+ CUser* pUser = GetUser();
SetUser(nullptr);
// Make sure we are not in the connection queue
@@ -308,6 +311,14 @@ CIRCNetwork::~CIRCNetwork() {
CZNC::Get().GetManager().DelCronByAddr(m_pPingTimer);
CZNC::Get().GetManager().DelCronByAddr(m_pJoinTimer);
+
+ if (pUser) {
+ pUser->AddBytesRead(m_uBytesRead);
+ pUser->AddBytesWritten(m_uBytesWritten);
+ } else {
+ CZNC::Get().AddBytesRead(m_uBytesRead);
+ CZNC::Get().AddBytesWritten(m_uBytesWritten);
+ }
}
void CIRCNetwork::DelServers() {
diff --git a/src/IRCSock.cpp b/src/IRCSock.cpp
index 8c016b66..450276b8 100644
--- a/src/IRCSock.cpp
+++ b/src/IRCSock.cpp
@@ -130,8 +130,8 @@ CIRCSock::~CIRCSock() {
Quit();
m_msChans.clear();
- m_pNetwork->GetUser()->AddBytesRead(GetBytesRead());
- m_pNetwork->GetUser()->AddBytesWritten(GetBytesWritten());
+ m_pNetwork->AddBytesRead(GetBytesRead());
+ m_pNetwork->AddBytesWritten(GetBytesWritten());
}
void CIRCSock::Quit(const CString& sQuitMsg) {
diff --git a/src/Socket.cpp b/src/Socket.cpp
index 77cd7859..80e86675 100644
--- a/src/Socket.cpp
+++ b/src/Socket.cpp
@@ -407,14 +407,19 @@ CSocket::CSocket(CModule* pModule, const CString& sHostname, unsigned short uPor
CSocket::~CSocket() {
CUser *pUser = nullptr;
+ CIRCNetwork* pNetwork = nullptr;
// CWebSock could cause us to have a nullptr pointer here
if (m_pModule) {
pUser = m_pModule->GetUser();
+ pNetwork = m_pModule->GetNetwork();
m_pModule->UnlinkSocket(this);
}
- if (pUser && m_pModule && (m_pModule->GetType() != CModInfo::GlobalModule)) {
+ if (pNetwork && m_pModule && (m_pModule->GetType() == CModInfo::NetworkModule)) {
+ pNetwork->AddBytesWritten(GetBytesWritten());
+ pNetwork->AddBytesRead(GetBytesRead());
+ } else if (pUser && m_pModule && (m_pModule->GetType() == CModInfo::UserModule)) {
pUser->AddBytesWritten(GetBytesWritten());
pUser->AddBytesRead(GetBytesRead());
} else {
diff --git a/src/User.cpp b/src/User.cpp
index a6fe44fc..8b8bedce 100644
--- a/src/User.cpp
+++ b/src/User.cpp
@@ -120,8 +120,8 @@ CUser::~CUser() {
CZNC::Get().GetManager().DelCronByAddr(m_pUserTimer);
- CZNC::Get().AddBytesRead(BytesRead());
- CZNC::Get().AddBytesWritten(BytesWritten());
+ CZNC::Get().AddBytesRead(m_uBytesRead);
+ CZNC::Get().AddBytesWritten(m_uBytesWritten);
}
template
@@ -1278,3 +1278,19 @@ bool CUser::AutoClearQueryBuffer() const { return m_bAutoClearQueryBuffer; }
CString CUser::GetSkinName() const { return m_sSkinName; }
const CString& CUser::GetUserPath() const { if (!CFile::Exists(m_sUserPath)) { CDir::MakeDir(m_sUserPath); } return m_sUserPath; }
// !Getters
+
+unsigned long long CUser::BytesRead() const {
+ unsigned long long uBytes = m_uBytesRead;
+ for (const CIRCNetwork* pNetwork : m_vIRCNetworks) {
+ uBytes += pNetwork->BytesRead();
+ }
+ return uBytes;
+}
+
+unsigned long long CUser::BytesWritten() const {
+ unsigned long long uBytes = m_uBytesWritten;
+ for (const CIRCNetwork* pNetwork : m_vIRCNetworks) {
+ uBytes += pNetwork->BytesWritten();
+ }
+ return uBytes;
+}
diff --git a/src/znc.cpp b/src/znc.cpp
index 084145ef..252a758f 100644
--- a/src/znc.cpp
+++ b/src/znc.cpp
@@ -1767,6 +1767,38 @@ CZNC::TrafficStatsMap CZNC::GetTrafficStats(TrafficStatsPair &Users,
return ret;
}
+CZNC::TrafficStatsMap CZNC::GetNetworkTrafficStats(const CString& sUsername, TrafficStatsPair& Total) {
+ TrafficStatsMap Networks;
+
+ CUser* pUser = FindUser(sUsername);
+ if (pUser) {
+ for (const CIRCNetwork* pNetwork : pUser->GetNetworks()) {
+ Networks[pNetwork->GetName()].first = pNetwork->BytesRead();
+ Networks[pNetwork->GetName()].second = pNetwork->BytesWritten();
+ Total.first += pNetwork->BytesRead();
+ Total.second += pNetwork->BytesWritten();
+ }
+
+ for (Csock* pSock : m_Manager) {
+ CIRCNetwork *pNetwork = nullptr;
+ if (pSock->GetSockName().StartsWith("IRC::")) {
+ pNetwork = ((CIRCSock *) pSock)->GetNetwork();
+ } else if (pSock->GetSockName().StartsWith("USR::")) {
+ pNetwork = ((CClient *) pSock)->GetNetwork();
+ }
+
+ if (pNetwork && pNetwork->GetUser() == pUser) {
+ Networks[pNetwork->GetName()].first = pSock->GetBytesRead();
+ Networks[pNetwork->GetName()].second = pSock->GetBytesWritten();
+ Total.first += pSock->GetBytesRead();
+ Total.second += pSock->GetBytesWritten();
+ }
+ }
+ }
+
+ return Networks;
+}
+
void CZNC::AuthUser(std::shared_ptr AuthClass) {
// TODO unless the auth module calls it, CUser::IsHostAllowed() is not honoured
bool bReturn = false;