/*! \file pidiagnostics.h * \ingroup IO * \~\brief * \~english Connection quality diagnostics * \~russian Диагностика качества связи */ /* PIP - Platform Independent Primitives Speed and quality in/out diagnostics Andrey Bychkov work.a.b@yandex.ru, Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PIDIAGNOSTICS_H #define PIDIAGNOSTICS_H #include "piqueue.h" #include "pitimer.h" class PIP_EXPORT PIDiagnostics: public PITimer { PIOBJECT_SUBCLASS(PIDiagnostics, PITimer); friend class PIConnection; public: NO_COPY_CLASS(PIDiagnostics); //! Constructs an empty diagnostics and if "start_" start it PIDiagnostics(bool start_ = true); virtual ~PIDiagnostics(); //! Connection quality enum Quality { Unknown /** Unknown, no one packet received yet */ = 1, Failure /** No connection, no one correct packet received for last period */ = 2, Bad /** Bad connection, correct packets received <= 20% */ = 3, Average /** Average connection, correct packets received > 20% and <= 80% */ = 4, Good /** Good connection, correct packets received > 80% */ = 5 }; //! Information about current diagnostics state struct PIP_EXPORT State { State(); float immediate_freq; float integral_freq; ullong received_packets_per_sec; ullong received_packets; ullong received_packets_wrong; ullong received_bytes_per_sec; ullong received_bytes; ullong received_bytes_wrong; ullong sended_packets_per_sec; ullong sended_packets; ullong sended_bytes_per_sec; ullong sended_bytes; PIString receive_speed; PIString send_speed; PIDiagnostics::Quality quality; }; //! Returns current state PIDiagnostics::State state() const; //! Returns period of full disconnect in seconds and period of averaging frequency float disconnectTimeout() const { return disconn_; } //! Returns period of full disconnect in seconds and period of averaging frequency void setDisconnectTimeout(float s) { setProperty("disconnectTimeout", s); } //! Returns connection quality PIDiagnostics::Quality quality() const; //! Returns receive speed in format "n {B|kB|MB|GB|TB}/s" PIString receiveSpeed() const; //! Returns send speed in format "n {B|kB|MB|GB|TB}/s" PIString sendSpeed() const; EVENT_HANDLER0(void, start) { PITimer::start(100.); changeDisconnectTimeout(disconn_); } EVENT_HANDLER1(void, start, double, msecs) { if (msecs > 0.) { PITimer::start(msecs); changeDisconnectTimeout(disconn_); } } EVENT_HANDLER0(void, reset); EVENT_HANDLER1(void, received, int, size) { received(size, true); } EVENT_HANDLER2(void, received, int, size, bool, correct); EVENT_HANDLER1(void, sended, int, size); EVENT2(qualityChanged, PIDiagnostics::Quality, new_quality, PIDiagnostics::Quality, old_quality); //! \handlers //! \{ //! \fn void start(double msecs = 1000.) //! \brief Start diagnostics evaluations with period "msecs" milliseconds //! \fn void reset() //! \brief Reset diagnostics counters //! \fn void received(int size, bool correct = true) //! \brief Notify diagnostics about "correct" corected received packet //! \fn void sended(int size) //! \brief Notify diagnostics about sended packet //! \} //! \events //! \{ //! \fn void qualityChanged(PIDiagnostics::Quality new_quality, PIDiagnostics::Quality old_quality) //! \brief Raise on change receive quality from "old_quality" to "new_quality" //! \} private: struct PIP_EXPORT Entry { Entry() { bytes_ok = bytes_fail = 0; cnt_ok = cnt_fail = 0; empty = true; } ullong bytes_ok; ullong bytes_fail; uint cnt_ok; uint cnt_fail; bool empty; }; friend bool operator==(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s); friend bool operator!=(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s); friend bool operator<(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s); void tick(void *, int) override; Entry calcHistory(PIQueue & hist, int & cnt); void propertyChanged(const char *) override; void changeDisconnectTimeout(float disct); PIQueue history_rec, history_send; float disconn_; State cur_state; mutable PIMutex mutex_state; }; inline bool operator==(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s) { return f.bytes_ok == s.bytes_ok && f.bytes_fail == s.bytes_fail && f.cnt_ok == s.cnt_ok && f.cnt_fail == s.cnt_fail && f.empty == s.empty; } inline bool operator!=(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s) { return !(f == s); } inline bool operator<(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s) { return f.bytes_ok < s.bytes_ok; } #endif // PIDIAGNOSTICS_H