diff options
Diffstat (limited to 'ksim/monitors/net/ksimnet.cpp')
-rw-r--r-- | ksim/monitors/net/ksimnet.cpp | 672 |
1 files changed, 672 insertions, 0 deletions
diff --git a/ksim/monitors/net/ksimnet.cpp b/ksim/monitors/net/ksimnet.cpp new file mode 100644 index 0000000..45f86c2 --- /dev/null +++ b/ksim/monitors/net/ksimnet.cpp @@ -0,0 +1,672 @@ +/* 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 <qpushbutton.h> +#include <qtextstream.h> +#include <qfile.h> +#include <qdatetime.h> +#include <qlayout.h> +#include <qtimer.h> +#include <qregexp.h> +#include <qcursor.h> +#include <qpopupmenu.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() +{ + QString version = kapp->aboutData()->version(); + + KAboutData aboutData(instanceName(), + I18N_NOOP("KSim Net Plugin"), version.latin1(), + I18N_NOOP("A net plugin for KSim"), + KAboutData::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 QTextStream(m_procFile, IO_ReadOnly); +#endif +#ifdef __FreeBSD__ + m_buf = 0; + m_allocSize = 0; +#endif + + m_firstTime = true; + m_netLayout = new QVBoxLayout(this); + + m_networkList = createList(); + addDisplay(); + + m_netTimer = new QTimer(this); + connect(m_netTimer, SIGNAL(timeout()), SLOT(updateGraph())); + m_netTimer->start(NET_UPDATE); + + m_lightTimer = new QTimer(this); + connect(m_lightTimer, SIGNAL(timeout()), 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 ); + QPopupMenu * 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 ); + //QPopupMenu * 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-" + QString::number( i ) ) ) + { + continue; + } + + config()->setGroup( "device-" + QString::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; + + QTime netTime; + QString timeDisplay; + QString pid( "/var/run/%1.pid" ); + QString 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 ( QFile::exists( newPid ) && stat( QFile::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() ); + + QString receiveString = KGlobal::locale()->formatNumber( ( float ) receiveDiff / 1024.0, 1 ); + QString sendString = KGlobal::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( KGlobal::locale()->formatNumber( 0.0, 1 ) ), + i18n( "out: %1k" ).arg( KGlobal::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 QString &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; +} + +QPopupMenu *NetView::addPopupMenu(const QString &device, int value) +{ + QPopupMenu *popup = new QPopupMenu(this); + popup->insertItem(SmallIcon("network"), i18n("Connect"), this, + SLOT(runConnectCommand(int)), 0, 1); + popup->setItemParameter(1, value); + popup->insertItem(SmallIcon("network"), i18n("Disconnect"), this, + SLOT(runDisconnectCommand(int)), 0, 2); + popup->setItemParameter(2, value); + menu()->insertItem(device, popup, 100 + value); + return popup; +} + +void NetView::netStatistics(const QString &device, NetData &data) +{ +#ifdef __linux__ + if (m_procFile == 0) { + data.in = 0; + data.out = 0; + return; + } + + QString output; + QString 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(QRegExp(":"), " "); + QStringList netList = QStringList::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 QString &device) +{ +#ifdef __linux__ + QFile file("/proc/net/route"); + if (!file.open(IO_ReadOnly)) + return -1; + + return (QTextStream(&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( QObject * o, QEvent * 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 ( o == ( *it ).chart() || o == ( *it ).label() || o == ( *it ).led() ) + { + break; + } + + ++i; + } + + if ( e->type() == QEvent::MouseButtonPress ) + { + if ( static_cast<QMouseEvent *>( e )->button() == QMouseEvent::RightButton ) + { + showMenu(i); + } + + return true; + } + + return false; +} + +void NetView::showMenu(int i) { + + QPopupMenu menu; + menu.insertItem( SmallIcon("network"), i18n("Connect"), 1); + menu.insertItem( SmallIcon("network"), i18n("Disconnect"), 2); + switch (menu.exec(QCursor::pos())) { + case 1: + runConnectCommand(i); + break; + case 2: + runDisconnectCommand(i); + break; + } +} + + +#include "ksimnet.moc" |