- Port State (Link/Transmit/Capture) now updated alongwith port stats
    - On link state change, the port window is not updated - partial changes have been done under #if 0; needs refactoring of Port Class implementation/usage before a signal/slot for the same can be implemented

Fixes
  - Fixed crash in client when connection to server is broken
  - Packet Capture and Capture Buffer Retrieval now works correctly and consistently (I think!)

Others
  - Minor visual changes in Ports Window
  - Port Stats Window now has 'right' alignment for stats data and 'center' for state data
This commit is contained in:
Srivats P. 2009-11-08 08:20:34 +00:00
parent 84c7fe1e06
commit ade8c119d9
16 changed files with 257 additions and 46 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

View File

@ -7,6 +7,7 @@
<file>icons/bullet_green.png</file>
<file>icons/bullet_orange.png</file>
<file>icons/bullet_red.png</file>
<file>icons/bullet_white.png</file>
<file>icons/bullet_yellow.png</file>
<file>icons/control_play.png</file>
<file>icons/control_stop.png</file>

View File

@ -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
}

View File

@ -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

View File

@ -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);

View File

@ -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()));

View File

@ -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();
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);
}

View File

@ -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();

View File

@ -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();

View File

@ -5,7 +5,19 @@
#include <QStringList>
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

View File

@ -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

View File

@ -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();

View File

@ -6,7 +6,7 @@
<x>0</x>
<y>0</y>
<width>689</width>
<height>389</height>
<height>254</height>
</rect>
</property>
<property name="windowTitle" >
@ -28,10 +28,28 @@
</widget>
<widget class="QStackedWidget" name="swDetail" >
<property name="currentIndex" >
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="portDetail" >
<layout class="QGridLayout" >
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<property name="horizontalSpacing" >
<number>6</number>
</property>
<property name="verticalSpacing" >
<number>6</number>
</property>
<item row="0" column="0" >
<layout class="QHBoxLayout" >
<item>
@ -118,11 +136,32 @@
<string>Control</string>
</attribute>
<layout class="QHBoxLayout" >
<property name="spacing" >
<number>0</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<widget class="QTableView" name="tvStreamList" >
<property name="contextMenuPolicy" >
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="frameShape" >
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth" >
<number>0</number>
</property>
<property name="selectionMode" >
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>

View File

@ -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;

View File

@ -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;
if (capHandle == NULL)
{
char errbuf[PCAP_ERRBUF_SIZE];
capHandle = pcap_open_live(port->dev->name, 65535,
PCAP_OPENFLAG_PROMISCUOUS, -1, errbuf);
PCAP_OPENFLAG_PROMISCUOUS, 1000 /* ms */, errbuf);
if (capHandle == NULL)
{
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);
m_stop = 0;
while (m_stop == 0)
{
struct pcap_pkthdr *hdr;
const uchar *data;
ret = pcap_next_ex(capHandle, &hdr, &data);
switch (ret)
{
case -2:
qDebug("%s: breakloop called %d", __PRETTY_FUNCTION__, ret);
break;
case -1:
case 1:
pcap_dump((uchar*) dumpHandle, hdr, data);
case 0:
qFatal("%s: unexpected break from loop (%d): %s",
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 -

View File

@ -23,12 +23,17 @@
#include <packet32.h>
#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
//! 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;
@ -111,7 +117,13 @@ class PortInfo
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();