a9da643fb2
Fixes issue 144
227 lines
6.4 KiB
C++
227 lines
6.4 KiB
C++
/*
|
|
Copyright (C) 2010 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 <http://www.gnu.org/licenses/>
|
|
*/
|
|
|
|
#include "winpcapport.h"
|
|
|
|
#include <QCoreApplication>
|
|
#include <QProcess>
|
|
|
|
#ifdef Q_OS_WIN32
|
|
|
|
const uint OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114;
|
|
|
|
WinPcapPort::WinPcapPort(int id, const char *device)
|
|
: PcapPort(id, device)
|
|
{
|
|
monitorRx_->stop();
|
|
monitorTx_->stop();
|
|
monitorRx_->wait();
|
|
monitorTx_->wait();
|
|
|
|
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());
|
|
minPacketSetSize_ = 256;
|
|
}
|
|
|
|
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_"));
|
|
QString bindConfigFilePath(QCoreApplication::applicationDirPath()
|
|
+ "/bindconfig.exe");
|
|
int exitCode;
|
|
|
|
qDebug("%s: %s", __FUNCTION__, portName.toAscii().constData());
|
|
|
|
if (!QFile::exists(bindConfigFilePath))
|
|
return false;
|
|
|
|
exitCode = QProcess::execute(bindConfigFilePath,
|
|
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 bindConfigFilePath(QCoreApplication::applicationDirPath()
|
|
+ "/bindconfig.exe");
|
|
QString status;
|
|
|
|
qDebug("%s: %s", __FUNCTION__, portName.toAscii().constData());
|
|
|
|
if (!QFile::exists(bindConfigFilePath))
|
|
return false;
|
|
|
|
status = exclusive ? "disable" : "enable";
|
|
|
|
QProcess::execute(bindConfigFilePath,
|
|
QStringList() << "comp" << portName << status);
|
|
|
|
updateNotes();
|
|
|
|
return (exclusive == hasExclusiveControl());
|
|
}
|
|
|
|
WinPcapPort::PortMonitor::PortMonitor(const char *device, Direction direction,
|
|
AbstractPort::PortStats *stats)
|
|
: PcapPort::PortMonitor(device, direction, stats)
|
|
{
|
|
if (handle())
|
|
pcap_setmode(handle(), MODE_STAT);
|
|
}
|
|
|
|
void WinPcapPort::PortMonitor::run()
|
|
{
|
|
struct timeval lastTs;
|
|
quint64 lastTxPkts = 0;
|
|
quint64 lastTxBytes = 0;
|
|
|
|
qDebug("in %s", __PRETTY_FUNCTION__);
|
|
|
|
lastTs.tv_sec = 0;
|
|
lastTs.tv_usec = 0;
|
|
|
|
while (!stop_)
|
|
{
|
|
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:
|
|
qWarning("%s: error reading packet (%d): %s",
|
|
__PRETTY_FUNCTION__, ret, pcap_geterr(handle()));
|
|
break;
|
|
default:
|
|
qFatal("%s: Unexpected return value %d", __PRETTY_FUNCTION__, ret);
|
|
}
|
|
lastTs.tv_sec = hdr->ts.tv_sec;
|
|
lastTs.tv_usec = hdr->ts.tv_usec;
|
|
if (!stop_)
|
|
QThread::msleep(1000);
|
|
}
|
|
}
|
|
|
|
#endif
|