diff options
Diffstat (limited to 'src/knemod/backends')
-rw-r--r-- | src/knemod/backends/Makefile.am | 22 | ||||
-rw-r--r-- | src/knemod/backends/backendbase.cpp | 38 | ||||
-rw-r--r-- | src/knemod/backends/backendbase.h | 68 | ||||
-rw-r--r-- | src/knemod/backends/daemonregistry.h | 54 | ||||
-rw-r--r-- | src/knemod/backends/kcmregistry.h | 61 | ||||
-rw-r--r-- | src/knemod/backends/nettoolsbackend.cpp | 498 | ||||
-rw-r--r-- | src/knemod/backends/nettoolsbackend.h | 72 | ||||
-rw-r--r-- | src/knemod/backends/sysbackend.cpp | 428 | ||||
-rw-r--r-- | src/knemod/backends/sysbackend.h | 54 |
9 files changed, 1295 insertions, 0 deletions
diff --git a/src/knemod/backends/Makefile.am b/src/knemod/backends/Makefile.am new file mode 100644 index 0000000..aab0fd0 --- /dev/null +++ b/src/knemod/backends/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for knemo backends + +noinst_LTLIBRARIES = libknemo_backends.la + +# set the include path for X, qt and KDE +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../../common $(all_includes) + +# the library search path. +libknemo_backends_la_LDFLAGS = -module -avoid-version $(all_libraries) + +# the libraries to link against. +libknemo_backends_la_LIBADD = $(LIB_KIO) $(LIB_KUTILS) + +# which sources should be compiled as backends +libknemo_backends_la_SOURCES = backendbase.cpp nettoolsbackend.cpp sysbackend.cpp + +# the headers of the backends +noinst_HEADERS = backendbase.h nettoolsbackend.h sysbackend.h + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + diff --git a/src/knemod/backends/backendbase.cpp b/src/knemod/backends/backendbase.cpp new file mode 100644 index 0000000..82da372 --- /dev/null +++ b/src/knemod/backends/backendbase.cpp @@ -0,0 +1,38 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <percy@eris23.de> + + KNemo is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + KNemo 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "backendbase.h" + +BackendBase::BackendBase( QDict<Interface>& interfaces ) + : mInterfaces( interfaces ) +{ +} + +BackendBase::~BackendBase() +{ +} + +void BackendBase::updateComplete() +{ + QDictIterator<Interface> ifIt( mInterfaces ); + for ( ; ifIt.current(); ++ifIt ) + { + ifIt.current()->activateMonitor(); + } +} diff --git a/src/knemod/backends/backendbase.h b/src/knemod/backends/backendbase.h new file mode 100644 index 0000000..183e40a --- /dev/null +++ b/src/knemod/backends/backendbase.h @@ -0,0 +1,68 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <percy@eris23.de> + + KNemo is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + KNemo 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef BACKENDBASE_H +#define BACKENDBASE_H + +#include <qdict.h> +#include <qstring.h> + +#include <klocale.h> + +#include "data.h" +#include "interface.h" + +/** + * This is the baseclass for all backends. Every backend that + * should be used for KNemo must inherit from this class. + * + * @short Baseclass for all backends + * @author Percy Leonhardt <percy@eris23.de> + */ + +class BackendBase +{ +public: + BackendBase( QDict<Interface>& interfaces ); + virtual ~BackendBase(); + + /** + * Create an instance of this backend because KNemo + * does not know about the different types of backends. + */ + + /** + * This function is called from KNemo whenever the + * backend shall update the information of the + * interfaces in the QDict. + */ + virtual void update() = 0; + +protected: + /** + * Call this function when you have completed the + * update. It will trigger the interfaces to check + * if there state has changed. + */ + void updateComplete(); + + const QDict<Interface>& mInterfaces; +}; + +#endif // BACKENDBASE_H diff --git a/src/knemod/backends/daemonregistry.h b/src/knemod/backends/daemonregistry.h new file mode 100644 index 0000000..ba4638d --- /dev/null +++ b/src/knemod/backends/daemonregistry.h @@ -0,0 +1,54 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <percy@eris23.de> + + KNemo is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + KNemo 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef DAEMONREGISTRY_H +#define DAEMONREGISTRY_H + +#include <qstring.h> + +#include <klocale.h> + +#include "backendbase.h" +#include "sysbackend.h" +#include "nettoolsbackend.h" + +/** + * This registry tells KNemo what backends are available + * and how they can be created. It is only used by the daemon + * to create the selected backend. Two registries were + * necessary to avoid linking the KCM module against all backends. + * + * @short Registry for all backends + * @author Percy Leonhardt <percy@eris23.de> + */ + +struct DaemonRegistryEntry +{ + QString name; + BackendBase* (*function) ( QDict<Interface>& ); +}; + +DaemonRegistryEntry DaemonRegistry[] = +{ + { "Nettools", NetToolsBackend::createInstance }, + { "Sys", SysBackend::createInstance }, + { QString::null, 0 } +}; + +#endif // DAEMONREGISTRY_H diff --git a/src/knemod/backends/kcmregistry.h b/src/knemod/backends/kcmregistry.h new file mode 100644 index 0000000..23820ac --- /dev/null +++ b/src/knemod/backends/kcmregistry.h @@ -0,0 +1,61 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <percy@eris23.de> + + KNemo is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + KNemo 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCMREGISTRY_H +#define KCMREGISTRY_H + +#include <qstring.h> + +#include <klocale.h> + +/** + * This registry tells the KCM module what backends are available + * and how they can be created. It also offers a short description + * for every backend that is used in the configuration dialog of KNemo. + * It should describe how a backend gathers its information. + * + * @short Registry for all backends + * @author Percy Leonhardt <percy@eris23.de> + */ + +struct KCMRegistryEntry +{ + QString name; + QString description; +}; + +KCMRegistryEntry KCMRegistry[] = +{ + { "Nettools", + i18n( "Uses the tools from the nettool packge like ifconfig, " \ + "iwconfig and route to read the necessary information " \ + "from the ouput of these commands.\n" \ + "This backend works rather stable but causes a relativly " \ + "high CPU load." ) }, + { "Sys", + i18n( "Uses the sys filesystem available in 2.6 kernels and " \ + "direct system calls to the Linux kernel.\n" \ + "This backend is rather new, so expect minor problems. " \ + "As an advantage this backend should reduce the CPU load " \ + "and should not access the harddisc while gathering " \ + "information." ) }, + { QString::null, QString::null } +}; + +#endif // KCMREGISTRY_H diff --git a/src/knemod/backends/nettoolsbackend.cpp b/src/knemod/backends/nettoolsbackend.cpp new file mode 100644 index 0000000..dca42e1 --- /dev/null +++ b/src/knemod/backends/nettoolsbackend.cpp @@ -0,0 +1,498 @@ +/* This file is part of KNemo + Copyright (C) 2004, 2006 Percy Leonhardt <percy@eris23.de> + + KNemo is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + KNemo 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <qmap.h> +#include <qregexp.h> +#include <qstringlist.h> + +#include <kdebug.h> +#include <kprocess.h> +#include <kio/global.h> + +#include "nettoolsbackend.h" + +#include "config.h" + +NetToolsBackend::NetToolsBackend( QDict<Interface>& interfaces ) + : QObject(), + BackendBase( interfaces ), + mRouteProcess(0L), + mIfconfigProcess(0L), + mIwconfigProcess(0L) +{ +} + +NetToolsBackend::~NetToolsBackend() +{ + if ( mRouteProcess ) + { + mRouteProcess->kill(); + delete mRouteProcess; + } + if ( mIfconfigProcess ) + { + mIfconfigProcess->kill(); + delete mIfconfigProcess; + } + if ( mIwconfigProcess ) + { + mIwconfigProcess->kill(); + delete mIwconfigProcess; + } +} + +BackendBase* NetToolsBackend::createInstance( QDict<Interface>& interfaces ) +{ + return new NetToolsBackend( interfaces ); +} + +void NetToolsBackend::update() +{ + if ( !mIfconfigProcess ) + { + mIfconfigStdout = QString::null; + mIfconfigProcess = new KProcess(); + mIfconfigProcess->setEnvironment( "LANG", "C" ); + mIfconfigProcess->setEnvironment( "LC_ALL", "C" ); + *mIfconfigProcess << PATH_IFCONFIG << "-a"; + connect( mIfconfigProcess, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + this, SLOT( ifconfigProcessStdout( KProcess*, char*, int ) ) ); + connect( mIfconfigProcess, SIGNAL( processExited( KProcess* ) ), + this, SLOT( ifconfigProcessExited( KProcess* ) ) ); + + if ( !mIfconfigProcess->start( KProcess::NotifyOnExit, KProcess::Stdout ) ) + { + delete mIfconfigProcess; + mIfconfigProcess = 0L; + } + } + +#ifdef PATH_IWCONFIG + if ( !mIwconfigProcess ) + { + mIwconfigStdout = QString::null; + mIwconfigProcess = new KProcess(); + mIwconfigProcess->setEnvironment( "LANG", "C" ); + mIwconfigProcess->setEnvironment( "LC_ALL", "C" ); + *mIwconfigProcess << PATH_IWCONFIG; + connect( mIwconfigProcess, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + this, SLOT( iwconfigProcessStdout( KProcess*, char*, int ) ) ); + connect( mIwconfigProcess, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + this, SLOT( iwconfigProcessStdout( KProcess*, char*, int ) ) ); + connect( mIwconfigProcess, SIGNAL( processExited( KProcess* ) ), + this, SLOT( iwconfigProcessExited( KProcess* ) ) ); + + if ( !mIwconfigProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + delete mIwconfigProcess; + mIwconfigProcess = 0L; + } + } +#endif + +#ifdef PATH_ROUTE + if ( !mRouteProcess ) + { + mRouteStdout = QString::null; + mRouteProcess = new KProcess(); + mRouteProcess->setEnvironment( "LANG", "C" ); + mRouteProcess->setEnvironment( "LC_ALL", "C" ); + *mRouteProcess << PATH_ROUTE << "-n"; + connect( mRouteProcess, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + this, SLOT( routeProcessStdout( KProcess*, char*, int ) ) ); + connect( mRouteProcess, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + this, SLOT( routeProcessStdout( KProcess*, char*, int ) ) ); + connect( mRouteProcess, SIGNAL( processExited( KProcess* ) ), + this, SLOT( routeProcessExited( KProcess* ) ) ); + + if ( !mRouteProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput ) ) + { + delete mRouteProcess; + mRouteProcess = 0L; + } + } +#endif +} + +void NetToolsBackend::routeProcessExited( KProcess* process ) +{ + if ( process == mRouteProcess ) + { + mRouteProcess->deleteLater(); // we're in a slot connected to mRouteProcess + mRouteProcess = 0L; + parseRouteOutput(); + } +} + +void NetToolsBackend::routeProcessStdout( KProcess*, char* buffer, int buflen ) +{ + mRouteStdout += QString::fromLatin1( buffer, buflen ); +} + +void NetToolsBackend::ifconfigProcessExited( KProcess* process ) +{ + if ( process == mIfconfigProcess ) + { + delete mIfconfigProcess; + mIfconfigProcess = 0L; + parseIfconfigOutput(); + } +} + +void NetToolsBackend::ifconfigProcessStdout( KProcess*, char* buffer, int buflen ) +{ + mIfconfigStdout += QString::fromLatin1( buffer, buflen ); +} + +void NetToolsBackend::iwconfigProcessExited( KProcess* process ) +{ + if ( process == mIwconfigProcess ) + { + delete mIwconfigProcess; + mIwconfigProcess = 0L; + parseIwconfigOutput(); + } +} + +void NetToolsBackend::iwconfigProcessStdout( KProcess*, char* buffer, int buflen ) +{ + mIwconfigStdout += QString::fromLatin1( buffer, buflen ); +} + +void NetToolsBackend::parseIfconfigOutput() +{ + /* mIfconfigStdout contains the complete output of 'ifconfig' which we + * are going to parse here. + */ + QMap<QString, QString> configs; + QStringList ifList = QStringList::split( "\n\n", mIfconfigStdout ); + QStringList::Iterator it; + for ( it = ifList.begin(); it != ifList.end(); ++it ) + { + int index = ( *it ).find( ' ' ); + if ( index == -1 ) + continue; + QString key = ( *it ).left( index ); + configs[key] = ( *it ).mid( index ); + } + + /* We loop over the interfaces the user wishs to monitor. + * If we find the interface in the output of 'ifconfig' + * we update its data, otherwise we mark it as + * 'not existing'. + */ + QDictIterator<Interface> ifIt( mInterfaces ); + for ( ; ifIt.current(); ++ifIt ) + { + QString key = ifIt.currentKey(); + Interface* interface = ifIt.current(); + + if ( configs.find( key ) == configs.end() ) + { + // The interface does not exist. Meaning the driver + // isn't loaded and/or the interface has not been created. + interface->getData().existing = false; + interface->getData().available = false; + } + // JJ 2005-07-18: use RUNNING instead of UP to detect whether interface is connected + else if ( !configs[key].contains( "inet " ) || + !configs[key].contains( "RUNNING" ) ) + { + // The interface is up or has an IP assigned but not both + interface->getData().existing = true; + interface->getData().available = false; + } + else + { + // ...determine the type of the interface + if ( configs[key].contains( "Ethernet" ) ) + interface->setType( Interface::ETHERNET ); + else + interface->setType( Interface::PPP ); + + // Update the interface. + interface->getData().existing = true; + interface->getData().available = true; + updateInterfaceData( configs[key], interface->getData(), interface->getType() ); + } + } + updateComplete(); +} + +void NetToolsBackend::updateInterfaceData( QString& config, InterfaceData& data, int type ) +{ + QRegExp regExp( ".*RX.*:(\\d+).*:\\d+.*:\\d+.*:\\d+" ); + if ( regExp.search( config ) > -1 ) + data.rxPackets = regExp.cap( 1 ).toULong(); + + regExp.setPattern( ".*TX.*:(\\d+).*:\\d+.*:\\d+.*:\\d+" ); + if ( regExp.search( config ) > -1 ) + data.txPackets = regExp.cap( 1 ).toULong(); + + regExp.setPattern( "RX bytes:(\\d+)\\s*\\(\\d+\\.\\d+\\s*\\w+\\)" ); + if ( regExp.search( config ) > -1 ) + { + // We count the traffic on ourself to avoid an overflow after + // 4GB of traffic. + unsigned long currentRxBytes = regExp.cap( 1 ).toULong(); + if ( currentRxBytes < data.prevRxBytes ) + { + // there was an overflow + if ( type == Interface::ETHERNET ) + { + // This makes data counting more accurate but will not work + // for interfaces that reset the transfered data to zero + // when deactivated like ppp does. + data.rxBytes += 0xFFFFFFFF - data.prevRxBytes; + } + data.prevRxBytes = 0L; + } + if ( data.rxBytes == 0L ) + { + // on startup set to currently received bytes + data.rxBytes = currentRxBytes; + // this is new: KNemo only counts the traffic transfered + // while it is running. Important to not falsify statistics! + data.prevRxBytes = currentRxBytes; + } + else + // afterwards only add difference to previous number of bytes + data.rxBytes += currentRxBytes - data.prevRxBytes; + + data.incomingBytes = currentRxBytes - data.prevRxBytes; + data.prevRxBytes = currentRxBytes; + data.rxString = KIO::convertSize( data.rxBytes ); + } + + regExp.setPattern( "TX bytes:(\\d+)\\s*\\(\\d+\\.\\d+\\s*\\w+\\)" ); + if ( regExp.search( config ) > -1 ) + { + // We count the traffic on ourself to avoid an overflow after + // 4GB of traffic. + unsigned long currentTxBytes = regExp.cap( 1 ).toULong(); + if ( currentTxBytes < data.prevTxBytes ) + { + // there was an overflow + if ( type == Interface::ETHERNET ) + { + // This makes data counting more accurate but will not work + // for interfaces that reset the transfered data to zero + // when deactivated like ppp does. + data.txBytes += 0xFFFFFFFF - data.prevTxBytes; + } + data.prevTxBytes = 0L; + } + if ( data.txBytes == 0L ) + { + // on startup set to currently transmitted bytes + data.txBytes = currentTxBytes; + // this is new: KNemo only counts the traffic transfered + // while it is running. Important to not falsify statistics! + data.prevTxBytes = currentTxBytes; + } + else + // afterwards only add difference to previous number of bytes + data.txBytes += currentTxBytes - data.prevTxBytes; + + data.outgoingBytes = currentTxBytes - data.prevTxBytes; + data.prevTxBytes = currentTxBytes; + data.txString = KIO::convertSize( data.txBytes ); + } + + regExp.setPattern( "inet\\s+\\w+:(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})" ); + if ( regExp.search( config ) > -1 ) + data.ipAddress = regExp.cap( 1 ); + + regExp.setPattern( "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}).*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}).*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})" ); + if ( regExp.search( config ) > -1 ) + { + data.broadcastAddress = regExp.cap( 2 ); + data.subnetMask = regExp.cap( 3 ); + } + + if ( type == Interface::ETHERNET ) + { + regExp.setPattern( "(.{2}:.{2}:.{2}:.{2}:.{2}:.{2})" ); + if ( regExp.search( config ) > -1 ) + data.hwAddress = regExp.cap( 1 ); + } + else if ( type == Interface::PPP ) + { + regExp.setPattern( "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}).*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}).*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})" ); + if ( regExp.search( config ) > -1 ) + data.ptpAddress = regExp.cap( 2 ); + } +} + +void NetToolsBackend::parseIwconfigOutput() +{ + /* mIwconfigStdout contains the complete output of 'iwconfig' which we + * are going to parse here. + */ + QMap<QString, QString> configs; + QStringList ifList = QStringList::split( "\n\n", mIwconfigStdout ); + QStringList::Iterator it; + for ( it = ifList.begin(); it != ifList.end(); ++it ) + { + int index = ( *it ).find( ' ' ); + if ( index == -1 ) + continue; + QString key = ( *it ).left( index ); + configs[key] = ( *it ).mid( index ); + } + + /* We loop over the interfaces the user wishs to monitor. + * If we find the interface in the output of 'iwconfig' + * we update its data. + */ + QDictIterator<Interface> ifIt( mInterfaces ); + for ( ; ifIt.current(); ++ifIt ) + { + QString key = ifIt.currentKey(); + Interface* interface = ifIt.current(); + + if ( configs.find( key ) == configs.end() ) + { + // The interface was not found. + continue; + } + else if ( configs[key].contains( "no wireless extensions" ) ) + { + // The interface isn't a wireless device. + interface->getData().wirelessDevice = false; + } + else + { + // Update the wireless data of the interface. + interface->getData().wirelessDevice = true; + updateWirelessData( configs[key], interface->getWirelessData() ); + } + } +} + +void NetToolsBackend::updateWirelessData( QString& config, WirelessData& data ) +{ + QRegExp regExp( "ESSID:([^\"][\\S]*)" ); + if ( regExp.search( config ) > -1 ) + data.essid = regExp.cap( 1 ); + else + { + regExp.setPattern( "ESSID:\"([^\"]*)" ); + if ( regExp.search( config ) > -1 ) + data.essid = regExp.cap( 1 ); + else + data.essid = QString::null; + } + + regExp.setPattern( "Mode:(\\w*)" ); + if ( regExp.search( config ) > -1 ) + data.mode = regExp.cap( 1 ); + + regExp.setPattern( "Frequency:([\\w|\\.]*\\s*\\w*)" ); + if ( regExp.search( config ) > -1 ) + { + data.frequency = regExp.cap( 1 ); + data.channel = "-"; + } + else + { + data.frequency = "-"; + regExp.setPattern( "Channel:(\\d*)" ); + if ( regExp.search( config ) > -1 ) + data.channel = regExp.cap( 1 ); + else + data.channel = "-"; + } + + regExp.setPattern( "Bit Rate[=:](\\d*\\s*[\\w/]*)" ); + if ( regExp.search( config ) > -1 ) + data.bitRate = regExp.cap( 1 ); + + regExp.setPattern( "(.{2}:.{2}:.{2}:.{2}:.{2}:.{2})" ); + if ( regExp.search( config ) > -1 ) + data.accessPoint = regExp.cap( 1 ); + + regExp.setPattern( "Nickname:\"(\\w*)\"" ); + if ( regExp.search( config ) > -1 ) + data.nickName = regExp.cap( 1 ); + + regExp.setPattern( "Link Quality[=:]([\\d]*)" ); + if ( regExp.search( config ) > -1 ) + data.linkQuality = regExp.cap( 1 ); + + regExp.setPattern( "Encryption key:" ); + if ( regExp.search( config ) > -1 ) + { + regExp.setPattern( "Encryption key:off" ); + if ( regExp.search( config ) > -1 ) + { + data.encryption = false; + } + else + { + data.encryption = true; + } + } + else + { + data.encryption = false; + } +} + +void NetToolsBackend::parseRouteOutput() +{ + /* mRouteStdout contains the complete output of 'route' which we + * are going to parse here. + */ + QMap<QString, QStringList> configs; + QStringList routeList = QStringList::split( "\n", mRouteStdout ); + QStringList::Iterator it; + for ( it = routeList.begin(); it != routeList.end(); ++it ) + { + QStringList routeParameter = QStringList::split( " ", *it ); + if ( routeParameter.count() < 8 ) // no routing entry + continue; + if ( routeParameter[0] != "0.0.0.0" ) // no default route + continue; + configs[routeParameter[7]] = routeParameter; + } + + /* We loop over the interfaces the user wishs to monitor. + * If we find the interface in the output of 'route' we update + * the data of the interface. + */ + QDictIterator<Interface> ifIt( mInterfaces ); + for ( ; ifIt.current(); ++ifIt ) + { + QString key = ifIt.currentKey(); + Interface* interface = ifIt.current(); + + if ( configs.find( key ) != configs.end() ) + { + // Update the default gateway. + QStringList routeParameter = configs[key]; + interface->getData().defaultGateway = routeParameter[1]; + } + else + { + // Reset the default gateway. + interface->getData().defaultGateway = QString::null; + } + } +} diff --git a/src/knemod/backends/nettoolsbackend.h b/src/knemod/backends/nettoolsbackend.h new file mode 100644 index 0000000..788938c --- /dev/null +++ b/src/knemod/backends/nettoolsbackend.h @@ -0,0 +1,72 @@ +/* This file is part of KNemo + Copyright (C) 2004 Percy Leonhardt <percy@eris23.de> + + KNemo is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + KNemo 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef NETTOOLSBACKEND_H +#define NETTOOLSBACKEND_H + +#include <qobject.h> + +#include "backendbase.h" + +class KProcess; + +/** + * The nettools backend runs 'ifconfig', 'iwconfig' and 'route' + * and parses their output. It then triggers the interface + * monitor to look for changes in the state of the interface. + * + * @short Update the information of the interfaces via nettools + * @author Percy Leonhardt <percy@eris23.de> + */ + +class NetToolsBackend : public QObject, BackendBase +{ + Q_OBJECT +public: + NetToolsBackend(QDict<Interface>& interfaces ); + virtual ~NetToolsBackend(); + + static BackendBase* createInstance( QDict<Interface>& interfaces ); + + void update(); + +private slots: + void routeProcessExited( KProcess* process ); + void routeProcessStdout( KProcess* process, char* buffer, int buflen ); + void ifconfigProcessExited( KProcess* process ); + void ifconfigProcessStdout( KProcess* process, char* buffer, int buflen ); + void iwconfigProcessExited( KProcess* process ); + void iwconfigProcessStdout( KProcess* process, char* buffer, int buflen ); + +private: + void parseRouteOutput(); + void parseIfconfigOutput(); + void updateInterfaceData( QString& config, InterfaceData& data, int type ); + void parseIwconfigOutput(); + void updateWirelessData( QString& config, WirelessData& data ); + + QString mRouteStdout; + QString mIfconfigStdout; + QString mIwconfigStdout; + KProcess* mRouteProcess; + KProcess* mIfconfigProcess; + KProcess* mIwconfigProcess; +}; + +#endif // NETTOOLSBACKEND_H diff --git a/src/knemod/backends/sysbackend.cpp b/src/knemod/backends/sysbackend.cpp new file mode 100644 index 0000000..2caf325 --- /dev/null +++ b/src/knemod/backends/sysbackend.cpp @@ -0,0 +1,428 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <percy@eris23.de> + + KNemo is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + KNemo 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <stdio.h> +#include <string.h> +#include <arpa/inet.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include <qmap.h> +#include <qdir.h> +#include <qregexp.h> +#include <qstringlist.h> + +#include <kdebug.h> +#include <kprocess.h> +#include <kio/global.h> + +#include "sysbackend.h" + +#include "config.h" + +#ifdef HAVE_LIBIW +#include <iwlib.h> +#else +#include <net/if.h> +#endif + +#define RTF_GATEWAY 0x0002 +#define SYSPATH "/sys/class/net/" +#define PROCROUTE "/proc/net/route" + +SysBackend::SysBackend( QDict<Interface>& interfaces ) + : BackendBase( interfaces ) +{ +} + +SysBackend::~SysBackend() +{ +} + +BackendBase* SysBackend::createInstance( QDict<Interface>& interfaces ) +{ + return new SysBackend( interfaces ); +} + +void SysBackend::update() +{ + QDir dir( SYSPATH ); + QStringList ifList = dir.entryList( QDir::Dirs ); + + QDictIterator<Interface> ifIt( mInterfaces ); + for ( ; ifIt.current(); ++ifIt ) + { + QString key = ifIt.currentKey(); + Interface* interface = ifIt.current(); + + if ( ifList.find( key ) == ifList.end() ) + { + // The interface does not exist. Meaning the driver + // isn't loaded and/or the interface has not been created. + interface->getData().existing = false; + interface->getData().available = false; + } + else + { + if ( QFile::exists( SYSPATH + key + "/wireless" ) ) + { + interface->getData().wirelessDevice = true; + } + + unsigned int carrier = 0; + if ( !readNumberFromFile( SYSPATH + key + "/carrier", carrier ) || + carrier == 0 ) + { + // The interface is there but not useable. + interface->getData().existing = true; + interface->getData().available = false; + } + else + { + // ...determine the type of the interface + unsigned int type = 0; + if ( readNumberFromFile( SYSPATH + key + "/type", type ) && + type == 512 ) + { + interface->setType( Interface::PPP ); + } + else + { + interface->setType( Interface::ETHERNET ); + } + + // Update the interface. + interface->getData().existing = true; + interface->getData().available = true; + updateInterfaceData( key, interface->getData(), interface->getType() ); + + if ( interface->getData().wirelessDevice == true ) + { + updateWirelessData( key, interface->getWirelessData() ); + } + } + } + } + updateComplete(); +} + +bool SysBackend::readNumberFromFile( const QString& fileName, unsigned int& value ) +{ + FILE* file = fopen( fileName.latin1(), "r" ); + if ( file != NULL ) + { + if ( fscanf( file, "%ul", &value ) > 0 ) + { + fclose( file ); + return true; + } + fclose( file ); + } + + return false; +} + +bool SysBackend::readStringFromFile( const QString& fileName, QString& string ) +{ + char buffer[64]; + FILE* file = fopen( fileName.latin1(), "r" ); + if ( file != NULL ) + { + if ( fscanf( file, "%s", buffer ) > 0 ) + { + fclose( file ); + string = buffer; + return true; + } + fclose( file ); + } + + return false; +} + +void SysBackend::updateInterfaceData( const QString& ifName, InterfaceData& data, int type ) +{ + QString ifFolder = SYSPATH + ifName + "/"; + + unsigned int rxPackets = 0; + if ( readNumberFromFile( ifFolder + "statistics/rx_packets", rxPackets ) ) + { + data.rxPackets = rxPackets; + } + + unsigned int txPackets = 0; + if ( readNumberFromFile( ifFolder + "statistics/tx_packets", txPackets ) ) + { + data.txPackets = txPackets; + } + + unsigned int rxBytes = 0; + if ( readNumberFromFile( ifFolder + "statistics/rx_bytes", rxBytes ) ) + { + // We count the traffic on ourself to avoid an overflow after + // 4GB of traffic. + if ( rxBytes < data.prevRxBytes ) + { + // there was an overflow + if ( type == Interface::ETHERNET ) + { + // This makes data counting more accurate but will not work + // for interfaces that reset the transfered data to zero + // when deactivated like ppp does. + data.rxBytes += 0xFFFFFFFF - data.prevRxBytes; + } + data.prevRxBytes = 0L; + } + if ( data.rxBytes == 0L ) + { + // on startup set to currently received bytes + data.rxBytes = rxBytes; + // this is new: KNemo only counts the traffic transfered + // while it is running. Important to not falsify statistics! + data.prevRxBytes = rxBytes; + } + else + // afterwards only add difference to previous number of bytes + data.rxBytes += rxBytes - data.prevRxBytes; + + data.incomingBytes = rxBytes - data.prevRxBytes; + data.prevRxBytes = rxBytes; + data.rxString = KIO::convertSize( data.rxBytes ); + } + + unsigned int txBytes = 0; + if ( readNumberFromFile( ifFolder + "statistics/tx_bytes", txBytes ) ) + { + // We count the traffic on ourself to avoid an overflow after + // 4GB of traffic. + if ( txBytes < data.prevTxBytes ) + { + // there was an overflow + if ( type == Interface::ETHERNET ) + { + // This makes data counting more accurate but will not work + // for interfaces that reset the transfered data to zero + // when deactivated like ppp does. + data.txBytes += 0xFFFFFFFF - data.prevTxBytes; + } + data.prevTxBytes = 0L; + } + if ( data.txBytes == 0L ) + { + // on startup set to currently received bytes + data.txBytes = txBytes; + // this is new: KNemo only counts the traffic transfered + // while it is running. Important to not falsify statistics! + data.prevTxBytes = txBytes; + } + else + // afterwards only add difference to previous number of bytes + data.txBytes += txBytes - data.prevTxBytes; + + data.outgoingBytes = txBytes - data.prevTxBytes; + data.prevTxBytes = txBytes; + data.txString = KIO::convertSize( data.txBytes ); + } + + if ( type == Interface::ETHERNET ) + { + QString hwAddress; + if ( readStringFromFile( ifFolder + "address", hwAddress ) ) + { + data.hwAddress = hwAddress; + } + + // for the default gateway we use the proc filesystem + QFile routeFile( PROCROUTE ); + if ( routeFile.open( IO_ReadOnly ) ) + { + QString routeData( routeFile.readAll().data() ); + QStringList routeEntries = QStringList::split( "\n", routeData ); + QStringList::Iterator it; + for ( it = routeEntries.begin(); it != routeEntries.end(); ++it ) + { + QRegExp regExp( ".*\\s+[\\w\\d]{8}\\s+([\\w\\d]{8})\\s+(\\d{4})" ); + if ( ( regExp.search( *it ) > -1 ) + && ( regExp.cap( 2 ).toUInt() & RTF_GATEWAY ) ) + { + bool ok; + struct in_addr in; + in.s_addr = regExp.cap( 1 ).toULong( &ok, 16 ); + data.defaultGateway = inet_ntoa( in ); + break; + } + } + routeFile.close(); + } + + } + + // use ioctls for the rest + int fd; + struct ifreq ifr; + if ( ( fd = socket(AF_INET, SOCK_DGRAM, 0) ) > -1 ) + { + strcpy( ifr.ifr_name, ifName.latin1() ); + ifr.ifr_addr.sa_family = AF_INET; + if ( ioctl( fd, SIOCGIFADDR, &ifr ) > -1 ) + { + data.ipAddress = inet_ntoa(((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr); + } + if ( ioctl( fd, SIOCGIFDSTADDR, &ifr) > -1 ) + { + data.ptpAddress = inet_ntoa(((struct sockaddr_in*)&ifr.ifr_dstaddr)->sin_addr); + } + + if ( ioctl( fd, SIOCGIFBRDADDR, &ifr ) > -1 ) + { + data.broadcastAddress = inet_ntoa(((struct sockaddr_in*)&ifr.ifr_broadaddr)->sin_addr); + } + + if ( ioctl( fd, SIOCGIFNETMASK, &ifr ) > -1 ) + { + data.subnetMask = inet_ntoa(((struct sockaddr_in*)&ifr.ifr_netmask)->sin_addr); + } + close( fd ); + } +} + +void SysBackend::updateWirelessData( const QString& ifName, WirelessData& data ) +{ + QString wirelessFolder = SYSPATH + ifName + "/wireless/"; + + unsigned int link = 0; + if ( readNumberFromFile( wirelessFolder + "link", link ) ) + { + data.linkQuality = QString::number( link ); + } + +#ifdef HAVE_LIBIW + // The following code was taken from iwconfig.c and iwlib.c. + int fd; + if ( ( fd = iw_sockets_open() ) > 0 ) + { + struct iwreq wrq; + char buffer[128]; + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWFREQ, &wrq ) >= 0 ) + { + int channel = -1; + double freq = iw_freq2float( &( wrq.u.freq ) ); + struct iw_range range; + if( iw_get_range_info( fd, ifName.latin1(), &range ) >= 0 ) + { + if ( freq < KILO ) + { + channel = iw_channel_to_freq( (int) freq, &freq, &range ); + } + else + { + channel = iw_freq_to_channel( freq, &range ); + } + iw_print_freq_value( buffer, sizeof( buffer ), freq ); + data.frequency = buffer; + data.channel = QString::number( channel ); + } + } + + char essid[IW_ESSID_MAX_SIZE + 1]; + memset( essid, 0, IW_ESSID_MAX_SIZE + 1 ); + wrq.u.essid.pointer = (caddr_t) essid; + wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1; + wrq.u.essid.flags = 0; + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWESSID, &wrq ) >= 0 ) + { + if ( wrq.u.data.flags > 0 ) + { + data.essid = essid; + } + else + { + data.essid = "any"; + } + } + + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWAP, &wrq ) >= 0 ) + { + char ap_addr[128]; + iw_ether_ntop( (const ether_addr*) wrq.u.ap_addr.sa_data, ap_addr); + data.accessPoint = ap_addr; + } + + memset( essid, 0, IW_ESSID_MAX_SIZE + 1 ); + wrq.u.essid.pointer = (caddr_t) essid; + wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1; + wrq.u.essid.flags = 0; + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWNICKN, &wrq ) >= 0 ) + { + if ( wrq.u.data.length > 1 ) + { + data.nickName = essid; + } + else + { + data.nickName = QString::null; + } + } + + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWRATE, &wrq ) >= 0 ) + { + iwparam bitrate; + memcpy (&(bitrate), &(wrq.u.bitrate), sizeof (iwparam)); + iw_print_bitrate( buffer, sizeof( buffer ), wrq.u.bitrate.value ); + data.bitRate = buffer; + } + + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWMODE, &wrq ) >= 0 ) + { + int mode = wrq.u.mode; + if ( mode < IW_NUM_OPER_MODE && mode >= 0 ) + { + data.mode = iw_operation_mode[mode]; + } + else + { + data.mode = QString::null; + } + } + + unsigned char key[IW_ENCODING_TOKEN_MAX]; + wrq.u.data.pointer = (caddr_t) key; + wrq.u.data.length = IW_ENCODING_TOKEN_MAX; + wrq.u.data.flags = 0; + if ( iw_get_ext( fd, ifName.latin1(), SIOCGIWENCODE, &wrq ) >= 0 ) + { + if ( ( wrq.u.data.flags & IW_ENCODE_DISABLED ) || ( wrq.u.data.length == 0 ) ) + { + data.encryption = false; + } + else + { + data.encryption = true; + } + } + else + { + data.encryption = false; + } + close( fd ); + } +#endif +} + diff --git a/src/knemod/backends/sysbackend.h b/src/knemod/backends/sysbackend.h new file mode 100644 index 0000000..10650b6 --- /dev/null +++ b/src/knemod/backends/sysbackend.h @@ -0,0 +1,54 @@ +/* This file is part of KNemo + Copyright (C) 2006 Percy Leonhardt <percy@eris23.de> + + KNemo is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + KNemo 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SYSBACKEND_H +#define SYSBACKEND_H + +#include "backendbase.h" + +/** + * The sys backend uses the sys filesystem available in 2.6 + * kernels. It reads all necessary information from the files + * and folders located at /sys and parses their output. + * It then triggers the interface monitor to look for changes + * in the state of the interface. + * + * @short Update the information of the interfaces via sys filesystem + * @author Percy Leonhardt <percy@eris23.de> + */ + +class SysBackend : public BackendBase +{ +public: + SysBackend(QDict<Interface>& interfaces ); + virtual ~SysBackend(); + + static BackendBase* createInstance( QDict<Interface>& interfaces ); + + void update(); + +private: + bool readNumberFromFile( const QString& fileName, unsigned int& value ); + bool readStringFromFile( const QString& fileName, QString& string ); + void updateWirelessData( const QString& ifName, WirelessData& data ); + void updateInterfaceData( const QString& ifName, InterfaceData& data, int type ); + +}; + +#endif // SYSBACKEND_H |