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:
parent
264b446410
commit
e188655e67
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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_);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user