You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeutils/ksim/monitors/net/ksimnet.cpp

673 lines
15 KiB

/* ksim - a system monitor for kde
*
* Copyright (C) 2001 Robbie Ward <linuxphreak@gmx.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#ifdef __FreeBSD__
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
static int mib[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
#endif
#include <tqpushbutton.h>
#include <tqtextstream.h>
#include <tqfile.h>
#include <tqdatetime.h>
#include <tqlayout.h>
#include <tqtimer.h>
#include <tqregexp.h>
#include <tqcursor.h>
#include <tqpopupmenu.h>
#include <kdebug.h>
#include <klocale.h>
#include <kaboutapplication.h>
#include <kaboutdata.h>
#include <ksimpleconfig.h>
#include <kglobal.h>
#include <krun.h>
#include <kapplication.h>
#include <kiconloader.h>
#include "ksimnet.h"
#include "netconfig.h"
#include <themetypes.h>
#define NET_UPDATE 1000
#define LED_UPDATE 125
KSIM_INIT_PLUGIN(NetPlugin)
NetPlugin::NetPlugin(const char *name)
: KSim::PluginObject(name)
{
setConfigFileName(instanceName());
}
NetPlugin::~NetPlugin()
{
}
KSim::PluginView *NetPlugin::createView(const char *className)
{
return new NetView(this, className);
}
KSim::PluginPage *NetPlugin::createConfigPage(const char *className)
{
return new NetConfig(this, className);
}
void NetPlugin::showAbout()
{
TQString version = kapp->aboutData()->version();
TDEAboutData aboutData(instanceName(),
I18N_NOOP("KSim Net Plugin"), version.latin1(),
I18N_NOOP("A net plugin for KSim"),
TDEAboutData::License_GPL, "(C) 2001 Robbie Ward");
aboutData.addAuthor("Robbie Ward", I18N_NOOP("Author"),
"linuxphreak@gmx.co.uk");
aboutData.addAuthor("Heitham Omar", I18N_NOOP("FreeBSD ports"),
"super_ice@ntlworld.com");
KAboutApplication(&aboutData).exec();
}
NetView::NetView(KSim::PluginObject *parent, const char *name)
: KSim::PluginView(parent, name)
{
#ifdef __linux__
m_procStream = 0L;
if ((m_procFile = fopen("/proc/net/dev", "r")))
m_procStream = new TQTextStream(m_procFile, IO_ReadOnly);
#endif
#ifdef __FreeBSD__
m_buf = 0;
m_allocSize = 0;
#endif
m_firstTime = true;
m_netLayout = new TQVBoxLayout(this);
m_networkList = createList();
addDisplay();
m_netTimer = new TQTimer(this);
connect(m_netTimer, TQT_SIGNAL(timeout()), TQT_SLOT(updateGraph()));
m_netTimer->start(NET_UPDATE);
m_lightTimer = new TQTimer(this);
connect(m_lightTimer, TQT_SIGNAL(timeout()), TQT_SLOT(updateLights()));
m_lightTimer->start(LED_UPDATE);
updateGraph();
}
NetView::~NetView()
{
#ifdef __linux__
delete m_procStream;
if (m_procFile)
fclose(m_procFile);
#endif
cleanup();
}
void NetView::reparseConfig()
{
Network::List networkList = createList();
if ( networkList == m_networkList )
return;
m_netTimer->stop();
m_lightTimer->stop();
m_firstTime = true;
cleanup();
m_networkList = networkList;
addDisplay();
m_netTimer->start(NET_UPDATE);
m_lightTimer->start(LED_UPDATE);
}
void NetView::cleanup()
{
Network::List::Iterator it;
for ( it = m_networkList.begin(); it != m_networkList.end(); ++it )
{
( *it ).cleanup();
}
m_networkList.clear();
}
void NetView::addDisplay()
{
int i = 0;
Network::List::Iterator it;
for ( it = m_networkList.begin(); it != m_networkList.end(); ++it )
{
KSim::LedLabel *led = addLedLabel( ( *it ).name() );
KSim::Label *label = ( ( *it ).showTimer() ? addLabel() : 0L );
TQPopupMenu * popup = ( ( *it ).commandsEnabled() ?
addPopupMenu( ( *it ).name(), i ) : 0L );
KSim::Chart *chart = addChart();
//KSim::LedLabel *led = addLedLabel( ( *it ).name() );
//KSim::Label *label = ( ( *it ).showTimer() ? addLabel() : 0L );
//TQPopupMenu * popup = ( ( *it ).commandsEnabled() ?
//addPopupMenu( ( *it ).name(), i ) : 0L );
if ( ( *it ).commandsEnabled() )
{
if ( chart )
{
chart->installEventFilter( this );
}
if ( led )
{
led->installEventFilter( this );
}
if ( label )
{
label->installEventFilter( this );
}
}
( *it ).setDisplay( chart, led, label, popup );
++i;
}
}
// Run the connect command
void NetView::runConnectCommand( int value )
{
int i = 0;
Network::List::ConstIterator it;
for ( it = m_networkList.begin(); it != m_networkList.end(); ++it )
{
if ( value == i )
{
// I use KRun here as it provides startup notification
if ( !( *it ).connectCommand().isNull() )
{
KRun::runCommand( ( *it ).connectCommand() );
}
break;
}
++i;
}
}
// Run the disconnect command
void NetView::runDisconnectCommand( int value )
{
int i = 0;
Network::List::ConstIterator it;
for ( it = m_networkList.begin(); it != m_networkList.end(); ++it )
{
if ( value == i )
{
// I use KRun here as it provides startup notification
if ( !( *it ).disconnectCommand().isNull() )
{
KRun::runCommand( ( *it ).disconnectCommand() );
}
break;
}
++i;
}
}
Network::List NetView::createList() const
{
config()->setGroup( "Net" );
int amount = config()->readNumEntry( "deviceAmount", 0 );
Network::List list;
for ( int i = 0; i < amount; ++i )
{
if ( !config()->hasGroup( "device-" + TQString::number( i ) ) )
{
continue;
}
config()->setGroup( "device-" + TQString::number( i ) );
list.append( Network( config()->readEntry( "deviceName" ),
config()->readEntry( "deviceFormat" ),
config()->readBoolEntry( "showTimer" ),
config()->readBoolEntry( "commands" ),
config()->readEntry( "cCommand" ),
config()->readEntry("dCommand") ) );
}
qHeapSort( list );
return list;
}
void NetView::updateLights()
{
Network::List::Iterator it;
for ( it = m_networkList.begin(); it != m_networkList.end(); ++it )
{
if ( isOnline( ( *it ).name() ) )
{
unsigned long receiveDiff = ( *it ).data().in - ( *it ).oldData().in;
unsigned long sendDiff = ( *it ).data().out - ( *it ).oldData().out;
unsigned long halfMax = ( *it ).maxValue() / 2;
( *it ).led()->setMaxValue( ( *it ).maxValue() / 1024 );
( *it ).led()->setValue( receiveDiff / 1024 );
if ( receiveDiff == 0 )
{
( *it ).led()->setOff( KSim::Led::First );
}
else if ( ( receiveDiff / 1024 ) >= halfMax )
{
( *it ).led()->setOn( KSim::Led::First );
}
else
{
( *it ).led()->toggle( KSim::Led::First );
}
if ( sendDiff == 0 )
{
( *it ).led()->setOff( KSim::Led::Second );
}
else if ( ( sendDiff / 1024 ) >= halfMax )
{
( *it ).led()->setOn( KSim::Led::Second );
}
else
{
( *it ).led()->toggle( KSim::Led::Second );
}
}
else
{
( *it ).led()->setMaxValue( 0 );
( *it ).led()->setValue( 0 );
( *it ).led()->setOff( KSim::Led::First );
( *it ).led()->setOff( KSim::Led::Second );
}
}
}
void NetView::updateGraph()
{
int timer = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
time_t start = 0;
struct stat st;
TQTime netTime;
TQString timeDisplay;
TQString pid( "/var/run/%1.pid" );
TQString newPid;
Network::List::Iterator it;
for ( it = m_networkList.begin(); it != m_networkList.end(); ++it )
{
if ( isOnline( ( *it ).name() ) )
{
NetData data;
if ( ( *it ).label() )
{
timeDisplay = ( *it ).format();
newPid = pid.arg( ( *it ).name() );
if ( TQFile::exists( newPid ) && stat( TQFile::encodeName( newPid ).data(), &st ) == 0 )
{
start = st.st_mtime;
timer = static_cast<int>( difftime( time( 0 ), start ) );
hours = timer / 3600;
minutes = (timer - hours * 3600) / 60;
seconds = timer % 60;
if ( netTime.isValid( hours, minutes, seconds ) )
netTime.setHMS( hours, minutes, seconds );
}
// Keep backwards compat for now
if ( timeDisplay.contains( '%' ) > 0 )
timeDisplay.replace( '%', "" );
( *it ).label()->setText( netTime.toString( timeDisplay ) );
}
netStatistics( ( *it ).name(), data );
( *it ).setData( data );
unsigned long receiveDiff = data.in - ( *it ).oldData().in;
unsigned long sendDiff = data.out - ( *it ).oldData().out;
if ( m_firstTime )
{
receiveDiff = sendDiff = 0;
}
( *it ).chart()->setValue( receiveDiff, sendDiff );
( *it ).setMaxValue( ( *it ).chart()->maxValue() );
TQString receiveString = TDEGlobal::locale()->formatNumber( ( float ) receiveDiff / 1024.0, 1 );
TQString sendString = TDEGlobal::locale()->formatNumber( ( float ) sendDiff / 1024.0, 1 );
( *it ).chart()->setText( i18n( "in: %1k" ).arg( receiveString ),
i18n( "out: %1k" ).arg( sendString ) );
}
else
{
( *it ).setData( NetData() );
( *it ).chart()->setValue( 0, 0 );
( *it ).chart()->setText( i18n( "in: %1k" ).arg( TDEGlobal::locale()->formatNumber( 0.0, 1 ) ),
i18n( "out: %1k" ).arg( TDEGlobal::locale()->formatNumber( 0.0, 1 ) ) );
if ( ( *it ).label() )
( *it ).label()->setText( i18n( "offline" ) );
}
}
if ( m_firstTime )
m_firstTime = false;
}
KSim::Chart *NetView::addChart()
{
KSim::Chart *chart = new KSim::Chart(false, 0, this);
m_netLayout->addWidget(chart);
chart->show();
return chart;
}
KSim::LedLabel *NetView::addLedLabel(const TQString &device)
{
KSim::LedLabel *ledLabel = new KSim::LedLabel(0, KSim::Types::Net,
device, this);
ledLabel->show();
m_netLayout->addWidget(ledLabel);
return ledLabel;
}
KSim::Label *NetView::addLabel()
{
KSim::Label *label = new KSim::Label(KSim::Types::None, this);
label->show();
m_netLayout->addWidget(label);
return label;
}
TQPopupMenu *NetView::addPopupMenu(const TQString &device, int value)
{
TQPopupMenu *popup = new TQPopupMenu(this);
popup->insertItem(SmallIcon("network"), i18n("Connect"), this,
TQT_SLOT(runConnectCommand(int)), 0, 1);
popup->setItemParameter(1, value);
popup->insertItem(SmallIcon("network"), i18n("Disconnect"), this,
TQT_SLOT(runDisconnectCommand(int)), 0, 2);
popup->setItemParameter(2, value);
menu()->insertItem(device, popup, 100 + value);
return popup;
}
void NetView::netStatistics(const TQString &device, NetData &data)
{
#ifdef __linux__
if (m_procFile == 0) {
data.in = 0;
data.out = 0;
return;
}
TQString output;
TQString parser;
// Parse the proc file
while (!m_procStream->atEnd()) {
parser = m_procStream->readLine();
// remove all the entries apart from the line containing 'device'
if (parser.find(device) != -1)
output = parser;
}
if (output.isEmpty()) {
data.in = 0;
data.out = 0;
return;
}
// make sure our output doesn't contain "eth0:11210107" so we dont
// end up with netList[1] actually being netList[2]
output.replace(TQRegExp(":"), " ");
TQStringList netList = TQStringList::split(' ', output);
data.in = netList[1].toULong();
data.out = netList[9].toULong();
fseek(m_procFile, 0L, SEEK_SET);
#endif
#ifdef __FreeBSD__
struct if_msghdr *ifm, *nextifm;
struct sockaddr_dl *sdl;
char *lim, *next;
size_t needed;
char s[32];
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
return;
if (m_allocSize < needed) {
if (m_buf != NULL)
delete[] m_buf;
m_buf = new char[needed];
if (m_buf == NULL)
return;
m_allocSize = needed;
}
if (sysctl(mib, 6, m_buf, &needed, NULL, 0) < 0)
return;
lim = m_buf + needed;
next = m_buf;
while (next < lim) {
ifm = (struct if_msghdr *)next;
if (ifm->ifm_type != RTM_IFINFO)
return;
next += ifm->ifm_msglen;
// get an interface with a network address
while (next < lim) {
nextifm = (struct if_msghdr *)next;
if (nextifm->ifm_type != RTM_NEWADDR)
break;
next += nextifm->ifm_msglen;
}
// if the interface is up
if (ifm->ifm_flags & IFF_UP) {
sdl = (struct sockaddr_dl *)(ifm + 1);
if (sdl->sdl_family != AF_LINK)
continue;
strncpy(s, sdl->sdl_data, sdl->sdl_nlen);
s[sdl->sdl_nlen] = '\0';
if (strcmp(device.local8Bit().data(), s) == 0) {
data.in = ifm->ifm_data.ifi_ibytes;
data.out = ifm->ifm_data.ifi_obytes;
return;
}
}
}
#endif
}
bool NetView::isOnline(const TQString &device)
{
#ifdef __linux__
TQFile file("/proc/net/route");
if (!file.open(IO_ReadOnly))
return -1;
return (TQTextStream(&file).read().find(device) != -1 ? true : false);
#endif
#ifdef __FreeBSD__
struct if_msghdr *ifm, *nextifm;
struct sockaddr_dl *sdl;
char *lim, *next;
size_t needed;
char s[32];
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
return false;
if (m_allocSize < needed) {
if (m_buf != NULL)
delete[] m_buf;
m_buf = new char[needed];
if (m_buf == NULL)
return false;
m_allocSize = needed;
}
if (sysctl(mib, 6, m_buf, &needed, NULL, 0) < 0)
return false;
lim = m_buf + needed;
next = m_buf;
while (next < lim) {
ifm = (struct if_msghdr *)next;
if (ifm->ifm_type != RTM_IFINFO)
return false;
next += ifm->ifm_msglen;
// get an interface with a network address
while (next < lim) {
nextifm = (struct if_msghdr *)next;
if (nextifm->ifm_type != RTM_NEWADDR)
break;
next += nextifm->ifm_msglen;
}
// if the interface is up
if (ifm->ifm_flags & IFF_UP) {
sdl = (struct sockaddr_dl *)(ifm + 1);
if (sdl->sdl_family != AF_LINK)
continue;
strncpy(s, sdl->sdl_data, sdl->sdl_nlen);
s[sdl->sdl_nlen] = '\0';
if (strcmp(s, device.local8Bit().data()) == 0)
return true;
}
}
return false;
#endif
}
// EventFilter
bool NetView::eventFilter( TQObject * o, TQEvent * e )
{
// find out which interface we are
int i = 0;
Network::List::Iterator it;
for ( it = m_networkList.begin(); it != m_networkList.end(); ++it )
{
if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(( *it ).chart()) || TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(( *it ).label()) || TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(( *it ).led()) )
{
break;
}
++i;
}
if ( e->type() == TQEvent::MouseButtonPress )
{
if ( TQT_TQMOUSEEVENT( e )->button() == Qt::RightButton )
{
showMenu(i);
}
return true;
}
return false;
}
void NetView::showMenu(int i) {
TQPopupMenu menu;
menu.insertItem( SmallIcon("network"), i18n("Connect"), 1);
menu.insertItem( SmallIcon("network"), i18n("Disconnect"), 2);
switch (menu.exec(TQCursor::pos())) {
case 1:
runConnectCommand(i);
break;
case 2:
runDisconnectCommand(i);
break;
}
}
#include "ksimnet.moc"