For Linux added specific code to put interfaces in PROMISC mode, since we no longer use PCAP to do stats (which was indirectly setting PROMISC). Also added signal handlers to do cleanup for SIGTERM and SIGINT. Some code indentation fixes also.

Fixes issue 52
This commit is contained in:
Srivats P. 2011-10-22 14:55:05 +05:30
parent 264b446410
commit e188655e67
3 changed files with 195 additions and 109 deletions

View File

@ -21,10 +21,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include "../common/protocolmanager.h"
#ifdef Q_OS_UNIX
#include "signal.h"
#endif
extern ProtocolManager *OstProtocolManager;
int myport;
void cleanup(int /*signum*/)
{
qApp->exit(-1);
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
@ -39,11 +48,24 @@ int main(int argc, char *argv[])
if (!drone.init())
exit(-1);
#ifdef Q_OS_UNIX
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = cleanup;
if (sigaction(SIGTERM, &sa, NULL))
qDebug("Failed to install SIGTERM handler. Cleanup may not happen!!!");
if (sigaction(SIGINT, &sa, NULL))
qDebug("Failed to install SIGINT handler. Cleanup may not happen!!!");
#endif
drone.setWindowFlags(drone.windowFlags()
| Qt::WindowMaximizeButtonHint
| Qt::WindowMinimizeButtonHint);
drone.showMinimized();
app.exec();
delete OstProtocolManager;
return 0;
}

View File

@ -23,9 +23,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include <QByteArray>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
QList<LinuxPort*> LinuxPort::allPorts_;
LinuxPort::StatsMonitor *LinuxPort::monitor_;
@ -33,13 +37,16 @@ LinuxPort::StatsMonitor *LinuxPort::monitor_;
LinuxPort::LinuxPort(int id, const char *device)
: PcapPort(id, device)
{
clearPromisc_ = false;
// We don't need per port Rx/Tx monitors for Linux
delete monitorRx_;
delete monitorTx_;
monitorRx_ = monitorTx_ = NULL;
// We have one monitor for both Rx/Tx of all ports
if (!monitor_)
monitor_ = new StatsMonitor();
monitor_ = new StatsMonitor();
data_.set_is_exclusive_control(hasExclusiveControl());
minPacketSetSize_ = 16;
@ -50,6 +57,32 @@ LinuxPort::LinuxPort(int id, const char *device)
LinuxPort::~LinuxPort()
{
qDebug("In %s", __FUNCTION__);
if (clearPromisc_)
{
int sd = socket(AF_INET, SOCK_DGRAM, 0);
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, name(), sizeof(ifr.ifr_name));
if (ioctl(sd, SIOCGIFFLAGS, &ifr) != -1)
{
if (ifr.ifr_flags & IFF_PROMISC)
{
ifr.ifr_flags &= ~IFF_PROMISC;
if (ioctl(sd, SIOCSIFFLAGS, &ifr) == -1)
qDebug("Failed clearing promisc flag. SIOCSIFFLAGS failed: %s",
strerror(errno));
}
}
else
qDebug("Failed clearing promisc flag. SIOCGIFFLAGS failed: %s",
strerror(errno));
close(sd);
}
}
void LinuxPort::init()
@ -57,7 +90,7 @@ void LinuxPort::init()
// TODO: Update Notes with Promisc/Non-Promisc
if (!monitor_->isRunning())
monitor_->start();
monitor_->start();
}
OstProto::LinkState LinuxPort::linkState()
@ -86,16 +119,17 @@ LinuxPort::StatsMonitor::StatsMonitor()
void LinuxPort::StatsMonitor::run()
{
PortStats **portStats;
int fd;
int fd, sd;
QByteArray buf;
int len;
char *p, *end;
int count, index;
const char* fmtopt[] = {
"%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u\n",
"%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u%n\n",
"%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u\n",
"%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u%n\n",
};
const char *fmt;
struct ifreq ifr;
//
// We first setup stuff before we start polling for stats
@ -103,16 +137,16 @@ void LinuxPort::StatsMonitor::run()
fd = open("/proc/net/dev", O_RDONLY);
if (fd < 0)
{
qWarning("Unable to open /proc/net/dev - no stats will be available");
return;
qWarning("Unable to open /proc/net/dev - no stats will be available");
return;
}
buf.fill('\0', 8192);
len = read(fd, (void*) buf.data(), buf.size());
if (len < 0)
{
qWarning("initial buffer size is too small. no stats will be available");
return;
qWarning("initial buffer size is too small. no stats will be available");
return;
}
p = buf.data();
@ -120,29 +154,33 @@ void LinuxPort::StatsMonitor::run()
// Select scanf format
if (strstr(buf, "compressed"))
fmt = fmtopt[0];
fmt = fmtopt[0];
else
fmt = fmtopt[1];
fmt = fmtopt[1];
// Count number of lines - number of ports is 2 less than number of lines
count = 0;
while (p < end)
{
if (*p == '\n')
count++;
p++;
if (*p == '\n')
count++;
p++;
}
count -= 2;
if (count <= 0)
{
qWarning("no ports in /proc/dev/net - no stats will be available");
return;
qWarning("no ports in /proc/dev/net - no stats will be available");
return;
}
portStats = (PortStats**) calloc(count, sizeof(PortStats));
Q_ASSERT(portStats != NULL);
sd = socket(AF_INET, SOCK_DGRAM, 0);
Q_ASSERT(sd >= 0);
memset(&ifr, 0, sizeof(ifr));
//
// Populate the port stats array
//
@ -150,48 +188,73 @@ void LinuxPort::StatsMonitor::run()
// Skip first two lines
while (*p != '\n')
p++;
p++;
p++;
while (*p != '\n')
p++;
p++;
p++;
index = 0;
while (p < end)
{
char* q;
char* q;
// Skip whitespace
while ((p < end) && (*p == ' '))
p++;
q = p;
// Skip whitespace
while ((p < end) && (*p == ' '))
p++;
// Get interface name
while ((q < end) && (*q != ':') && (*q != '\n'))
q++;
q = p;
if ((q < end) && (*q == ':'))
{
foreach(LinuxPort* port, allPorts_)
// Get interface name
while ((q < end) && (*q != ':') && (*q != '\n'))
q++;
if ((q < end) && (*q == ':'))
{
if (strncmp(port->name(), p, int(q-p)) == 0)
{
portStats[index] = &(port->stats_);
break;
}
}
}
index++;
foreach(LinuxPort* port, allPorts_)
{
if (strncmp(port->name(), p, int(q-p)) == 0)
{
portStats[index] = &(port->stats_);
// Skip till newline
p = q;
while (*p != '\n')
// Set promisc mode, if not already set
strncpy(ifr.ifr_name, port->name(), sizeof(ifr.ifr_name));
if (ioctl(sd, SIOCGIFFLAGS, &ifr) != -1)
{
if ((ifr.ifr_flags & IFF_PROMISC) == 0)
{
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl(sd, SIOCSIFFLAGS, &ifr) != -1)
port->clearPromisc_ = true;
else
{
qDebug("%s: failed to set promisc; "
"SIOCSIFFLAGS failed (%s)",
port->name(), strerror(errno));
}
}
}
else
{
qDebug("%s: failed to set promisc; SIOCGIFFLAGS failed (%s)",
port->name(), strerror(errno));
}
break;
}
}
}
index++;
// Skip till newline
p = q;
while (*p != '\n')
p++;
p++;
p++;
}
Q_ASSERT(index == count);
close(sd);
qDebug("stats for %d ports setup", count);
//
@ -199,77 +262,77 @@ void LinuxPort::StatsMonitor::run()
//
while (1)
{
lseek(fd, 0, SEEK_SET);
len = read(fd, (void*) buf.data(), buf.size());
if (len < 0)
{
if (buf.size() > 1*1024*1024)
lseek(fd, 0, SEEK_SET);
len = read(fd, (void*) buf.data(), buf.size());
if (len < 0)
{
qWarning("buffer size hit limit. no more stats");
return;
}
qDebug("doubling buffer size. curr = %d", buf.size());
buf.resize(buf.size() * 2);
continue;
}
p = buf.data();
end = p + len;
// Skip first two lines
while (*p != '\n')
p++;
p++;
while (*p != '\n')
p++;
p++;
index = 0;
while (p < end)
{
uint dummy;
quint64 rxBytes, rxPkts;
quint64 txBytes, txPkts;
// Skip interface name - we assume the number and order of ports
// won't change since we parsed the output before we started polling
while ((p < end) && (*p != ':') && (*p != '\n'))
p++;
if (p >= end)
break;
if (*p == '\n')
{
index++;
continue;
}
p++;
sscanf(p, fmt,
&rxBytes, &rxPkts, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy,
&txBytes, &txPkts, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy);
if (index < count)
{
AbstractPort::PortStats *stats = portStats[index];
if (stats)
{
stats->rxPps = (rxPkts - stats->rxPkts)/kRefreshFreq_;
stats->rxBps = (rxBytes - stats->rxBytes)/kRefreshFreq_;
stats->rxPkts = rxPkts;
stats->rxBytes = rxBytes;
stats->txPps = (txPkts - stats->txPkts)/kRefreshFreq_;
stats->txBps = (txBytes - stats->txBytes)/kRefreshFreq_;
stats->txPkts = txPkts;
stats->txBytes = txBytes;
}
if (buf.size() > 1*1024*1024)
{
qWarning("buffer size hit limit. no more stats");
return;
}
qDebug("doubling buffer size. curr = %d", buf.size());
buf.resize(buf.size() * 2);
continue;
}
p = buf.data();
end = p + len;
// Skip first two lines
while (*p != '\n')
p++;
p++;
while (*p != '\n')
p++;
p++;
index++;
}
QThread::sleep(kRefreshFreq_);
index = 0;
while (p < end)
{
uint dummy;
quint64 rxBytes, rxPkts;
quint64 txBytes, txPkts;
// Skip interface name - we assume the number and order of ports
// won't change since we parsed the output before we started polling
while ((p < end) && (*p != ':') && (*p != '\n'))
p++;
if (p >= end)
break;
if (*p == '\n')
{
index++;
continue;
}
p++;
sscanf(p, fmt,
&rxBytes, &rxPkts, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy,
&txBytes, &txPkts, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy);
if (index < count)
{
AbstractPort::PortStats *stats = portStats[index];
if (stats)
{
stats->rxPps = (rxPkts - stats->rxPkts)/kRefreshFreq_;
stats->rxBps = (rxBytes - stats->rxBytes)/kRefreshFreq_;
stats->rxPkts = rxPkts;
stats->rxBytes = rxBytes;
stats->txPps = (txPkts - stats->txPkts)/kRefreshFreq_;
stats->txBps = (txBytes - stats->txBytes)/kRefreshFreq_;
stats->txPkts = txPkts;
stats->txBytes = txBytes;
}
}
while (*p != '\n')
p++;
p++;
index++;
}
QThread::sleep(kRefreshFreq_);
}
}

View File

@ -48,6 +48,7 @@ protected:
static const int kRefreshFreq_ = 1; // in seconds
};
bool clearPromisc_;
static QList<LinuxPort*> allPorts_;
static StatsMonitor *monitor_; // rx/tx stats for ALL ports
};