// // 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 #include #include #include #include #include #if defined(GNULIBC) || defined(__GLIBC__) #include #else #include #endif #include #include #include #include #include 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 : " <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 : " <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]; } }