diff --git a/server/abstractport.cpp b/server/abstractport.cpp
index c210e56..d121bcf 100644
--- a/server/abstractport.cpp
+++ b/server/abstractport.cpp
@@ -1,5 +1,5 @@
/*
-Copyright (C) 2010 Srivats P.
+Copyright (C) 2010-2012 Srivats P.
This file is part of "Ostinato"
@@ -121,6 +121,24 @@ bool AbstractPort::deleteStream(int streamId)
return false;
}
+void AbstractPort::addNote(QString note)
+{
+ QString notes = QString::fromStdString(data_.notes());
+
+ note.prepend("
");
+ note.append("");
+
+ if (notes.isEmpty())
+ notes="Limitation(s)";
+ else
+ notes.remove("
");
+
+ notes.append(note);
+ notes.append("");
+
+ data_.set_notes(notes.toStdString());
+}
+
void AbstractPort::updatePacketList()
{
switch(data_.transmit_mode())
diff --git a/server/abstractport.h b/server/abstractport.h
index 288f898..b9c7a6e 100644
--- a/server/abstractport.h
+++ b/server/abstractport.h
@@ -1,5 +1,5 @@
/*
-Copyright (C) 2010 Srivats P.
+Copyright (C) 2010-2012 Srivats P.
This file is part of "Ostinato"
@@ -97,6 +97,8 @@ public:
void resetStats() { epochStats_ = stats_; }
protected:
+ void addNote(QString note);
+
void updatePacketListSequential();
void updatePacketListInterleaved();
diff --git a/server/bsdport.cpp b/server/bsdport.cpp
new file mode 100644
index 0000000..016e93e
--- /dev/null
+++ b/server/bsdport.cpp
@@ -0,0 +1,327 @@
+/*
+Copyright (C) 2012 Srivats P.
+
+This file is part of "Ostinato"
+
+This 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 3 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, see
+*/
+
+#include "bsdport.h"
+
+#ifdef Q_OS_BSD4
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+QList BsdPort::allPorts_;
+BsdPort::StatsMonitor *BsdPort::monitor_;
+
+BsdPort::BsdPort(int id, const char *device)
+ : PcapPort(id, device)
+{
+ isPromisc_ = true;
+ clearPromisc_ = false;
+
+ // We don't need per port Rx/Tx monitors for Bsd
+ delete monitorRx_;
+ delete monitorTx_;
+ monitorRx_ = monitorTx_ = NULL;
+
+ // We have one monitor for both Rx/Tx of all ports
+ if (!monitor_)
+ monitor_ = new StatsMonitor();
+
+ data_.set_is_exclusive_control(hasExclusiveControl());
+ minPacketSetSize_ = 16;
+
+ qDebug("adding dev to all ports list <%s>", device);
+ allPorts_.append(this);
+}
+
+BsdPort::~BsdPort()
+{
+ qDebug("In %s", __FUNCTION__);
+
+ if (monitor_->isRunning())
+ {
+ monitor_->stop();
+ monitor_->wait();
+ }
+
+ 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)
+ {
+ short promisc = IFF_PPROMISC >> 16;
+
+ if (ifr.ifr_flagshigh & promisc)
+ {
+ ifr.ifr_flagshigh &= ~promisc;
+ if (ioctl(sd, SIOCSIFFLAGS, &ifr) == -1)
+ qDebug("Failed clearing promisc flag. SIOCSIFFLAGS failed: %s",
+ strerror(errno));
+ else
+ qDebug("Cleared promisc successfully");
+ }
+ else
+ qDebug("clear_promisc is set but IFF_PPROMISC is not?");
+ }
+ else
+ qDebug("Failed clearing promisc flag. SIOCGIFFLAGS failed: %s",
+ strerror(errno));
+
+ close(sd);
+ }
+}
+
+void BsdPort::init()
+{
+ if (!monitor_->isRunning())
+ monitor_->start();
+
+ monitor_->waitForSetupFinished();
+
+ if (!isPromisc_)
+ addNote("Non Promiscuous Mode");
+}
+
+bool BsdPort::hasExclusiveControl()
+{
+ // TODO
+ return false;
+}
+
+bool BsdPort::setExclusiveControl(bool /*exclusive*/)
+{
+ // TODO
+ return false;
+}
+
+BsdPort::StatsMonitor::StatsMonitor()
+ : QThread()
+{
+ stop_ = false;
+ setupDone_ = false;
+}
+
+void BsdPort::StatsMonitor::run()
+{
+ int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
+ const int mibLen = sizeof(mib)/sizeof(mib[0]);
+ QHash portStats;
+ QHash linkState;
+ int sd;
+ QByteArray buf;
+ size_t len;
+ char *p, *end;
+ int count;
+ struct ifreq ifr;
+
+ //
+ // We first setup stuff before we start polling for stats
+ //
+ if (sysctl(mib, mibLen, NULL, &len, NULL, 0) < 0)
+ {
+ qWarning("sysctl NET_RT_IFLIST(1) failed (%s)\n", strerror(errno));
+ return;
+ }
+
+ qDebug("sysctl mib returns reqd len = %d\n", len);
+ len *= 2; // for extra room, just in case!
+ buf.fill('\0', len);
+ if (sysctl(mib, mibLen, buf.data(), &len, NULL, 0) < 0)
+ {
+ qWarning("sysctl NET_RT_IFLIST(2) failed(%s)\n", strerror(errno));
+ return;
+ }
+
+ sd = socket(AF_INET, SOCK_DGRAM, 0);
+ Q_ASSERT(sd >= 0);
+ memset(&ifr, 0, sizeof(ifr));
+
+ //
+ // Populate the port stats hash table
+ //
+ p = buf.data();
+ end = p + len;
+ count = 0;
+ while (p < end)
+ {
+ struct if_msghdr *ifm = (struct if_msghdr*) p;
+ struct sockaddr_dl *sdl = (struct sockaddr_dl*) (ifm + 1);
+
+ if (ifm->ifm_type == RTM_IFINFO)
+ {
+ char ifname[1024];
+
+ strncpy(ifname, sdl->sdl_data, sdl->sdl_nlen);
+ ifname[sdl->sdl_nlen] = 0;
+
+ qDebug("if: %s(%d, %d)", ifname, ifm->ifm_index, sdl->sdl_index);
+ foreach(BsdPort* port, allPorts_)
+ {
+ if (strncmp(port->name(), sdl->sdl_data, sdl->sdl_nlen) == 0)
+ {
+ Q_ASSERT(ifm->ifm_index == sdl->sdl_index);
+ portStats[uint(ifm->ifm_index)] = &(port->stats_);
+ linkState[uint(ifm->ifm_index)] = &(port->linkState_);
+
+ // Set promisc mode, if not already set
+ strncpy(ifr.ifr_name, port->name(), sizeof(ifr.ifr_name));
+ if (ioctl(sd, SIOCGIFFLAGS, &ifr) != -1)
+ {
+ short promisc = IFF_PPROMISC >> 16;
+
+ if ((ifr.ifr_flagshigh & promisc) == 0)
+ {
+ ifr.ifr_flagshigh |= promisc;
+ if (ioctl(sd, SIOCSIFFLAGS, &ifr) != -1)
+ {
+ qDebug("%s: set promisc successful",
+ port->name());
+ port->clearPromisc_ = true;
+ }
+ else
+ {
+ port->isPromisc_ = false;
+ qDebug("%s: failed to set promisc; "
+ "SIOCSIFFLAGS failed (%s)",
+ port->name(), strerror(errno));
+ }
+ }
+ else
+ qDebug("%s: promisc already set", port->name());
+ }
+ else
+ {
+ port->isPromisc_ = false;
+ qDebug("%s: failed to set promisc; SIOCGIFFLAGS failed (%s)",
+ port->name(), strerror(errno));
+ }
+ break;
+ }
+ }
+ count++;
+ }
+ p += ifm->ifm_msglen;
+ }
+
+ qDebug("port count = %d\n", count);
+ if (count <= 0)
+ {
+ qWarning("no ports in NET_RT_IFLIST - no stats will be available");
+ return;
+ }
+
+ close(sd);
+
+ qDebug("stats for %d ports setup", count);
+ setupDone_ = true;
+
+ //
+ // We are all set - Let's start polling for stats!
+ //
+ while (!stop_)
+ {
+ if (sysctl(mib, mibLen, buf.data(), &len, NULL, 0) < 0)
+ {
+ qWarning("sysctl NET_RT_IFLIST(3) failed(%s)\n", strerror(errno));
+ goto _try_later;
+ }
+
+ p = buf.data();
+ end = p + len;
+
+ while (p < end)
+ {
+ struct if_msghdr *ifm = (struct if_msghdr*) p;
+ AbstractPort::PortStats *stats;
+
+ if (ifm->ifm_type != RTM_IFINFO)
+ goto _next;
+
+ stats = portStats[ifm->ifm_index];
+ if (stats)
+ {
+ struct if_data *ifd = &(ifm->ifm_data);
+ OstProto::LinkState *state = linkState[ifm->ifm_index];
+
+ Q_ASSERT(state);
+ *state = (OstProto::LinkState) ifd->ifi_link_state;
+
+ stats->rxPps = (ifd->ifi_ipackets + ifd->ifi_noproto
+ - stats->rxPkts) /kRefreshFreq_;
+ stats->rxBps = (ifd->ifi_ibytes - stats->rxBytes)
+ /kRefreshFreq_;
+ stats->rxPkts = ifd->ifi_ipackets + ifd->ifi_noproto;
+ stats->rxBytes = ifd->ifi_ibytes;
+ stats->txPps = (ifd->ifi_opackets - stats->txPkts)
+ /kRefreshFreq_;
+ stats->txBps = (ifd->ifi_obytes - stats->txBytes)
+ /kRefreshFreq_;
+ stats->txPkts = ifd->ifi_opackets;
+ stats->txBytes = ifd->ifi_obytes;
+
+ stats->rxDrops = ifd->ifi_iqdrops;
+ stats->rxErrors = ifd->ifi_ierrors;
+ }
+_next:
+ p += ifm->ifm_msglen;
+ }
+_try_later:
+ QThread::sleep(kRefreshFreq_);
+ }
+
+ portStats.clear();
+ linkState.clear();
+}
+
+void BsdPort::StatsMonitor::stop()
+{
+ stop_ = true;
+}
+
+bool BsdPort::StatsMonitor::waitForSetupFinished(int msecs)
+{
+ QTime t;
+
+ t.start();
+ while (!setupDone_)
+ {
+ if (t.elapsed() > msecs)
+ return false;
+
+ QThread::msleep(10);
+ }
+
+ return true;
+}
+#endif
diff --git a/server/bsdport.h b/server/bsdport.h
new file mode 100644
index 0000000..776c39a
--- /dev/null
+++ b/server/bsdport.h
@@ -0,0 +1,61 @@
+/*
+Copyright (C) 2012 Srivats P.
+
+This file is part of "Ostinato"
+
+This 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 3 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, see
+*/
+
+#ifndef _SERVER_BSD_PORT_H
+#define _SERVER_BSD_PORT_H
+
+#include
+
+#ifdef Q_OS_BSD4
+
+#include "pcapport.h"
+
+class BsdPort : public PcapPort
+{
+public:
+ BsdPort(int id, const char *device);
+ ~BsdPort();
+
+ void init();
+
+ virtual bool hasExclusiveControl();
+ virtual bool setExclusiveControl(bool exclusive);
+
+protected:
+ class StatsMonitor: public QThread
+ {
+ public:
+ StatsMonitor();
+ void run();
+ void stop();
+ bool waitForSetupFinished(int msecs = 10000);
+ private:
+ static const int kRefreshFreq_ = 1; // in seconds
+ bool stop_;
+ bool setupDone_;
+ };
+
+ bool isPromisc_;
+ bool clearPromisc_;
+ static QList allPorts_;
+ static StatsMonitor *monitor_; // rx/tx stats for ALL ports
+};
+#endif
+
+#endif
diff --git a/server/drone.pro b/server/drone.pro
index e235c24..341634c 100644
--- a/server/drone.pro
+++ b/server/drone.pro
@@ -36,6 +36,7 @@ SOURCES += \
portmanager.cpp \
abstractport.cpp \
pcapport.cpp \
+ bsdport.cpp \
linuxport.cpp \
winpcapport.cpp
SOURCES += myservice.cpp
diff --git a/server/portmanager.cpp b/server/portmanager.cpp
index 9a47ae7..2981464 100644
--- a/server/portmanager.cpp
+++ b/server/portmanager.cpp
@@ -1,5 +1,5 @@
/*
-Copyright (C) 2010 Srivats P.
+Copyright (C) 2010-2012 Srivats P.
This file is part of "Ostinato"
@@ -22,6 +22,7 @@ along with this program. If not, see
#include
#include
+#include "bsdport.h"
#include "linuxport.h"
#include "pcapport.h"
#include "winpcapport.h"
@@ -52,6 +53,8 @@ PortManager::PortManager()
port = new WinPcapPort(i, device->name);
#elif defined(Q_OS_LINUX)
port = new LinuxPort(i, device->name);
+#elif defined(Q_OS_BSD4)
+ port = new BsdPort(i, device->name);
#else
port = new PcapPort(i, device->name);
#endif