diff --git a/client/icons/bullet_white.png b/client/icons/bullet_white.png
new file mode 100644
index 0000000..a9af8d4
Binary files /dev/null and b/client/icons/bullet_white.png differ
diff --git a/client/ostinato.qrc b/client/ostinato.qrc
index 48ab66a..1b09036 100644
--- a/client/ostinato.qrc
+++ b/client/ostinato.qrc
@@ -7,6 +7,7 @@
icons/bullet_green.png
icons/bullet_orange.png
icons/bullet_red.png
+ icons/bullet_white.png
icons/bullet_yellow.png
icons/control_play.png
icons/control_stop.png
diff --git a/client/port.cpp b/client/port.cpp
index 291b1b5..d7e2b4c 100644
--- a/client/port.cpp
+++ b/client/port.cpp
@@ -183,6 +183,13 @@ void Port::when_syncComplete()
void Port::updateStats(OstProto::PortStats *portStats)
{
+ OstProto::PortState oldState;
+
+ oldState = stats.state();
stats.MergeFrom(*portStats);
+#if 0
+ if (oldState.link_state() != stats.state().link_state())
+ emit portDataChanged(mPortGroupId, mPortId);
+#endif
}
diff --git a/client/port.h b/client/port.h
index 126b28d..bdafdb9 100644
--- a/client/port.h
+++ b/client/port.h
@@ -30,7 +30,6 @@ private:
void reorderStreamsByOrdinals();
public:
enum AdminStatus { AdminDisable, AdminEnable };
- enum OperStatus { OperDown, OperUp };
enum ControlMode { ControlShared, ControlExclusive };
// FIXME(HIGH): default args is a hack for QList operations on Port
@@ -48,8 +47,6 @@ public:
{ return QString().fromStdString(d.description()); }
AdminStatus adminStatus()
{ return (d.is_enabled()?AdminEnable:AdminDisable); }
- OperStatus operStatus()
- { return (d.is_oper_up()?OperUp:OperDown); }
ControlMode controlMode()
{ return (d.is_exclusive_control()?ControlExclusive:ControlShared); }
@@ -70,6 +67,9 @@ public:
Q_ASSERT(index < mStreams.size());
return mStreams[index];
}
+ OstProto::LinkState linkState()
+ { return stats.state().link_state(); }
+
OstProto::PortStats getStats() { return stats; }
// FIXME(MED): naming inconsistency - PortConfig/Stream; also retVal
@@ -97,6 +97,11 @@ public:
void updateStats(OstProto::PortStats *portStats);
+#if 0
+signals:
+ void portDataChanged(int portGroupId, int portId);
+#endif
+
};
#endif
diff --git a/client/portgroup.h b/client/portgroup.h
index c74640a..81363cc 100644
--- a/client/portgroup.h
+++ b/client/portgroup.h
@@ -91,7 +91,7 @@ public:
void processClearStatsAck(OstProto::Ack *ack);
signals:
- void portGroupDataChanged(PortGroup* portGroup);
+ void portGroupDataChanged(PortGroup* portGroup, int portId = 0xFFFF);
void portListAboutToBeChanged(quint32 portGroupId);
void portListChanged(quint32 portGroupId);
void statsChanged(quint32 portGroupId);
diff --git a/client/portgrouplist.cpp b/client/portgrouplist.cpp
index a503449..4387aee 100644
--- a/client/portgrouplist.cpp
+++ b/client/portgrouplist.cpp
@@ -60,8 +60,8 @@ void PortGroupList::addPortGroup(PortGroup &portGroup)
{
mPortGroupListModel.portGroupAboutToBeAppended();
- connect(&portGroup, SIGNAL(portGroupDataChanged(PortGroup*)),
- &mPortGroupListModel, SLOT(when_portGroupDataChanged(PortGroup*)));
+ connect(&portGroup, SIGNAL(portGroupDataChanged(PortGroup*, int)),
+ &mPortGroupListModel, SLOT(when_portGroupDataChanged(PortGroup*, int)));
#if 0
connect(&portGroup, SIGNAL(portListAboutToBeChanged(quint32)),
&mPortGroupListModel, SLOT(triggerLayoutAboutToBeChanged()));
diff --git a/client/portmodel.cpp b/client/portmodel.cpp
index 61f9be8..9397cc1 100644
--- a/client/portmodel.cpp
+++ b/client/portmodel.cpp
@@ -144,7 +144,17 @@ QVariant PortModel::data(const QModelIndex &index, int role) const
DBG0("Exit PortModel data 5\n");
if (pgl->mPortGroups.at(parent.row())->numPorts() == 0)
return QVariant();
- return QIcon(":/icons/bullet_green.png");
+ switch(pgl->mPortGroups.at(parent.row())->mPorts[index.row()].linkState())
+ {
+ case OstProto::LinkStateUnknown:
+ return QIcon(":/icons/bullet_white.png");
+ case OstProto::LinkStateDown:
+ return QIcon(":/icons/bullet_red.png");
+ case OstProto::LinkStateUp:
+ return QIcon(":/icons/bullet_green.png");
+ default:
+ qFatal("unexpected/unimplemented port oper state");
+ }
}
else
{
@@ -152,6 +162,8 @@ QVariant PortModel::data(const QModelIndex &index, int role) const
return QVariant();
}
}
+
+ return QVariant();
}
QVariant PortModel::headerData(int section, Qt::Orientation orientation, int role) const
@@ -252,7 +264,7 @@ quint32 PortModel::portId(const QModelIndex& index)
// ----------------------------------------------
// Slots
// ----------------------------------------------
-void PortModel::when_portGroupDataChanged(PortGroup* portGroup)
+void PortModel::when_portGroupDataChanged(PortGroup* portGroup, int portId)
{
QModelIndex index;
@@ -266,7 +278,7 @@ void PortModel::when_portGroupDataChanged(PortGroup* portGroup)
qDebug("when_portGroupDataChanged idx = %d", pgl->mPortGroups.indexOf(portGroup));
index = createIndex(pgl->mPortGroups.indexOf(portGroup), 0,
- (portGroup->id() << 16) | 0xFFFF);
+ (portGroup->id() << 16) | portId);
emit dataChanged(index, index);
}
diff --git a/client/portmodel.h b/client/portmodel.h
index b68acdc..de2b140 100644
--- a/client/portmodel.h
+++ b/client/portmodel.h
@@ -32,7 +32,7 @@ class PortModel : public QAbstractItemModel
private slots:
- void when_portGroupDataChanged(PortGroup *portGroup);
+ void when_portGroupDataChanged(PortGroup *portGroup, int portId);
void portGroupAboutToBeAppended();
void portGroupAppended();
diff --git a/client/portstatsmodel.cpp b/client/portstatsmodel.cpp
index 9961e12..6d77945 100644
--- a/client/portstatsmodel.cpp
+++ b/client/portstatsmodel.cpp
@@ -67,13 +67,15 @@ void PortStatsModel::getDomainIndexes(const QModelIndex &index,
QVariant PortStatsModel::data(const QModelIndex &index, int role) const
{
uint pgidx, pidx;
+ int row;
// Check for a valid index
if (!index.isValid())
return QVariant();
// Check for row/column limits
- if (index.row() >= e_STAT_MAX)
+ row = index.row();
+ if (row >= e_STAT_MAX)
return QVariant();
if (numPorts.isEmpty())
@@ -91,8 +93,19 @@ QVariant PortStatsModel::data(const QModelIndex &index, int role) const
stats = pgl->mPortGroups.at(pgidx)->mPorts[pidx].getStats();
- switch(index.row())
+ switch(row)
{
+ // States
+ case e_LINK_STATE:
+ return LinkStateName.at(stats.state().link_state());
+
+ case e_TRANSMIT_STATE:
+ return BoolStateName.at(stats.state().is_transmit_on());
+
+ case e_CAPTURE_STATE:
+ return BoolStateName.at(stats.state().is_capture_on());
+
+ // Statistics
case e_STAT_FRAMES_RCVD:
return stats.rx_pkts();
@@ -136,6 +149,15 @@ QVariant PortStatsModel::data(const QModelIndex &index, int role) const
return 0;
}
}
+ else if (role == Qt::TextAlignmentRole)
+ {
+ if (row >= e_STATE_START && row <= e_STATE_END)
+ return Qt::AlignHCenter;
+ else if (row >= e_STATISTICS_START && row <= e_STATISTICS_END)
+ return Qt::AlignRight;
+ else
+ return QVariant();
+ }
else
return QVariant();
diff --git a/client/portstatsmodel.h b/client/portstatsmodel.h
index de1c585..02f02dd 100644
--- a/client/portstatsmodel.h
+++ b/client/portstatsmodel.h
@@ -5,7 +5,19 @@
#include
typedef enum {
- e_STAT_FRAMES_RCVD = 0,
+ // State
+ e_STATE_START = 0,
+
+ e_LINK_STATE = e_STATE_START,
+ e_TRANSMIT_STATE,
+ e_CAPTURE_STATE,
+
+ e_STATE_END = e_CAPTURE_STATE,
+
+ // Statistics
+ e_STATISTICS_START,
+
+ e_STAT_FRAMES_RCVD = e_STATISTICS_START,
e_STAT_FRAMES_SENT,
e_STAT_FRAME_SEND_RATE,
e_STAT_FRAME_RECV_RATE,
@@ -19,10 +31,17 @@ typedef enum {
e_STAT_BYTES_RCVD_NIC,
e_STAT_BYTES_SENT_NIC,
#endif
+
+ e_STATISTICS_END = e_STAT_BYTE_RECV_RATE,
+
e_STAT_MAX
} PortStat;
static QStringList PortStatName = (QStringList()
+ << "Link State"
+ << "Transmit State"
+ << "Capture State"
+
<< "Frames Received"
<< "Frames Sent"
<< "Frame Send Rate (fps)"
@@ -39,6 +58,17 @@ static QStringList PortStatName = (QStringList()
#endif
);
+static QStringList LinkStateName = (QStringList()
+ << "Unknown"
+ << "Down"
+ << "Up"
+);
+
+static QStringList BoolStateName = (QStringList()
+ << "Off"
+ << "On"
+);
+
class PortGroupList;
class PortStatsModel : public QAbstractTableModel
diff --git a/client/portswindow.cpp b/client/portswindow.cpp
index 8b75b65..7d9bbc4 100644
--- a/client/portswindow.cpp
+++ b/client/portswindow.cpp
@@ -36,6 +36,9 @@ PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
this, SLOT(when_portModel_dataChanged(const QModelIndex&,
const QModelIndex&)));
+ connect(plm->getPortModel(), SIGNAL(modelReset()),
+ SLOT(when_portModel_reset()));
+
connect( tvPortList->selectionModel(),
SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
this, SLOT(when_portView_currentChanged(const QModelIndex&,
@@ -139,7 +142,11 @@ void PortsWindow::when_portModel_dataChanged(const QModelIndex& topLeft,
{
updatePortViewActions(tvPortList->currentIndex());
}
-
+}
+
+void PortsWindow::when_portModel_reset()
+{
+ when_portView_currentChanged(QModelIndex(), tvPortList->currentIndex());
}
#if 0
diff --git a/client/portswindow.h b/client/portswindow.h
index a5bc562..b291f91 100644
--- a/client/portswindow.h
+++ b/client/portswindow.h
@@ -40,6 +40,7 @@ private slots:
void when_streamView_selectionChanged();
void when_portModel_dataChanged(const QModelIndex& topLeft,
const QModelIndex& bottomRight);
+ void when_portModel_reset();
void on_pbApply_clicked();
diff --git a/client/portswindow.ui b/client/portswindow.ui
index b58c356..1ed9485 100644
--- a/client/portswindow.ui
+++ b/client/portswindow.ui
@@ -6,7 +6,7 @@
0
0
689
- 389
+ 254
@@ -28,10 +28,28 @@
- 1
+ 0
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 6
+
+
+ 6
+
-
-
@@ -118,11 +136,32 @@
Control
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
-
Qt::ActionsContextMenu
+
+ QFrame::NoFrame
+
+
+ 0
+
QAbstractItemView::ExtendedSelection
diff --git a/common/protocol.proto b/common/protocol.proto
index 1f3c0a5..6557dbb 100644
--- a/common/protocol.proto
+++ b/common/protocol.proto
@@ -128,7 +128,6 @@ message Port {
optional string name = 2;
optional string description = 3;
optional bool is_enabled = 4;
- optional bool is_oper_up = 5;
optional bool is_exclusive_control = 6;
}
@@ -149,9 +148,24 @@ message CaptureBufferList {
repeated CaptureBuffer list = 1;
}
+enum LinkState {
+ LinkStateUnknown = 0;
+ LinkStateDown = 1;
+ LinkStateUp = 2;
+}
+
+message PortState {
+ optional LinkState link_state = 1 [default = LinkStateUnknown];
+ optional bool is_transmit_on = 2 [default = false];
+ optional bool is_capture_on = 3 [default = false];
+}
+
message PortStats {
+
required PortId port_id = 1;
+ optional PortState state = 2;
+
optional uint64 rx_pkts = 11;
optional uint64 rx_bytes = 12;
optional uint64 rx_pkts_nic = 13;
diff --git a/server/myservice.cpp b/server/myservice.cpp
index cb9a2db..54b0895 100644
--- a/server/myservice.cpp
+++ b/server/myservice.cpp
@@ -68,6 +68,20 @@ PortInfo::PortInfo(uint id, pcap_if_t *dev)
this->dev = dev;
+#ifdef Q_OS_WIN32
+ adapter = PacketOpenAdapter(dev->name);
+ if (!adapter)
+ qFatal("Unable to open adapter %s", dev->name);
+ oidData = (PPACKET_OID_DATA) malloc(sizeof(PACKET_OID_DATA) + sizeof(uint));
+ if (oidData)
+ {
+ memset(oidData, 0, sizeof(PACKET_OID_DATA) + sizeof(uint));
+ oidData->Length=sizeof(uint);
+ }
+ else
+ qFatal("failed to alloc oidData");
+#endif
+
/*
* Get 2 device handles - one for rx and one for tx. If we use only
* one handle for both rx and tx anythin that we tx using the single
@@ -131,12 +145,13 @@ PortInfo::PortInfo(uint id, pcap_if_t *dev)
if (dev->description)
d.set_description(dev->description);
d.set_is_enabled(true); //! \todo (LOW) admin enable/disable of port
- d.set_is_oper_up(true); //! \todo (HIGH) oper up/down of port
d.set_is_exclusive_control(false); //! \todo (HIGH) port exclusive control
memset((void*) &stats, 0, sizeof(stats));
resetStats();
+ linkState = OstProto::LinkStateUnknown;
+
// We'll create sendqueue later when required
sendQueueList.clear();
returnToQIdx = -1;
@@ -149,6 +164,35 @@ PortInfo::PortInfo(uint id, pcap_if_t *dev)
monitorTx.start();
}
+void PortInfo::updateLinkState()
+{
+#ifdef Q_OS_WIN32
+ OstProto::LinkState newLinkState
+ = OstProto::LinkStateUnknown;
+
+ memset(oidData, 0, sizeof(PACKET_OID_DATA) + sizeof(uint));
+ oidData->Oid = OID_GEN_MEDIA_CONNECT_STATUS;
+ oidData->Length = sizeof(uint);
+ if (PacketRequest(adapter, 0, oidData))
+ {
+ uint state;
+
+ if (oidData->Length == sizeof(state))
+ {
+ memcpy((void*)&state, (void*)oidData->Data, oidData->Length);
+ if (state == 0)
+ newLinkState = OstProto::LinkStateUp;
+ else if (state == 1)
+ newLinkState = OstProto::LinkStateDown;
+ }
+ }
+
+ linkState = newLinkState;
+#elif defined(Q_OS_LINUX)
+ //! \todo (HI) implement link state for linux - get from /proc maybe?
+#endif
+}
+
void PortInfo::update()
{
uchar pktBuf[2000];
@@ -211,6 +255,9 @@ void PortInfo::update()
{
int len;
+ /*! \todo (HIGH) if pkt contents do not change across
+ pkts then don't call makePacket(), rather reuse the
+ previous */
len = streamList[i]->makePacket(pktBuf, sizeof(pktBuf),
j * numPackets + k);
if (len > 0)
@@ -722,55 +769,60 @@ PortInfo::PortCapture::~PortCapture()
void PortInfo::PortCapture::run()
{
int ret;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ capHandle = pcap_open_live(port->dev->name, 65535,
+ PCAP_OPENFLAG_PROMISCUOUS, 1000 /* ms */, errbuf);
if (capHandle == NULL)
{
- char errbuf[PCAP_ERRBUF_SIZE];
-
- capHandle = pcap_open_live(port->dev->name, 65535,
- PCAP_OPENFLAG_PROMISCUOUS, -1, errbuf);
- if (capHandle == NULL)
- {
- qDebug("Error opening port %s: %s\n",
- port->dev->name, pcap_geterr(capHandle));
- }
+ qDebug("Error opening port %s: %s\n",
+ port->dev->name, pcap_geterr(capHandle));
+ return;
}
+
if (!capFile.isOpen())
{
if (!capFile.open())
qFatal("Unable to open temp cap file");
+ return;
}
qDebug("cap file = %s", capFile.fileName().toAscii().constData());
dumpHandle = pcap_dump_open(capHandle,
capFile.fileName().toAscii().constData());
- ret = pcap_loop(capHandle, -1, pcap_dump, (uchar*) dumpHandle);
- switch (ret)
+ m_stop = 0;
+ while (m_stop == 0)
{
- case -2:
- qDebug("%s: breakloop called %d", __PRETTY_FUNCTION__, ret);
- break;
+ struct pcap_pkthdr *hdr;
+ const uchar *data;
- case -1:
- case 0:
- qFatal("%s: unexpected break from loop (%d): %s",
- __PRETTY_FUNCTION__, ret, pcap_geterr(capHandle));
- break;
- default:
- qFatal("%s: Unexpected return value %d", __PRETTY_FUNCTION__, ret);
+ ret = pcap_next_ex(capHandle, &hdr, &data);
+ switch (ret)
+ {
+ case 1:
+ pcap_dump((uchar*) dumpHandle, hdr, data);
+ case 0:
+ continue;
+ case -1:
+ qWarning("%s: error reading packet (%d): %s",
+ __PRETTY_FUNCTION__, ret, pcap_geterr(capHandle));
+ break;
+ case -2:
+ default:
+ qFatal("%s: Unexpected return value %d", __PRETTY_FUNCTION__, ret);
+ }
}
+ m_stop = 0;
+ pcap_dump_close(dumpHandle);
+ pcap_close(capHandle);
+ dumpHandle = NULL;
+ capHandle = NULL;
}
void PortInfo::PortCapture::stop()
{
- pcap_breakloop(capHandle);
- if (dumpHandle)
- {
- pcap_dump_flush(dumpHandle);
- pcap_dump_close(dumpHandle);
- dumpHandle = NULL;
- }
+ m_stop = 1;
}
QFile* PortInfo::PortCapture::captureFile()
@@ -1200,6 +1252,7 @@ const ::OstProto::PortIdList* request,
{
uint portidx;
::OstProto::PortStats *s;
+ OstProto::PortState *st;
portidx = request->port_id(i).id();
if (portidx >= numPorts)
@@ -1216,6 +1269,13 @@ const ::OstProto::PortIdList* request,
}
#endif
+ portInfo[portidx]->updateLinkState();
+
+ st = s->mutable_state();
+ st->set_link_state(portInfo[portidx]->linkState);
+ st->set_is_transmit_on(portInfo[portidx]->transmitter.isRunning());
+ st->set_is_capture_on(portInfo[portidx]->capturer.isRunning());
+
s->set_rx_pkts(portInfo[portidx]->stats.rxPkts -
portInfo[portidx]->epochStats.rxPkts);
s->set_rx_bytes(portInfo[portidx]->stats.rxBytes -
diff --git a/server/myservice.h b/server/myservice.h
index fb55283..ebd1db1 100644
--- a/server/myservice.h
+++ b/server/myservice.h
@@ -22,6 +22,10 @@
#ifdef Q_OS_WIN32
#include
#endif
+
+#ifdef Q_OS_WIN32
+#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
+#endif
#define MAX_PKT_HDR_SIZE 1536
#define MAX_STREAM_NAME_SIZE 64
@@ -29,6 +33,7 @@
//! 7 byte Preamble + 1 byte SFD + 4 byte FCS
#define ETH_FRAME_HDR_SIZE 12
+
class MyService;
class StreamInfo : public StreamBase
@@ -99,6 +104,7 @@ class PortInfo
friend class PortInfo;
PortInfo *port;
+ int m_stop;
pcap_t *capHandle;
pcap_dumper_t *dumpHandle;
QTemporaryFile capFile;
@@ -110,8 +116,14 @@ class PortInfo
void stop();
QFile* captureFile();
};
+
+#ifdef Q_OS_WIN32
+ LPADAPTER adapter;
+ PPACKET_OID_DATA oidData;
+#endif
OstProto::Port d;
+ OstProto::LinkState linkState;
struct PortStats
{
@@ -167,6 +179,7 @@ class PortInfo
public:
PortInfo(uint id, pcap_if_t *dev);
uint id() { return d.port_id().id(); }
+ void updateLinkState();
bool isDirty() { return isSendQueueDirty; }
void setDirty(bool dirty) { isSendQueueDirty = dirty; }
void update();