diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2c73ee08c3..434a6cb94d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -85,6 +85,7 @@ set(SHARED_SOURCES "crypto/CryptographicHash.cpp" "crypto/CryptographicRandom.cpp" + "crypto/CryptState.cpp" "crypto/CryptStateOCB2.cpp" "${3RDPARTY_DIR}/arc4random/arc4random_uniform.cpp" diff --git a/src/Mumble.proto b/src/Mumble.proto index 169c18a692..bfcd4c362c 100644 --- a/src/Mumble.proto +++ b/src/Mumble.proto @@ -553,6 +553,12 @@ message UserStats { // True if the user has a strong certificate. optional bool strong_certificate = 18 [default = false]; optional bool opus = 19 [default = false]; + + optional uint32 rolling_time = 20; + // Rolling packet statistics for packets received from the client. + optional Stats rolling_from_client = 21; + // Rolling packet statistics for packets sent by the server. + optional Stats rolling_from_server = 22; } // Used by the client to request binary data from the server. By default large diff --git a/src/crypto/CryptState.cpp b/src/crypto/CryptState.cpp new file mode 100644 index 0000000000..29e091fc5c --- /dev/null +++ b/src/crypto/CryptState.cpp @@ -0,0 +1,39 @@ +// Copyright The Mumble Developers. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file at the root of the +// Mumble source tree or at . + +#include "CryptState.h" + +void CryptState::handleRollingStats() { + // Update every 5 seconds + if (!m_rollingTimer.isElapsed(1000000ULL * m_rollingScanInterval) && !m_statsLocalReference.empty() + && !m_statsRemoteReference.empty()) { + return; + } + + m_rollingTimer.restart(); + + m_statsLocalReference.push(m_statsLocal); + m_statsRemoteReference.push(m_statsRemote); + + uint32_t maxEntries = m_rollingWindow / m_rollingScanInterval; + + while (m_statsLocalReference.size() > maxEntries) { + m_statsLocalReference.pop(); + } + + while (m_statsRemoteReference.size() > maxEntries) { + m_statsRemoteReference.pop(); + } + + m_statsLocalRolling.good = m_statsLocal.good - m_statsLocalReference.front().good; + m_statsLocalRolling.late = m_statsLocal.late - m_statsLocalReference.front().late; + m_statsLocalRolling.lost = m_statsLocal.lost - m_statsLocalReference.front().lost; + m_statsLocalRolling.resync = m_statsLocal.resync - m_statsLocalReference.front().resync; + + m_statsRemoteRolling.good = m_statsRemote.good - m_statsRemoteReference.front().good; + m_statsRemoteRolling.late = m_statsRemote.late - m_statsRemoteReference.front().late; + m_statsRemoteRolling.lost = m_statsRemote.lost - m_statsRemoteReference.front().lost; + m_statsRemoteRolling.resync = m_statsRemote.resync - m_statsRemoteReference.front().resync; +} diff --git a/src/crypto/CryptState.h b/src/crypto/CryptState.h index 6a9dc66ae7..2554b5881e 100644 --- a/src/crypto/CryptState.h +++ b/src/crypto/CryptState.h @@ -7,21 +7,37 @@ #define MUMBLE_CRYPTSTATE_H_ #include "Timer.h" +#include #include struct PacketStats { - unsigned int good = 0; - unsigned int late = 0; - unsigned int lost = 0; - unsigned int rsync = 0; + unsigned int good = 0; + unsigned int late = 0; + unsigned int lost = 0; + unsigned int resync = 0; }; class CryptState { private: Q_DISABLE_COPY(CryptState) + + const uint32_t m_rollingScanInterval = 5; + Timer m_rollingTimer; + + std::queue< PacketStats > m_statsLocalReference; + std::queue< PacketStats > m_statsRemoteReference; + +protected: + void handleRollingStats(); + public: - PacketStats m_statsLocal = {}; - PacketStats m_statsRemote = {}; + PacketStats m_statsLocal = {}; + PacketStats m_statsRemote = {}; + PacketStats m_statsLocalRolling = {}; + PacketStats m_statsRemoteRolling = {}; + + /// This is the packet statistics sliding time window size in seconds + uint32_t m_rollingWindow = 60 * 5; Timer tLastGood; Timer tLastRequest; diff --git a/src/crypto/CryptStateOCB2.cpp b/src/crypto/CryptStateOCB2.cpp index 733ee12a4d..9b1c5d763d 100644 --- a/src/crypto/CryptStateOCB2.cpp +++ b/src/crypto/CryptStateOCB2.cpp @@ -220,6 +220,7 @@ bool CryptStateOCB2::decrypt(const unsigned char *source, unsigned char *dst, un m_statsLocal.lost -= static_cast< unsigned int >(std::abs(lost)); } + handleRollingStats(); tLastGood.restart(); return true; } diff --git a/src/mumble/UserInformation.cpp b/src/mumble/UserInformation.cpp index a735763f31..95d5a8031c 100644 --- a/src/mumble/UserInformation.cpp +++ b/src/mumble/UserInformation.cpp @@ -163,8 +163,12 @@ void UserInformation::update(const MumbleProto::UserStats &msg) { qlTCPVar->setText(QString::number(msg.tcp_ping_var() > 0.0f ? sqrtf(msg.tcp_ping_var()) : 0.0f, 'f', 2)); qlUDPVar->setText(QString::number(msg.udp_ping_var() > 0.0f ? sqrtf(msg.udp_ping_var()) : 0.0f, 'f', 2)); - if (msg.has_from_client() && msg.has_from_server()) { - qgbUDP->setVisible(true); + bool hasTotalStats = msg.has_from_client() && msg.has_from_server(); + bool hasRollingStats = msg.has_rolling_time() && msg.has_rolling_from_client() && msg.has_rolling_from_server(); + + qgbUDP->setVisible(hasTotalStats || hasRollingStats); + + if (hasTotalStats) { const MumbleProto::UserStats_Stats &from = msg.from_client(); qlFromGood->setText(QString::number(from.good())); qlFromLate->setText(QString::number(from.late())); @@ -186,8 +190,40 @@ void UserInformation::update(const MumbleProto::UserStats &msg) { quint32 allToPackets = to.good() + to.late() + to.lost(); qlToLatePercent->setText(QString::number(allToPackets > 0 ? to.late() * 100.0 / allToPackets : 0., 'f', 2)); qlToLostPercent->setText(QString::number(allToPackets > 0 ? to.lost() * 100.0 / allToPackets : 0., 'f', 2)); - } else { - qgbUDP->setVisible(false); + } + + if (hasRollingStats) { + const MumbleProto::UserStats_Stats &from = msg.rolling_from_client(); + qlFromGoodRolling->setText(QString::number(from.good())); + qlFromLateRolling->setText(QString::number(from.late())); + qlFromLostRolling->setText(QString::number(from.lost())); + qlFromResyncRolling->setText(QString::number(from.resync())); + + const MumbleProto::UserStats_Stats &to = msg.rolling_from_server(); + qlToGoodRolling->setText(QString::number(to.good())); + qlToLateRolling->setText(QString::number(to.late())); + qlToLostRolling->setText(QString::number(to.lost())); + qlToResyncRolling->setText(QString::number(to.resync())); + + quint32 allFromPackets = from.good() + from.late() + from.lost(); + qlFromLatePercentRolling->setText( + QString::number(allFromPackets > 0 ? from.late() * 100.0 / allFromPackets : 0., 'f', 2)); + qlFromLostPercentRolling->setText( + QString::number(allFromPackets > 0 ? from.lost() * 100.0 / allFromPackets : 0., 'f', 2)); + + quint32 allToPackets = to.good() + to.late() + to.lost(); + qlToLatePercentRolling->setText( + QString::number(allToPackets > 0 ? to.late() * 100.0 / allToPackets : 0., 'f', 2)); + qlToLostPercentRolling->setText( + QString::number(allToPackets > 0 ? to.lost() * 100.0 / allToPackets : 0., 'f', 2)); + + uint32_t rollingSeconds = msg.rolling_time(); + QString rollingText = tr("Last %1 %2:"); + if (rollingSeconds < 120) { + qliRolling->setText(rollingText.arg(QString::number(rollingSeconds)).arg(tr("seconds"))); + } else { + qliRolling->setText(rollingText.arg(QString::number(rollingSeconds / 60)).arg(tr("minutes"))); + } } if (msg.has_onlinesecs()) { diff --git a/src/mumble/UserInformation.ui b/src/mumble/UserInformation.ui index 54c8374f8c..a58a613ec4 100644 --- a/src/mumble/UserInformation.ui +++ b/src/mumble/UserInformation.ui @@ -7,7 +7,7 @@ 0 0 488 - 658 + 713 @@ -39,10 +39,10 @@ - Qt::PlainText + Qt::TextFormat::PlainText - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -94,7 +94,7 @@ - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -110,10 +110,10 @@ - Qt::PlainText + Qt::TextFormat::PlainText - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -165,10 +165,10 @@ - Qt::PlainText + Qt::TextFormat::PlainText - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -194,7 +194,7 @@ Pings received - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -204,7 +204,7 @@ Average ping - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -214,7 +214,7 @@ Ping deviation - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -231,10 +231,10 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -244,10 +244,10 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -257,10 +257,10 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -277,10 +277,10 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -290,10 +290,10 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -303,10 +303,10 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -319,23 +319,36 @@ UDP Network statistics - - + + - Good + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + - Late + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -345,24 +358,30 @@ Lost - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + - Resync + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + - From Client + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -372,49 +391,127 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse - - + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + From Client - - + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + Resync + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse + + + + + + + % + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + From Client + + + + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + Late + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -425,42 +522,66 @@ - - + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + % + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -470,60 +591,80 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse - - + + - % + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse - - + + - % + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + + + Qt::Orientation::Horizontal + + + + + - + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse - - + + - + Good - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + - + To Client + + + + + + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -533,7 +674,14 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + Last X minutes: @@ -565,7 +713,7 @@ - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -588,7 +736,7 @@ - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse diff --git a/src/murmur/Messages.cpp b/src/murmur/Messages.cpp index 8d0dc3abd2..2a5c5ee79b 100644 --- a/src/murmur/Messages.cpp +++ b/src/murmur/Messages.cpp @@ -2285,6 +2285,20 @@ void Server::msgUserStats(ServerUser *uSource, MumbleProto::UserStats &msg) { mpusss->set_late(pDstServerUser->csCrypt->m_statsRemote.late); mpusss->set_lost(pDstServerUser->csCrypt->m_statsRemote.lost); mpusss->set_resync(pDstServerUser->csCrypt->m_statsRemote.resync); + + mpusss = msg.mutable_rolling_from_client(); + mpusss->set_good(pDstServerUser->csCrypt->m_statsLocalRolling.good); + mpusss->set_late(pDstServerUser->csCrypt->m_statsLocalRolling.late); + mpusss->set_lost(pDstServerUser->csCrypt->m_statsLocalRolling.lost); + mpusss->set_resync(pDstServerUser->csCrypt->m_statsLocalRolling.resync); + + mpusss = msg.mutable_rolling_from_server(); + mpusss->set_good(pDstServerUser->csCrypt->m_statsRemoteRolling.good); + mpusss->set_late(pDstServerUser->csCrypt->m_statsRemoteRolling.late); + mpusss->set_lost(pDstServerUser->csCrypt->m_statsRemoteRolling.lost); + mpusss->set_resync(pDstServerUser->csCrypt->m_statsRemoteRolling.resync); + + msg.set_rolling_time(pDstServerUser->csCrypt->m_statsLocalReference.size()); } msg.set_udp_packets(pDstServerUser->uiUDPPackets);