diff options
Diffstat (limited to 'statistics.cpp')
-rw-r--r-- | statistics.cpp | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/statistics.cpp b/statistics.cpp new file mode 100644 index 0000000..800a4e5 --- /dev/null +++ b/statistics.cpp @@ -0,0 +1,160 @@ +#include "config.h" +#include "statistics.hpp" +#include <algorithm> +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <sys/time.h> + +#include <iostream> +#include <sstream> + +#define PROC_NET_DEV "/proc/net/dev" + +namespace statistics { + +Interface::Interface(const std::string& name) : name_(name), updated_(false) {} + +class InterfaceNameMatchesPredicate { + public: + InterfaceNameMatchesPredicate(const std::string& name) : name_(name) {} + + bool operator() (const Interface& interface) const { + return name_ == interface.getName(); + } + private: + std::string name_; +}; + +class InterfaceNotUpdatedPredicate { + public: + bool operator() (const Interface& interface) const { + return !interface.getUpdated(); + } +}; + +void Interface::update(const Statistics& statistics) { + memcpy(statistics_ + 1, statistics_ + 0, sizeof(Statistics)); + memcpy(statistics_, &statistics, sizeof(Statistics)); + + const Statistics& x0 = statistics_[1]; + const Statistics& x1 = statistics_[0]; + + double timeDelta = + (x1.timestamp.tv_sec - x0.timestamp.tv_sec) * 1. + + (x1.timestamp.tv_usec - x0.timestamp.tv_usec) * .000001; + + receiveSpeed_ = (x1.rx_bytes - x0.rx_bytes) / timeDelta; + transmitSpeed_ = (x1.tx_bytes - x0.tx_bytes) / timeDelta; + + updated_ = true; +} + +void Reader::update() { + // Open /proc/net/dev + FILE *dev = fopen(PROC_NET_DEV, "r"); + if (!dev) { + std::cerr << "cannot open " << PROC_NET_DEV << "\n"; + exit(EXIT_FAILURE); + } + + try { + // Clear the 'updated' flag for all interfaces + for (Interfaces::iterator interface = interfaces_.begin(); + interface != interfaces_.end(); ++interface) + interface->setUpdated(false); + + // Read /proc/dev/net + while (!feof(dev)) { + char buf[500]; + char *name, *statistics_string; + Statistics stats; + struct timezone unused_timezone; + + // Read a line + fgets(buf, sizeof(buf), dev); + gettimeofday(&stats.timestamp, &unused_timezone); + + // Find the colon separating the name from the statistics + statistics_string = strchr(buf, ':'); + if (!statistics_string) continue; + + // Get a pointer to the statistics + *statistics_string = 0; + ++statistics_string; + + // Remove leading whitespace from the name + name = buf; + while (*name == ' ' || *name == '\t') ++name; + + // Parse the statistics + if (sscanf(statistics_string, "%Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu " + "%Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu", + &stats.rx_bytes, &stats.rx_packets, + &stats.rx_errs, &stats.rx_drop, + &stats.rx_fifo, &stats.rx_frame, + &stats.rx_compressed, &stats.rx_multicast, + &stats.tx_bytes, &stats.tx_packets, + &stats.tx_errs, &stats.tx_drop, + &stats.tx_fifo, &stats.tx_frame, + &stats.tx_compressed, &stats.tx_multicast) + == 16) { + + // Find the interface with the same name + Interfaces::iterator interface + = std::find_if(interfaces_.begin(), interfaces_.end(), + InterfaceNameMatchesPredicate(name)); + + if (interface == interfaces_.end()) { + // This is a new interface; add it to the list + interfaces_.push_back(Interface(name)); + interface = interfaces_.end(); + --interface; + } + + // Update the interface + interface->update(stats); + } + } + + // Remove all interfaces for which the updated flag was not set + interfaces_.remove_if(InterfaceNotUpdatedPredicate()); + + // Close the file + fclose(dev); + } + catch (...) { + fclose(dev); + throw; + } +} + +void Interface::setUpdated(bool updated) { + updated_ = updated; +} + +bool Interface::getUpdated() const { + return updated_; +} + +const std::string& Interface::getName() const { + return name_; +} + +double Interface::getReceiveSpeed() const { + return receiveSpeed_; +} + +double Interface::getTransmitSpeed() const { + return transmitSpeed_; +} + +const Reader::Interfaces& Reader::getInterfaces() const { + return interfaces_; +} + +} // namespace statistics |