- Queued RPC calls would cause crashes due to invalid pointers to request/response and/or controller; this has been fixed - PbRpcController now takes ownership of request and response messages and will delete them when it itself is being deleted - This design mandates that request and response messages for each RPC call have to be allocated on the heap. - The convention for the Closure 'done' call now is to allocate and pass a pointer to the controller object to it which will delete it after use; this requires that controller itself be also allocated on the heap (NOTE: this is just a convention - not mandatory) - All existing RPC calls (in portgroup.cpp) have been changed to follow the above convention - Reordering of queued RPC calls has been fixed - PortManager is now destroyed at exit; because of this fix the per port temporary capture files are auto-removed at exit - WinPcapPort destructor no longer deletes the monitor threads because the parent class PcapPort already does it - Capture does not automatically (and incorrectly) stop after one packet if started immediately after a View Capture operation - User is prompted to stop transmit on a port first if he tries to apply configuration changes on a port in 'transmit' state
186 lines
5.0 KiB
C++
186 lines
5.0 KiB
C++
#include "winpcapport.h"
|
|
|
|
#include <QProcess>
|
|
|
|
#ifdef Q_OS_WIN32
|
|
|
|
const uint OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114;
|
|
|
|
WinPcapPort::WinPcapPort(int id, const char *device)
|
|
: PcapPort(id, device)
|
|
{
|
|
delete monitorRx_;
|
|
delete monitorTx_;
|
|
|
|
monitorRx_ = new PortMonitor(device, kDirectionRx, &stats_);
|
|
monitorTx_ = new PortMonitor(device, kDirectionTx, &stats_);
|
|
|
|
adapter_ = PacketOpenAdapter((CHAR*)device);
|
|
if (!adapter_)
|
|
qFatal("Unable to open adapter %s", device);
|
|
linkStateOid_ = (PPACKET_OID_DATA) malloc(sizeof(PACKET_OID_DATA) +
|
|
sizeof(uint));
|
|
if (!linkStateOid_)
|
|
qFatal("failed to alloc oidData");
|
|
|
|
data_.set_is_exclusive_control(hasExclusiveControl());
|
|
}
|
|
|
|
WinPcapPort::~WinPcapPort()
|
|
{
|
|
}
|
|
|
|
OstProto::LinkState WinPcapPort::linkState()
|
|
{
|
|
memset(linkStateOid_, 0, sizeof(PACKET_OID_DATA) + sizeof(uint));
|
|
|
|
linkStateOid_->Oid = OID_GEN_MEDIA_CONNECT_STATUS;
|
|
linkStateOid_->Length = sizeof(uint);
|
|
|
|
if (PacketRequest(adapter_, 0, linkStateOid_))
|
|
{
|
|
uint state;
|
|
|
|
if (linkStateOid_->Length == sizeof(state))
|
|
{
|
|
memcpy((void*)&state, (void*)linkStateOid_->Data,
|
|
linkStateOid_->Length);
|
|
if (state == 0)
|
|
linkState_ = OstProto::LinkStateUp;
|
|
else if (state == 1)
|
|
linkState_ = OstProto::LinkStateDown;
|
|
}
|
|
}
|
|
|
|
return linkState_;
|
|
}
|
|
|
|
bool WinPcapPort::hasExclusiveControl()
|
|
{
|
|
QString portName(adapter_->Name + strlen("\\Device\\NPF_"));
|
|
int exitCode;
|
|
|
|
qDebug("%s: %s", __FUNCTION__, portName.toAscii().constData());
|
|
|
|
exitCode = QProcess::execute("bindconfig.exe",
|
|
QStringList() << "comp" << portName);
|
|
|
|
qDebug("%s: exit code %d", __FUNCTION__, exitCode);
|
|
|
|
if (exitCode == 0)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
bool WinPcapPort::setExclusiveControl(bool exclusive)
|
|
{
|
|
QString portName(adapter_->Name + strlen("\\Device\\NPF_"));
|
|
QString status;
|
|
|
|
qDebug("%s: %s", __FUNCTION__, portName.toAscii().constData());
|
|
|
|
status = exclusive ? "disable" : "enable";
|
|
|
|
QProcess::execute("bindconfig.exe",
|
|
QStringList() << "comp" << portName << status);
|
|
|
|
updateNotes();
|
|
|
|
return (exclusive == hasExclusiveControl());
|
|
}
|
|
|
|
WinPcapPort::PortMonitor::PortMonitor(const char *device, Direction direction,
|
|
AbstractPort::PortStats *stats)
|
|
: PcapPort::PortMonitor(device, direction, stats)
|
|
{
|
|
pcap_setmode(handle(), MODE_STAT);
|
|
}
|
|
|
|
void WinPcapPort::PortMonitor::run()
|
|
{
|
|
struct timeval lastTs;
|
|
quint64 lastTxPkts = 0;
|
|
quint64 lastTxBytes = 0;
|
|
|
|
qWarning("in %s", __PRETTY_FUNCTION__);
|
|
|
|
lastTs.tv_sec = 0;
|
|
lastTs.tv_usec = 0;
|
|
|
|
while (1)
|
|
{
|
|
int ret;
|
|
struct pcap_pkthdr *hdr;
|
|
const uchar *data;
|
|
|
|
ret = pcap_next_ex(handle(), &hdr, &data);
|
|
switch (ret)
|
|
{
|
|
case 1:
|
|
{
|
|
quint64 pkts = *((quint64*)(data + 0));
|
|
quint64 bytes = *((quint64*)(data + 8));
|
|
|
|
// TODO: is it 12 or 16?
|
|
bytes -= pkts * 12;
|
|
|
|
uint usec = (hdr->ts.tv_sec - lastTs.tv_sec) * 1000000 +
|
|
(hdr->ts.tv_usec - lastTs.tv_usec);
|
|
|
|
switch (direction())
|
|
{
|
|
case kDirectionRx:
|
|
stats_->rxPkts += pkts;
|
|
stats_->rxBytes += bytes;
|
|
stats_->rxPps = (pkts * 1000000) / usec;
|
|
stats_->rxBps = (bytes * 1000000) / usec;
|
|
break;
|
|
|
|
case kDirectionTx:
|
|
if (isDirectional())
|
|
{
|
|
stats_->txPkts += pkts;
|
|
stats_->txBytes += bytes;
|
|
}
|
|
else
|
|
{
|
|
// Assuming stats_->txXXX are updated externally
|
|
quint64 txPkts = stats_->txPkts;
|
|
quint64 txBytes = stats_->txBytes;
|
|
|
|
pkts = txPkts - lastTxPkts;
|
|
bytes = txBytes - lastTxBytes;
|
|
|
|
lastTxPkts = txPkts;
|
|
lastTxBytes = txBytes;
|
|
}
|
|
stats_->txPps = (pkts * 1000000) / usec;
|
|
stats_->txBps = (bytes * 1000000) / usec;
|
|
break;
|
|
|
|
default:
|
|
Q_ASSERT(false);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case 0:
|
|
//qDebug("%s: timeout. continuing ...", __PRETTY_FUNCTION__);
|
|
continue;
|
|
case -1:
|
|
qWarning("%s: error reading packet (%d): %s",
|
|
__PRETTY_FUNCTION__, ret, pcap_geterr(handle()));
|
|
break;
|
|
case -2:
|
|
default:
|
|
qFatal("%s: Unexpected return value %d", __PRETTY_FUNCTION__, ret);
|
|
}
|
|
lastTs.tv_sec = hdr->ts.tv_sec;
|
|
lastTs.tv_usec = hdr->ts.tv_usec;
|
|
QThread::msleep(1000);
|
|
}
|
|
}
|
|
|
|
#endif
|