//
// Copyright (c) 1994, 1995, 2002, 2006 by Mike Romberg ( mike.romberg@noaa.gov )
//
// Modifications to support dynamic addresses by:
// Michael N. Lipp (mnl@dtro.e-technik.th-darmstadt.de)
//
// This file may be distributed under terms of the GPL
//
//
// $Id$
//
//-----------------------------------------------------------------------
//
// To use this meter, ipaccounting needs to be configured in the kernel and
// accounting needs to be set up. Here are a couple of lines from my
// rc.local which add ip accounting on all packets to and from my ip
// address (192.168.0.3):
//
// /sbin/ipfw add accounting all iface 192.168.0.3 from 192.168.0.3 to 0/0
// /sbin/ipfw add accounting all iface 192.168.0.3 from 0/0 to 192.168.0.3
//
// If you have more than one ip address you can add lines similar to the
// ones above for the other addresses and this class will combine them in
// its display.
//-----------------------------------------------------------------------
#include "netmeter.h"
#include "xosview.h"
#include <unistd.h>
#include <fstream>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#if defined(GNULIBC) || defined(__GLIBC__)
#include <net/if.h>
#else
#include <linux/if.h>
#endif
#include <netinet/in.h>
#include <errno.h>
#include <iostream>
#include <iomanip>
#include <string>
NetMeter::NetMeter( XOSView *parent, float max )
: FieldMeterGraph( parent, 3, "NET", "IN/OUT/IDLE" ){
_timer.start();
maxpackets_ = max;
_lastBytesIn = _lastBytesOut = 0;
_usechains = false;
checkOSVersion();
}
NetMeter::~NetMeter( void ){
close (_ipsock);
}
void NetMeter::checkOSVersion(void)
{
std::ifstream ifs("/proc/sys/kernel/osrelease");
if (!ifs)
{
std::cerr <<"Can not open file : " << "/proc/sys/kernel/osrelease"
<< std::endl;
exit(1);
}
int major, minor;
_bytesInDev = 0;
ifs >> major;
ifs.ignore(1);
ifs >> minor;
ifs.ignore(1);
if (major > 2 || (major == 2 && minor >= 1))
{
// check presence of iacct and oacct chains
std::ifstream chains("/proc/net/ip_fwchains");
int n = 0;
char buf[1024];
while (chains && !chains.eof())
{
chains >> buf;
chains.ignore(1024, '\n');
if (!strncmp(buf, "iacct", 5))
n |= 1;
if (!strncmp(buf, "oacct", 5))
n |= 2;
}
if (n == 3)
{
_netfilename = "/proc/net/ip_fwchains";
_usechains = true;
}
else
_netfilename = "/proc/net/dev";
_bytesInDev = 1;
}
else
_netfilename = "/proc/net/ip_acct";
}
void NetMeter::checkResources( void ){
FieldMeterGraph::checkResources();
setfieldcolor( 0, parent_->getResource( "netInColor" ) );
setfieldcolor( 1, parent_->getResource( "netOutColor" ) );
setfieldcolor( 2, parent_->getResource( "netBackground" ) );
priority_ = atoi (parent_->getResource( "netPriority" ) );
useGraph_ = parent_->isResourceTrue( "netGraph" );
dodecay_ = parent_->isResourceTrue( "netDecay" );
SetUsedFormat (parent_->getResource("netUsedFormat"));
netIface_ = parent_->getResource( "netIface" );
_ipsock = socket(AF_INET, SOCK_DGRAM, 0);
if (_ipsock == -1) {
std::cerr <<"Can not open socket : " <<strerror( errno ) << std::endl;
parent_->done(1);
return;
}
}
void NetMeter::checkevent(void)
{
if (_bytesInDev)
checkeventNew();
else
checkeventOld();
}
void NetMeter::checkeventNew(void)
{
std::ifstream ifs(_netfilename);
if (!ifs)
{
std::cerr <<"Can not open file : " <<_netfilename << std::endl;
parent_->done(1);
return;
}
std::string str_in;
unsigned long long in, out, ig;
unsigned long long totin = 0, totout = 0;
char buf[1024];
fields_[2] = maxpackets_; // assume no
fields_[0] = fields_[1] = 0; // network activity
_timer.stop();
if (_usechains)
while (ifs)
{
ifs >> buf;
if (!strncmp(buf, "iacct", 5))
ifs >> buf >> buf >> ig >> ig >> ig >> ig >> ig >> ig >> totin;
else if (!strncmp(buf, "oacct", 5))
ifs >> buf >> buf >> ig >> ig >> ig >> ig >> ig >> ig >> totout;
ifs.ignore(1024, '\n');
}
else
{
std::string ifname;
ifs.ignore(1024, '\n');
ifs.ignore(1024, '\n');
while (ifs)
{
if (netIface_ == "False" )
{
ifs.ignore(1024, ':');
}
else
{
ifs.get(buf, 128, ':');
ifname = buf;
ifs.ignore(1, ':');
ifname.erase(0, ifname.find_first_not_of(" ") );
if (ifname != netIface_)
{
ifs.ignore(1024,'\n');
continue;
}
}
ifs >> str_in;
if (str_in == "No")
continue;
else
{
in = strtoull(str_in.c_str(), NULL, 10);
ifs >> ig >> ig >> ig >> ig >> ig >> ig >> ig >> out;
}
if (!ifs.eof())
{
totin += in;
totout += out;
}
ifs.ignore(1024, '\n');
}
}
float t = 1000000.0 / _timer.report_usecs();
if (t < 0)
t = 0.1;
fields_[0] = (totin - _lastBytesIn) * t;
fields_[1] = (totout - _lastBytesOut) * t;
_lastBytesIn = totin;
_lastBytesOut = totout;
adjust();
if (total_)
setUsed(fields_[0] + fields_[1], total_);
_timer.start();
drawfields();
}
void NetMeter::checkeventOld(void)
{
_timer.stop();
fields_[2] = maxpackets_; // assume no
fields_[0] = fields_[1] = 0; // network activity
std::ifstream ifs(_netfilename);
if (!ifs)
{
std::cerr <<"Can not open file : " << _netfilename << std::endl;
parent_->done(1);
return;
}
struct ifconf ifc;
char buff[1024];
ifc.ifc_len = sizeof(buff);
ifc.ifc_buf = buff;
if (ioctl(_ipsock, SIOCGIFCONF, &ifc) < 0)
{
std::cerr <<"Can not get interface list : " <<strerror( errno )
<< std::endl;
parent_->done(1);
return;
}
char c;
unsigned long long sa, da, sm, dm, bytes;
unsigned long long tot_in = 0, tot_out = 0;
ifs.ignore(1024, '\n');
while (ifs)
{
ifs >> std::hex >> sa >> c >> sm >> c >> c >> da >> c >> dm;
for (int index = 0 ; index < 7 ; index++)
ifs.ignore(9999, ' ');
ifs >> std::dec >> bytes;
ifs.ignore(9999, '\n');
if (!ifs.eof())
{
struct ifreq *ifr = ifc.ifc_req;
for (int i = ifc.ifc_len / sizeof(struct ifreq);
--i >= 0; ifr++)
{
unsigned long adr = ntohl(
((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr);
if (sm == 0 && da == adr)
{
tot_in += bytes;
break;
}
if (dm == 0 && sa == adr)
{
tot_out += bytes;
break;
}
}
}
}
// This will happen when a dynamic connection (SLIP/PPP) goes down.
if ((tot_in < _lastBytesIn) || (tot_out < _lastBytesOut))
{
fields_[0] = fields_[1] = 0;
_lastBytesIn = tot_in;
_lastBytesOut = tot_out;
}
else
{
float t = 1000000.0 / _timer.report_usecs();
if (t < 0) // can happen when system clock is reset. (ntp, timed, etc)
t = 0.1;
fields_[0] = (tot_in - _lastBytesIn) * t;
fields_[1] = (tot_out - _lastBytesOut) * t;
_lastBytesIn = tot_in;
_lastBytesOut = tot_out;
}
adjust();
if (total_)
setUsed(fields_[0] + fields_[1], total_);
_timer.start();
drawfields();
}
void NetMeter::adjust(void)
{
total_ = fields_[0] + fields_[1];
if (total_ > maxpackets_)
fields_[2] = 0;
else
{
total_ = maxpackets_;
fields_[2] = total_ - fields_[0] - fields_[1];
}
}
syntax highlighted by Code2HTML, v. 0.9.1