From 38fb4cc444666f347342d20b6c62c25ea24e55ae Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 6 Aug 2015 00:53:55 +0200 Subject: [PATCH 1/4] Calculate per-network traffic (#963) --- include/znc/IRCNetwork.h | 8 ++++++++ include/znc/User.h | 4 ++-- src/IRCNetwork.cpp | 13 ++++++++++++- src/IRCSock.cpp | 4 ++-- src/Socket.cpp | 7 ++++++- src/User.cpp | 20 ++++++++++++++++++-- 6 files changed, 48 insertions(+), 8 deletions(-) diff --git a/include/znc/IRCNetwork.h b/include/znc/IRCNetwork.h index 3b7130c2..229748f3 100644 --- a/include/znc/IRCNetwork.h +++ b/include/znc/IRCNetwork.h @@ -196,6 +196,12 @@ public: unsigned short int GetJoinDelay() const { return m_uJoinDelay; } void SetJoinDelay(unsigned short int uJoinDelay) { m_uJoinDelay = uJoinDelay; } + unsigned long long BytesRead() const { return m_uBytesRead; } + unsigned long long BytesWritten() const { return m_uBytesWritten; } + + void AddBytesRead(unsigned long long u) { m_uBytesRead += u; } + void AddBytesWritten(unsigned long long u) { m_uBytesWritten += u; } + CString ExpandString(const CString& sStr) const; CString& ExpandString(const CString& sStr, CString& sRet) const; private: @@ -245,6 +251,8 @@ protected: CIRCNetworkJoinTimer* m_pJoinTimer; unsigned short int m_uJoinDelay; + unsigned long long m_uBytesRead; + unsigned long long m_uBytesWritten; }; #endif // !ZNC_IRCNETWORK_H diff --git a/include/znc/User.h b/include/znc/User.h index 84018e45..dc7c29e0 100644 --- a/include/znc/User.h +++ b/include/znc/User.h @@ -187,8 +187,8 @@ public: bool AutoClearQueryBuffer() const; bool IsBeingDeleted() const { return m_bBeingDeleted; } CString GetTimezone() const { return m_sTimezone; } - unsigned long long BytesRead() const { return m_uBytesRead; } - unsigned long long BytesWritten() const { return m_uBytesWritten; } + unsigned long long BytesRead() const; + unsigned long long BytesWritten() const; unsigned int JoinTries() const { return m_uMaxJoinTries; } unsigned int MaxJoins() const { return m_uMaxJoins; } CString GetSkinName() const; diff --git a/src/IRCNetwork.cpp b/src/IRCNetwork.cpp index 3cb96d63..2ef36d6e 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 f8e835b2..fff8c4c3 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 3991b3b0..13cfa3e6 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 @@ -1277,3 +1277,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; +} From 66053e24ff8dd4b3aa5071b89773da6f6c3c8249 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 7 Aug 2015 12:43:29 +0200 Subject: [PATCH 2/4] Add CZNC::GetNetworkTrafficStats() --- include/znc/znc.h | 1 + src/znc.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/znc/znc.h b/include/znc/znc.h index 5dba289d..2c50d590 100644 --- a/include/znc/znc.h +++ b/include/znc/znc.h @@ -92,6 +92,7 @@ public: // generated through ZNC. TrafficStatsMap GetTrafficStats(TrafficStatsPair &Users, TrafficStatsPair &ZNC, TrafficStatsPair &Total); + TrafficStatsMap GetNetworkTrafficStats(const CString& sUsername, TrafficStatsPair& Total); // Authenticate a user. // The result is passed back via callbacks to CAuthBase. diff --git a/src/znc.cpp b/src/znc.cpp index c1f0d2fa..7e79f07f 100644 --- a/src/znc.cpp +++ b/src/znc.cpp @@ -1753,6 +1753,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; From c36aa6c832e12416d1414d0a98fd442d70af4534 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 7 Aug 2015 13:26:04 +0200 Subject: [PATCH 3/4] webadmin: show per-network traffic info Close #963 --- modules/data/webadmin/tmpl/traffic.tmpl | 61 ++++++++++++++++--------- modules/webadmin.cpp | 11 +++++ 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/modules/data/webadmin/tmpl/traffic.tmpl b/modules/data/webadmin/tmpl/traffic.tmpl index 368f09b4..81d26c5b 100644 --- a/modules/data/webadmin/tmpl/traffic.tmpl +++ b/modules/data/webadmin/tmpl/traffic.tmpl @@ -40,51 +40,70 @@ - +
-

Traffic

+

Total

- + - - - - - - - - Add the totals separately so that if sort is ever used they stay at the bottom - By keeping them inside the loop we can figure out even/odd classes though. - - - - + + - - + + - - + + - + +
Username In Out Total
User Total
Users
ZNC Total
ZNC
Grand Total
Total
+
+
+
+ + + +
+

Users

+
+
+ + + + + + + + + + + + + + + + + + +
UsernameNetworkInOutTotal
diff --git a/modules/webadmin.cpp b/modules/webadmin.cpp index 6d6ca7ed..afc967b8 100644 --- a/modules/webadmin.cpp +++ b/modules/webadmin.cpp @@ -1475,6 +1475,17 @@ public: 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); From 013203cfb5a564b2c697f6f38f244c0050c6e120 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 22 Aug 2015 01:59:08 +0200 Subject: [PATCH 4/4] webadmin: make the traffic info page visible for non-admins --- modules/data/webadmin/tmpl/traffic.tmpl | 23 ++++++++++++++++++++++- modules/webadmin.cpp | 14 ++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/modules/data/webadmin/tmpl/traffic.tmpl b/modules/data/webadmin/tmpl/traffic.tmpl index 81d26c5b..d9641481 100644 --- a/modules/data/webadmin/tmpl/traffic.tmpl +++ b/modules/data/webadmin/tmpl/traffic.tmpl @@ -33,6 +33,23 @@ Total IRC Connections + + + Networks + + + + Attached Networks + + + + Client Connections + + + + IRC Connections + + @@ -80,9 +97,13 @@
- +
+

Users

+ +

Traffic

+
diff --git a/modules/webadmin.cpp b/modules/webadmin.cpp index afc967b8..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,6 +1475,10 @@ 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;