Merge branch 'master' of https://github.com/pstavirs/ostinato into emul
Conflicts: server/pcapport.cpp
This commit is contained in:
commit
c022290da1
@ -6,7 +6,7 @@ Ostinato is an open-source, cross-platform network packet crafter/traffic genera
|
|||||||
|
|
||||||
Ostinato aims to be "Wireshark in Reverse" and become complementary to Wireshark.
|
Ostinato aims to be "Wireshark in Reverse" and become complementary to Wireshark.
|
||||||
|
|
||||||
License: GPLv3+ (see COPYING)
|
License: GPLv3+ (see [COPYING](https://raw.githubusercontent.com/pstavirs/ostinato/master/COPYING))
|
||||||
|
|
||||||
For more information visit http://ostinato.org.
|
For more information visit http://ostinato.org.
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ extern char *version;
|
|||||||
|
|
||||||
quint32 PortGroup::mPortGroupAllocId = 0;
|
quint32 PortGroup::mPortGroupAllocId = 0;
|
||||||
|
|
||||||
PortGroup::PortGroup(QHostAddress ip, quint16 port)
|
PortGroup::PortGroup(QString serverName, quint16 port)
|
||||||
{
|
{
|
||||||
// Allocate an id for self
|
// Allocate an id for self
|
||||||
mPortGroupId = PortGroup::mPortGroupAllocId++;
|
mPortGroupId = PortGroup::mPortGroupAllocId++;
|
||||||
@ -57,7 +57,7 @@ PortGroup::PortGroup(QHostAddress ip, quint16 port)
|
|||||||
connect(reconnectTimer, SIGNAL(timeout()),
|
connect(reconnectTimer, SIGNAL(timeout()),
|
||||||
this, SLOT(on_reconnectTimer_timeout()));
|
this, SLOT(on_reconnectTimer_timeout()));
|
||||||
|
|
||||||
rpcChannel = new PbRpcChannel(ip, port,
|
rpcChannel = new PbRpcChannel(serverName, port,
|
||||||
OstProto::Notification::default_instance());
|
OstProto::Notification::default_instance());
|
||||||
serviceStub = new OstProto::OstService::Stub(rpcChannel);
|
serviceStub = new OstProto::OstService::Stub(rpcChannel);
|
||||||
|
|
||||||
@ -272,7 +272,7 @@ void PortGroup::when_portListChanged(quint32 /*portGroupId*/)
|
|||||||
"For more information see "
|
"For more information see "
|
||||||
"http://code.google.com/p/ostinato/wiki/FAQ#"
|
"http://code.google.com/p/ostinato/wiki/FAQ#"
|
||||||
"Q._Port_group_has_no_interfaces")
|
"Q._Port_group_has_no_interfaces")
|
||||||
.arg(serverAddress().toString())
|
.arg(serverName())
|
||||||
.arg(int(serverPort())));
|
.arg(int(serverPort())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ public: // FIXME(HIGH): member access
|
|||||||
QList<Port*> mPorts;
|
QList<Port*> mPorts;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PortGroup(QHostAddress ip = QHostAddress::LocalHost,
|
PortGroup(QString serverName = "127.0.0.1",
|
||||||
quint16 port = DEFAULT_SERVER_PORT);
|
quint16 port = DEFAULT_SERVER_PORT);
|
||||||
~PortGroup();
|
~PortGroup();
|
||||||
|
|
||||||
@ -75,10 +75,10 @@ public:
|
|||||||
compat = kUnknown;
|
compat = kUnknown;
|
||||||
rpcChannel->establish();
|
rpcChannel->establish();
|
||||||
}
|
}
|
||||||
void connectToHost(QHostAddress ip, quint16 port) {
|
void connectToHost(QString serverName, quint16 port) {
|
||||||
reconnect = true;
|
reconnect = true;
|
||||||
compat = kUnknown;
|
compat = kUnknown;
|
||||||
rpcChannel->establish(ip, port);
|
rpcChannel->establish(serverName, port);
|
||||||
}
|
}
|
||||||
void disconnectFromHost() { reconnect = false; rpcChannel->tearDown(); }
|
void disconnectFromHost() { reconnect = false; rpcChannel->tearDown(); }
|
||||||
|
|
||||||
@ -88,8 +88,8 @@ public:
|
|||||||
const QString& userAlias() const { return mUserAlias; }
|
const QString& userAlias() const { return mUserAlias; }
|
||||||
void setUserAlias(QString alias) { mUserAlias = alias; };
|
void setUserAlias(QString alias) { mUserAlias = alias; };
|
||||||
|
|
||||||
const QHostAddress& serverAddress() const
|
const QString serverName() const
|
||||||
{ return rpcChannel->serverAddress(); }
|
{ return rpcChannel->serverName(); }
|
||||||
quint16 serverPort() const
|
quint16 serverPort() const
|
||||||
{ return rpcChannel->serverPort(); }
|
{ return rpcChannel->serverPort(); }
|
||||||
QAbstractSocket::SocketState state() const {
|
QAbstractSocket::SocketState state() const {
|
||||||
|
@ -121,10 +121,10 @@ QVariant PortModel::data(const QModelIndex &index, int role) const
|
|||||||
if ((role == Qt::DisplayRole))
|
if ((role == Qt::DisplayRole))
|
||||||
{
|
{
|
||||||
DBG0("Exit PortModel data 1\n");
|
DBG0("Exit PortModel data 1\n");
|
||||||
return QString("Port Group %1: %2 [%3:%4] (%5)").
|
return QString("Port Group %1: %2 [%3]:%4 (%5)").
|
||||||
arg(pgl->mPortGroups.at(index.row())->id()).
|
arg(pgl->mPortGroups.at(index.row())->id()).
|
||||||
arg(pgl->mPortGroups.at(index.row())->userAlias()).
|
arg(pgl->mPortGroups.at(index.row())->userAlias()).
|
||||||
arg(pgl->mPortGroups.at(index.row())->serverAddress().toString()).
|
arg(pgl->mPortGroups.at(index.row())->serverName()).
|
||||||
arg(pgl->mPortGroups.at(index.row())->serverPort()).
|
arg(pgl->mPortGroups.at(index.row())->serverPort()).
|
||||||
arg(pgl->mPortGroups.value(index.row())->numPorts());
|
arg(pgl->mPortGroups.value(index.row())->numPorts());
|
||||||
}
|
}
|
||||||
|
@ -503,15 +503,29 @@ void PortsWindow::on_actionNew_Port_Group_triggered()
|
|||||||
{
|
{
|
||||||
bool ok;
|
bool ok;
|
||||||
QString text = QInputDialog::getText(this,
|
QString text = QInputDialog::getText(this,
|
||||||
"Add Port Group", "Port Group Address (IP[:Port])",
|
"Add Port Group", "Port Group Address (HostName[:Port])",
|
||||||
QLineEdit::Normal, lastNewPortGroup, &ok);
|
QLineEdit::Normal, lastNewPortGroup, &ok);
|
||||||
|
|
||||||
if (ok)
|
if (ok)
|
||||||
{
|
{
|
||||||
QStringList addr = text.split(":");
|
QStringList addr = text.split(":");
|
||||||
if (addr.size() == 1) // Port unspecified
|
quint16 port = DEFAULT_SERVER_PORT;
|
||||||
addr.append(QString().setNum(DEFAULT_SERVER_PORT));
|
|
||||||
PortGroup *pg = new PortGroup(QHostAddress(addr[0]),addr[1].toUShort());
|
if (addr.size() > 2) { // IPv6 Address
|
||||||
|
// IPv6 addresses with port number SHOULD be specified as
|
||||||
|
// [2001:db8::1]:80 (RFC5952 Sec6) to avoid ambiguity due to ':'
|
||||||
|
addr = text.split("]:");
|
||||||
|
if (addr.size() > 1)
|
||||||
|
port = addr[1].toUShort();
|
||||||
|
}
|
||||||
|
else if (addr.size() == 2) // Hostname/IPv4 + Port specified
|
||||||
|
port = addr[1].toUShort();
|
||||||
|
|
||||||
|
// Play nice and remove square brackets irrespective of addr type
|
||||||
|
addr[0].remove(QChar('['));
|
||||||
|
addr[0].remove(QChar(']'));
|
||||||
|
|
||||||
|
PortGroup *pg = new PortGroup(addr[0], port);
|
||||||
plm->addPortGroup(*pg);
|
plm->addPortGroup(*pg);
|
||||||
lastNewPortGroup = text;
|
lastNewPortGroup = text;
|
||||||
}
|
}
|
||||||
|
@ -447,6 +447,27 @@ _exit:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int StreamBase::frameSizeVariableCount() const
|
||||||
|
{
|
||||||
|
int count = 1;
|
||||||
|
|
||||||
|
switch(lenMode())
|
||||||
|
{
|
||||||
|
case OstProto::StreamCore::e_fl_fixed:
|
||||||
|
break;
|
||||||
|
case OstProto::StreamCore::e_fl_inc:
|
||||||
|
case OstProto::StreamCore::e_fl_dec:
|
||||||
|
case OstProto::StreamCore::e_fl_random:
|
||||||
|
count = frameLenMax() - frameLenMin() + 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qWarning("%s: Unhandled len mode %d", __FUNCTION__, lenMode());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
int StreamBase::frameVariableCount() const
|
int StreamBase::frameVariableCount() const
|
||||||
{
|
{
|
||||||
ProtocolListIterator *iter;
|
ProtocolListIterator *iter;
|
||||||
@ -469,7 +490,7 @@ int StreamBase::frameVariableCount() const
|
|||||||
}
|
}
|
||||||
delete iter;
|
delete iter;
|
||||||
|
|
||||||
return frameCount;
|
return AbstractProtocol::lcm(frameCount, frameSizeVariableCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
// frameProtocolLength() returns the sum of all the individual protocol sizes
|
// frameProtocolLength() returns the sum of all the individual protocol sizes
|
||||||
|
@ -131,6 +131,7 @@ public:
|
|||||||
|
|
||||||
bool isFrameVariable() const;
|
bool isFrameVariable() const;
|
||||||
bool isFrameSizeVariable() const;
|
bool isFrameSizeVariable() const;
|
||||||
|
int frameSizeVariableCount() const;
|
||||||
int frameVariableCount() const;
|
int frameVariableCount() const;
|
||||||
int frameProtocolLength(int frameIndex) const;
|
int frameProtocolLength(int frameIndex) const;
|
||||||
int frameCount() const;
|
int frameCount() const;
|
||||||
|
@ -25,7 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
static uchar msgBuf[4096];
|
static uchar msgBuf[4096];
|
||||||
|
|
||||||
PbRpcChannel::PbRpcChannel(QHostAddress ip, quint16 port,
|
PbRpcChannel::PbRpcChannel(QString serverName, quint16 port,
|
||||||
const ::google::protobuf::Message ¬ifProto)
|
const ::google::protobuf::Message ¬ifProto)
|
||||||
: notifPrototype(notifProto)
|
: notifPrototype(notifProto)
|
||||||
{
|
{
|
||||||
@ -36,7 +36,7 @@ PbRpcChannel::PbRpcChannel(QHostAddress ip, quint16 port,
|
|||||||
done = NULL;
|
done = NULL;
|
||||||
response = NULL;
|
response = NULL;
|
||||||
|
|
||||||
mServerAddress = ip;
|
mServerHost = serverName;
|
||||||
mServerPort = port;
|
mServerPort = port;
|
||||||
mpSocket = new QTcpSocket(this);
|
mpSocket = new QTcpSocket(this);
|
||||||
|
|
||||||
@ -75,12 +75,12 @@ void PbRpcChannel::establish()
|
|||||||
{
|
{
|
||||||
qDebug("In %s", __FUNCTION__);
|
qDebug("In %s", __FUNCTION__);
|
||||||
|
|
||||||
mpSocket->connectToHost(mServerAddress, mServerPort);
|
mpSocket->connectToHost(mServerHost, mServerPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbRpcChannel::establish(QHostAddress ip, quint16 port)
|
void PbRpcChannel::establish(QString serverName, quint16 port)
|
||||||
{
|
{
|
||||||
mServerAddress = ip;
|
mServerHost = serverName;
|
||||||
mServerPort = port;
|
mServerPort = port;
|
||||||
establish();
|
establish();
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#ifndef _PB_RPC_CHANNEL_H
|
#ifndef _PB_RPC_CHANNEL_H
|
||||||
#define _PB_RPC_CHANNEL_H
|
#define _PB_RPC_CHANNEL_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ class PbRpcChannel : public QObject, public ::google::protobuf::RpcChannel
|
|||||||
const ::google::protobuf::Message ¬ifPrototype;
|
const ::google::protobuf::Message ¬ifPrototype;
|
||||||
::google::protobuf::Message *notif;
|
::google::protobuf::Message *notif;
|
||||||
|
|
||||||
QHostAddress mServerAddress;
|
QString mServerHost;
|
||||||
quint16 mServerPort;
|
quint16 mServerPort;
|
||||||
QTcpSocket *mpSocket;
|
QTcpSocket *mpSocket;
|
||||||
|
|
||||||
@ -72,15 +73,18 @@ class PbRpcChannel : public QObject, public ::google::protobuf::RpcChannel
|
|||||||
::google::protobuf::io::CopyingOutputStreamAdaptor *outStream;
|
::google::protobuf::io::CopyingOutputStreamAdaptor *outStream;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PbRpcChannel(QHostAddress ip, quint16 port,
|
PbRpcChannel(QString serverName, quint16 port,
|
||||||
const ::google::protobuf::Message ¬ifProto);
|
const ::google::protobuf::Message ¬ifProto);
|
||||||
~PbRpcChannel();
|
~PbRpcChannel();
|
||||||
|
|
||||||
void establish();
|
void establish();
|
||||||
void establish(QHostAddress ip, quint16 port);
|
void establish(QString serverName, quint16 port);
|
||||||
void tearDown();
|
void tearDown();
|
||||||
|
|
||||||
const QHostAddress& serverAddress() const { return mServerAddress; }
|
const QString serverName() const
|
||||||
|
{
|
||||||
|
return mpSocket->peerName();
|
||||||
|
}
|
||||||
quint16 serverPort() const { return mServerPort; }
|
quint16 serverPort() const { return mServerPort; }
|
||||||
|
|
||||||
QAbstractSocket::SocketState state() const
|
QAbstractSocket::SocketState state() const
|
||||||
|
@ -43,13 +43,14 @@ RpcServer::~RpcServer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool RpcServer::registerService(::google::protobuf::Service *service,
|
bool RpcServer::registerService(::google::protobuf::Service *service,
|
||||||
quint16 tcpPortNum)
|
QHostAddress address, quint16 tcpPortNum)
|
||||||
{
|
{
|
||||||
this->service = service;
|
this->service = service;
|
||||||
|
|
||||||
if (!listen(QHostAddress::Any, tcpPortNum))
|
if (!listen(address, tcpPortNum))
|
||||||
{
|
{
|
||||||
qDebug("Unable to start the server: %s",
|
qDebug("Unable to start the server on <%s>: %s",
|
||||||
|
qPrintable(address.toString()),
|
||||||
errorString().toAscii().constData());
|
errorString().toAscii().constData());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ public:
|
|||||||
virtual ~RpcServer();
|
virtual ~RpcServer();
|
||||||
|
|
||||||
bool registerService(::google::protobuf::Service *service,
|
bool registerService(::google::protobuf::Service *service,
|
||||||
quint16 tcpPortNum);
|
QHostAddress address, quint16 tcpPortNum);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void notifyClients(int notifType, SharedProtobufMessage notifData);
|
void notifyClients(int notifType, SharedProtobufMessage notifData);
|
||||||
|
@ -45,6 +45,7 @@ AbstractPort::AbstractPort(int id, const char *device)
|
|||||||
data_.set_is_exclusive_control(false);
|
data_.set_is_exclusive_control(false);
|
||||||
|
|
||||||
isSendQueueDirty_ = false;
|
isSendQueueDirty_ = false;
|
||||||
|
rateAccuracy_ = kHighAccuracy;
|
||||||
linkState_ = OstProto::LinkStateUnknown;
|
linkState_ = OstProto::LinkStateUnknown;
|
||||||
minPacketSetSize_ = 1;
|
minPacketSetSize_ = 1;
|
||||||
|
|
||||||
@ -154,6 +155,17 @@ void AbstractPort::addNote(QString note)
|
|||||||
data_.set_notes(notes.toStdString());
|
data_.set_notes(notes.toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AbstractPort::Accuracy AbstractPort::rateAccuracy()
|
||||||
|
{
|
||||||
|
return rateAccuracy_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractPort::setRateAccuracy(Accuracy accuracy)
|
||||||
|
{
|
||||||
|
rateAccuracy_ = accuracy;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void AbstractPort::updatePacketList()
|
void AbstractPort::updatePacketList()
|
||||||
{
|
{
|
||||||
switch(data_.transmit_mode())
|
switch(data_.transmit_mode())
|
||||||
|
@ -54,6 +54,13 @@ public:
|
|||||||
quint64 txBps;
|
quint64 txBps;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Accuracy
|
||||||
|
{
|
||||||
|
kHighAccuracy,
|
||||||
|
kMediumAccuracy,
|
||||||
|
kLowAccuracy,
|
||||||
|
};
|
||||||
|
|
||||||
AbstractPort(int id, const char *device);
|
AbstractPort(int id, const char *device);
|
||||||
virtual ~AbstractPort();
|
virtual ~AbstractPort();
|
||||||
|
|
||||||
@ -80,6 +87,9 @@ public:
|
|||||||
bool isDirty() { return isSendQueueDirty_; }
|
bool isDirty() { return isSendQueueDirty_; }
|
||||||
void setDirty() { isSendQueueDirty_ = true; }
|
void setDirty() { isSendQueueDirty_ = true; }
|
||||||
|
|
||||||
|
Accuracy rateAccuracy();
|
||||||
|
virtual bool setRateAccuracy(Accuracy accuracy);
|
||||||
|
|
||||||
virtual void clearPacketList() = 0;
|
virtual void clearPacketList() = 0;
|
||||||
virtual void loopNextPacketSet(qint64 size, qint64 repeats,
|
virtual void loopNextPacketSet(qint64 size, qint64 repeats,
|
||||||
long repeatDelaySec, long repeatDelayNsec) = 0;
|
long repeatDelaySec, long repeatDelayNsec) = 0;
|
||||||
@ -122,6 +132,7 @@ protected:
|
|||||||
OstProto::Port data_;
|
OstProto::Port data_;
|
||||||
OstProto::LinkState linkState_;
|
OstProto::LinkState linkState_;
|
||||||
ulong minPacketSetSize_;
|
ulong minPacketSetSize_;
|
||||||
|
Accuracy rateAccuracy_;
|
||||||
|
|
||||||
quint64 maxStatsValue_;
|
quint64 maxStatsValue_;
|
||||||
struct PortStats stats_;
|
struct PortStats stats_;
|
||||||
|
@ -19,8 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
#include "drone.h"
|
#include "drone.h"
|
||||||
|
|
||||||
#include "rpcserver.h"
|
|
||||||
#include "myservice.h"
|
#include "myservice.h"
|
||||||
|
#include "rpcserver.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
|
|
||||||
@ -43,11 +44,21 @@ Drone::~Drone()
|
|||||||
|
|
||||||
bool Drone::init()
|
bool Drone::init()
|
||||||
{
|
{
|
||||||
|
QString addr = appSettings->value(kRpcServerAddress).toString();
|
||||||
|
QHostAddress address = addr.isEmpty() ?
|
||||||
|
QHostAddress::Any : QHostAddress(addr);
|
||||||
|
|
||||||
Q_ASSERT(rpcServer);
|
Q_ASSERT(rpcServer);
|
||||||
|
|
||||||
qRegisterMetaType<SharedProtobufMessage>("SharedProtobufMessage");
|
qRegisterMetaType<SharedProtobufMessage>("SharedProtobufMessage");
|
||||||
|
|
||||||
if (!rpcServer->registerService(service, myport ? myport : 7878))
|
if (address.isNull()) {
|
||||||
|
qWarning("Invalid RpcServer Address <%s> specified. Using 'Any'",
|
||||||
|
qPrintable(addr));
|
||||||
|
address = QHostAddress::Any;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rpcServer->registerService(service, address, myport ? myport : 7878))
|
||||||
{
|
{
|
||||||
//qCritical(qPrintable(rpcServer->errorString()));
|
//qCritical(qPrintable(rpcServer->errorString()));
|
||||||
return false;
|
return false;
|
||||||
|
@ -172,6 +172,15 @@ void PcapPort::updateNotes()
|
|||||||
arg(notes).toStdString());
|
arg(notes).toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PcapPort::setRateAccuracy(AbstractPort::Accuracy accuracy)
|
||||||
|
{
|
||||||
|
if (transmitter_->setRateAccuracy(accuracy)) {
|
||||||
|
AbstractPort::setRateAccuracy(accuracy);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void PcapPort::startDeviceEmulation()
|
void PcapPort::startDeviceEmulation()
|
||||||
{
|
{
|
||||||
emulXcvr_->start();
|
emulXcvr_->start();
|
||||||
@ -187,7 +196,6 @@ int PcapPort::sendEmulationPacket(PacketBuffer *pktBuf)
|
|||||||
return emulXcvr_->transmitPacket(pktBuf);
|
return emulXcvr_->transmitPacket(pktBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ------------------------------------------------------------------- *
|
* ------------------------------------------------------------------- *
|
||||||
* Port Monitor
|
* Port Monitor
|
||||||
@ -350,7 +358,7 @@ PcapPort::PortTransmitter::PortTransmitter(const char *device)
|
|||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
LARGE_INTEGER freq;
|
LARGE_INTEGER freq;
|
||||||
if (QueryPerformanceFrequency(&freq))
|
if (QueryPerformanceFrequency(&freq))
|
||||||
gTicksFreq = ticksFreq_ = freq.QuadPart;
|
gTicksFreq = freq.QuadPart;
|
||||||
else
|
else
|
||||||
Q_ASSERT_X(false, "PortTransmitter::PortTransmitter",
|
Q_ASSERT_X(false, "PortTransmitter::PortTransmitter",
|
||||||
"This Win32 platform does not support performance counter");
|
"This Win32 platform does not support performance counter");
|
||||||
@ -383,6 +391,26 @@ PcapPort::PortTransmitter::~PortTransmitter()
|
|||||||
pcap_close(handle_);
|
pcap_close(handle_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PcapPort::PortTransmitter::setRateAccuracy(
|
||||||
|
AbstractPort::Accuracy accuracy)
|
||||||
|
{
|
||||||
|
switch (accuracy) {
|
||||||
|
case kHighAccuracy:
|
||||||
|
udelayFn_ = udelay;
|
||||||
|
qWarning("%s: rate accuracy set to High - busy wait", __FUNCTION__);
|
||||||
|
break;
|
||||||
|
case kLowAccuracy:
|
||||||
|
udelayFn_ = QThread::usleep;
|
||||||
|
qWarning("%s: rate accuracy set to Low - usleep", __FUNCTION__);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qWarning("%s: unsupported rate accuracy value %d", __FUNCTION__,
|
||||||
|
accuracy);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void PcapPort::PortTransmitter::clearPacketList()
|
void PcapPort::PortTransmitter::clearPacketList()
|
||||||
{
|
{
|
||||||
Q_ASSERT(!isRunning());
|
Q_ASSERT(!isRunning());
|
||||||
@ -585,7 +613,7 @@ _restart:
|
|||||||
long usecs = seq->usecDelay_ + overHead;
|
long usecs = seq->usecDelay_ + overHead;
|
||||||
if (usecs > 0)
|
if (usecs > 0)
|
||||||
{
|
{
|
||||||
udelay(usecs);
|
(*udelayFn_)(usecs);
|
||||||
overHead = 0;
|
overHead = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -611,7 +639,7 @@ _restart:
|
|||||||
|
|
||||||
if (usecs > 0)
|
if (usecs > 0)
|
||||||
{
|
{
|
||||||
udelay(usecs);
|
(*udelayFn_)(usecs);
|
||||||
overHead = 0;
|
overHead = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -687,7 +715,7 @@ int PcapPort::PortTransmitter::sendQueueTransmit(pcap_t *p,
|
|||||||
usec += overHead;
|
usec += overHead;
|
||||||
if (usec > 0)
|
if (usec > 0)
|
||||||
{
|
{
|
||||||
udelay(usec);
|
(*udelayFn_)(usec);
|
||||||
overHead = 0;
|
overHead = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -716,14 +744,14 @@ int PcapPort::PortTransmitter::sendQueueTransmit(pcap_t *p,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PcapPort::PortTransmitter::udelay(long usec)
|
void PcapPort::PortTransmitter::udelay(unsigned long usec)
|
||||||
{
|
{
|
||||||
#if defined(Q_OS_WIN32)
|
#if defined(Q_OS_WIN32)
|
||||||
LARGE_INTEGER tgtTicks;
|
LARGE_INTEGER tgtTicks;
|
||||||
LARGE_INTEGER curTicks;
|
LARGE_INTEGER curTicks;
|
||||||
|
|
||||||
QueryPerformanceCounter(&curTicks);
|
QueryPerformanceCounter(&curTicks);
|
||||||
tgtTicks.QuadPart = curTicks.QuadPart + (usec*ticksFreq_)/1000000;
|
tgtTicks.QuadPart = curTicks.QuadPart + (usec*gTicksFreq)/1000000;
|
||||||
|
|
||||||
while (curTicks.QuadPart < tgtTicks.QuadPart)
|
while (curTicks.QuadPart < tgtTicks.QuadPart)
|
||||||
QueryPerformanceCounter(&curTicks);
|
QueryPerformanceCounter(&curTicks);
|
||||||
|
@ -38,6 +38,8 @@ public:
|
|||||||
virtual bool hasExclusiveControl() { return false; }
|
virtual bool hasExclusiveControl() { return false; }
|
||||||
virtual bool setExclusiveControl(bool /*exclusive*/) { return false; }
|
virtual bool setExclusiveControl(bool /*exclusive*/) { return false; }
|
||||||
|
|
||||||
|
virtual bool setRateAccuracy(AbstractPort::Accuracy accuracy);
|
||||||
|
|
||||||
virtual void clearPacketList() {
|
virtual void clearPacketList() {
|
||||||
transmitter_->clearPacketList();
|
transmitter_->clearPacketList();
|
||||||
setPacketListLoopMode(false, 0, 0);
|
setPacketListLoopMode(false, 0, 0);
|
||||||
@ -106,6 +108,9 @@ protected:
|
|||||||
public:
|
public:
|
||||||
PortTransmitter(const char *device);
|
PortTransmitter(const char *device);
|
||||||
~PortTransmitter();
|
~PortTransmitter();
|
||||||
|
|
||||||
|
bool setRateAccuracy(AbstractPort::Accuracy accuracy);
|
||||||
|
|
||||||
void clearPacketList();
|
void clearPacketList();
|
||||||
void loopNextPacketSet(qint64 size, qint64 repeats,
|
void loopNextPacketSet(qint64 size, qint64 repeats,
|
||||||
long repeatDelaySec, long repeatDelayNsec);
|
long repeatDelaySec, long repeatDelayNsec);
|
||||||
@ -176,11 +181,10 @@ protected:
|
|||||||
long usecDelay_;
|
long usecDelay_;
|
||||||
};
|
};
|
||||||
|
|
||||||
void udelay(long usec);
|
static void udelay(unsigned long usec);
|
||||||
int sendQueueTransmit(pcap_t *p, pcap_send_queue *queue, long &overHead,
|
int sendQueueTransmit(pcap_t *p, pcap_send_queue *queue, long &overHead,
|
||||||
int sync);
|
int sync);
|
||||||
|
|
||||||
quint64 ticksFreq_;
|
|
||||||
QList<PacketSequence*> packetSequenceList_;
|
QList<PacketSequence*> packetSequenceList_;
|
||||||
PacketSequence *currentPacketSequence_;
|
PacketSequence *currentPacketSequence_;
|
||||||
int repeatSequenceStart_;
|
int repeatSequenceStart_;
|
||||||
@ -190,6 +194,8 @@ protected:
|
|||||||
int returnToQIdx_;
|
int returnToQIdx_;
|
||||||
quint64 loopDelay_;
|
quint64 loopDelay_;
|
||||||
|
|
||||||
|
void (*udelayFn_)(unsigned long);
|
||||||
|
|
||||||
bool usingInternalStats_;
|
bool usingInternalStats_;
|
||||||
AbstractPort::PortStats *stats_;
|
AbstractPort::PortStats *stats_;
|
||||||
bool usingInternalHandle_;
|
bool usingInternalHandle_;
|
||||||
|
@ -36,12 +36,15 @@ PortManager::PortManager()
|
|||||||
pcap_if_t *deviceList;
|
pcap_if_t *deviceList;
|
||||||
pcap_if_t *device;
|
pcap_if_t *device;
|
||||||
char errbuf[PCAP_ERRBUF_SIZE];
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||||||
|
AbstractPort::Accuracy txRateAccuracy;
|
||||||
|
|
||||||
qDebug("Retrieving the device list from the local machine\n");
|
qDebug("Retrieving the device list from the local machine\n");
|
||||||
|
|
||||||
if (pcap_findalldevs(&deviceList, errbuf) == -1)
|
if (pcap_findalldevs(&deviceList, errbuf) == -1)
|
||||||
qDebug("Error in pcap_findalldevs_ex: %s\n", errbuf);
|
qDebug("Error in pcap_findalldevs_ex: %s\n", errbuf);
|
||||||
|
|
||||||
|
txRateAccuracy = rateAccuracy();
|
||||||
|
|
||||||
for(device = deviceList, i = 0; device != NULL; device = device->next, i++)
|
for(device = deviceList, i = 0; device != NULL; device = device->next, i++)
|
||||||
{
|
{
|
||||||
AbstractPort *port;
|
AbstractPort *port;
|
||||||
@ -81,6 +84,9 @@ PortManager::PortManager()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!port->setRateAccuracy(txRateAccuracy))
|
||||||
|
qWarning("failed to set rateAccuracy (%d)", txRateAccuracy);
|
||||||
|
|
||||||
portList_.append(port);
|
portList_.append(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +112,21 @@ PortManager* PortManager::instance()
|
|||||||
return instance_;
|
return instance_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AbstractPort::Accuracy PortManager::rateAccuracy()
|
||||||
|
{
|
||||||
|
QString rateAccuracy = appSettings->value(kRateAccuracyKey,
|
||||||
|
kRateAccuracyDefaultValue).toString();
|
||||||
|
if (rateAccuracy == "High")
|
||||||
|
return AbstractPort::kHighAccuracy;
|
||||||
|
else if (rateAccuracy == "Low")
|
||||||
|
return AbstractPort::kLowAccuracy;
|
||||||
|
else
|
||||||
|
qWarning("Unsupported RateAccuracy setting - %s",
|
||||||
|
qPrintable(rateAccuracy));
|
||||||
|
|
||||||
|
return AbstractPort::kHighAccuracy;
|
||||||
|
}
|
||||||
|
|
||||||
bool PortManager::filterAcceptsPort(const char *name)
|
bool PortManager::filterAcceptsPort(const char *name)
|
||||||
{
|
{
|
||||||
QRegExp pattern;
|
QRegExp pattern;
|
||||||
|
@ -35,6 +35,7 @@ public:
|
|||||||
static PortManager* instance();
|
static PortManager* instance();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
AbstractPort::Accuracy rateAccuracy();
|
||||||
bool filterAcceptsPort(const char *name);
|
bool filterAcceptsPort(const char *name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -25,6 +25,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
extern QSettings *appSettings;
|
extern QSettings *appSettings;
|
||||||
|
|
||||||
|
//
|
||||||
|
// General Section Keys
|
||||||
|
//
|
||||||
|
const QString kRateAccuracyKey("RateAccuracy");
|
||||||
|
const QString kRateAccuracyDefaultValue("High");
|
||||||
|
|
||||||
|
//
|
||||||
|
// RpcServer Section Keys
|
||||||
|
//
|
||||||
|
const QString kRpcServerAddress("RpcServer/Address");
|
||||||
|
|
||||||
//
|
//
|
||||||
// PortList Section Keys
|
// PortList Section Keys
|
||||||
//
|
//
|
||||||
|
214
test/pktlentest.py
Normal file
214
test/pktlentest.py
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
# standard modules
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
from harness import extract_column
|
||||||
|
|
||||||
|
sys.path.insert(1, '../binding')
|
||||||
|
from core import ost_pb, DroneProxy
|
||||||
|
from rpc import RpcError
|
||||||
|
#from protocols.mac_pb2 import mac
|
||||||
|
#from protocols.payload_pb2 import payload, Payload
|
||||||
|
|
||||||
|
# initialize defaults
|
||||||
|
host_name = '127.0.0.1'
|
||||||
|
tx_number = -1
|
||||||
|
rx_number = -1
|
||||||
|
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
tshark = r'C:\Program Files\Wireshark\tshark.exe'
|
||||||
|
else:
|
||||||
|
tshark = 'tshark'
|
||||||
|
|
||||||
|
fmt = 'column.format:"Packet#","%m","Time","%t","Source","%uns","Destination","%und","Protocol","%p","Size","%L","Info","%i","Expert","%a"'
|
||||||
|
fmt_col = 7 # col# in fmt for Size/PktLength
|
||||||
|
|
||||||
|
# setup protocol number dictionary
|
||||||
|
proto_number = {}
|
||||||
|
proto_number['mac'] = ost_pb.Protocol.kMacFieldNumber
|
||||||
|
proto_number['eth2'] = ost_pb.Protocol.kEth2FieldNumber
|
||||||
|
proto_number['ip4'] = ost_pb.Protocol.kIp4FieldNumber
|
||||||
|
proto_number['udp'] = ost_pb.Protocol.kUdpFieldNumber
|
||||||
|
proto_number['payload'] = ost_pb.Protocol.kPayloadFieldNumber
|
||||||
|
|
||||||
|
# setup logging
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
print('')
|
||||||
|
print('This test uses the following topology -')
|
||||||
|
print('')
|
||||||
|
print(' +-------+ ')
|
||||||
|
print(' | |Tx--->----+')
|
||||||
|
print(' | Drone | |')
|
||||||
|
print(' | |Rx---<----+')
|
||||||
|
print(' +-------+ ')
|
||||||
|
print('')
|
||||||
|
print('A loopback port is used as both the Tx and Rx ports')
|
||||||
|
print('')
|
||||||
|
|
||||||
|
@pytest.fixture(scope='module')
|
||||||
|
def drone(request):
|
||||||
|
"""Baseline Configuration for all testcases in this module"""
|
||||||
|
|
||||||
|
dut = DroneProxy(host_name)
|
||||||
|
|
||||||
|
log.info('connecting to drone(%s:%d)' % (dut.hostName(), dut.portNumber()))
|
||||||
|
dut.connect()
|
||||||
|
|
||||||
|
def fin():
|
||||||
|
dut.disconnect()
|
||||||
|
|
||||||
|
request.addfinalizer(fin)
|
||||||
|
|
||||||
|
return dut
|
||||||
|
|
||||||
|
@pytest.fixture(scope='module')
|
||||||
|
def ports(request, drone):
|
||||||
|
# retreive port id list
|
||||||
|
log.info('retreiving port list')
|
||||||
|
port_id_list = drone.getPortIdList()
|
||||||
|
|
||||||
|
# retreive port config list
|
||||||
|
log.info('retreiving port config for all ports')
|
||||||
|
port_config_list = drone.getPortConfig(port_id_list)
|
||||||
|
|
||||||
|
if len(port_config_list.port) == 0:
|
||||||
|
log.warning('drone has no ports!')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# iterate port list to find a loopback port to use as the tx/rx port id
|
||||||
|
print('Port List')
|
||||||
|
print('---------')
|
||||||
|
for port in port_config_list.port:
|
||||||
|
print('%d.%s (%s)' % (port.port_id.id, port.name, port.description))
|
||||||
|
# use a loopback port as default tx/rx port
|
||||||
|
if ('lo' in port.name or 'loopback' in port.description.lower()):
|
||||||
|
tx_number = port.port_id.id
|
||||||
|
rx_number = port.port_id.id
|
||||||
|
|
||||||
|
if tx_number < 0 or rx_number < 0:
|
||||||
|
log.warning('loopback port not found')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print('Using port %d as tx/rx port(s)' % tx_number)
|
||||||
|
|
||||||
|
ports.tx = ost_pb.PortIdList()
|
||||||
|
ports.tx.port_id.add().id = tx_number;
|
||||||
|
|
||||||
|
ports.rx = ost_pb.PortIdList()
|
||||||
|
ports.rx.port_id.add().id = rx_number;
|
||||||
|
|
||||||
|
# delete existing streams, if any, on tx port
|
||||||
|
sid_list = drone.getStreamIdList(ports.tx.port_id[0])
|
||||||
|
drone.deleteStream(sid_list)
|
||||||
|
|
||||||
|
return ports
|
||||||
|
|
||||||
|
protolist=['mac eth2 ip4 udp payload', 'mac eth2 ip4 udp']
|
||||||
|
@pytest.fixture(scope='module', params=protolist)
|
||||||
|
def stream(request, drone, ports):
|
||||||
|
global proto_number
|
||||||
|
|
||||||
|
# add a stream
|
||||||
|
stream_id = ost_pb.StreamIdList()
|
||||||
|
stream_id.port_id.CopyFrom(ports.tx.port_id[0])
|
||||||
|
stream_id.stream_id.add().id = 1
|
||||||
|
log.info('adding tx_stream %d' % stream_id.stream_id[0].id)
|
||||||
|
drone.addStream(stream_id)
|
||||||
|
|
||||||
|
# configure the stream
|
||||||
|
stream_cfg = ost_pb.StreamConfigList()
|
||||||
|
stream_cfg.port_id.CopyFrom(ports.tx.port_id[0])
|
||||||
|
s = stream_cfg.stream.add()
|
||||||
|
s.stream_id.id = stream_id.stream_id[0].id
|
||||||
|
s.core.is_enabled = True
|
||||||
|
s.control.packets_per_sec = 100
|
||||||
|
s.control.num_packets = 10
|
||||||
|
|
||||||
|
# setup stream protocols as mac:eth2:ip:udp:payload
|
||||||
|
s.ClearField("protocol")
|
||||||
|
protos = request.param.split()
|
||||||
|
for p in protos:
|
||||||
|
s.protocol.add().protocol_id.id = proto_number[p]
|
||||||
|
|
||||||
|
def fin():
|
||||||
|
# delete streams
|
||||||
|
log.info('deleting tx_stream %d' % stream_id.stream_id[0].id)
|
||||||
|
drone.deleteStream(stream_id)
|
||||||
|
|
||||||
|
request.addfinalizer(fin)
|
||||||
|
|
||||||
|
return stream_cfg
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("mode", [
|
||||||
|
ost_pb.StreamCore.e_fl_inc,
|
||||||
|
ost_pb.StreamCore.e_fl_dec,
|
||||||
|
ost_pb.StreamCore.e_fl_random
|
||||||
|
])
|
||||||
|
def test_packet_length(drone, ports, stream, mode):
|
||||||
|
""" Test random length packets """
|
||||||
|
|
||||||
|
min_pkt_len = 100
|
||||||
|
max_pkt_len = 1000
|
||||||
|
stream.stream[0].core.len_mode = mode
|
||||||
|
stream.stream[0].core.frame_len_min = min_pkt_len
|
||||||
|
stream.stream[0].core.frame_len_max = max_pkt_len
|
||||||
|
|
||||||
|
log.info('configuring tx_stream %d' % stream.stream[0].stream_id.id)
|
||||||
|
drone.modifyStream(stream)
|
||||||
|
|
||||||
|
# clear tx/rx stats
|
||||||
|
log.info('clearing tx/rx stats')
|
||||||
|
drone.clearStats(ports.tx)
|
||||||
|
drone.clearStats(ports.rx)
|
||||||
|
|
||||||
|
try:
|
||||||
|
drone.startCapture(ports.rx)
|
||||||
|
drone.startTransmit(ports.tx)
|
||||||
|
log.info('waiting for transmit to finish ...')
|
||||||
|
time.sleep(3)
|
||||||
|
drone.stopTransmit(ports.tx)
|
||||||
|
drone.stopCapture(ports.rx)
|
||||||
|
|
||||||
|
log.info('getting Rx capture buffer')
|
||||||
|
buff = drone.getCaptureBuffer(ports.rx.port_id[0])
|
||||||
|
drone.saveCaptureBuffer(buff, 'capture.pcap')
|
||||||
|
log.info('dumping Rx capture buffer')
|
||||||
|
cap_pkts = subprocess.check_output([tshark, '-n', '-r', 'capture.pcap',
|
||||||
|
'-R', 'udp'])
|
||||||
|
cap_pkts = subprocess.check_output([tshark, '-n', '-r', 'capture.pcap',
|
||||||
|
'-R', 'udp', '-o', fmt])
|
||||||
|
print(cap_pkts)
|
||||||
|
result = extract_column(cap_pkts, fmt_col)
|
||||||
|
diffSum = 0
|
||||||
|
for i in range(len(result)):
|
||||||
|
l = int(result[i]) + 4 # add FCS to length
|
||||||
|
assert (l >= min_pkt_len) and (l <= max_pkt_len)
|
||||||
|
|
||||||
|
# check current packet length to last
|
||||||
|
if (i > 0):
|
||||||
|
ll = int(result[i-1]) + 4
|
||||||
|
if mode == ost_pb.StreamCore.e_fl_inc:
|
||||||
|
assert l == (ll+1)
|
||||||
|
elif mode == ost_pb.StreamCore.e_fl_dec:
|
||||||
|
assert l == (ll-1)
|
||||||
|
elif mode == ost_pb.StreamCore.e_fl_random:
|
||||||
|
diffSum += (l-ll)
|
||||||
|
|
||||||
|
# TODO: find a better way to check for randomness
|
||||||
|
if mode == ost_pb.StreamCore.e_fl_random:
|
||||||
|
assert (diffSum % (len(result) - 1)) != 0
|
||||||
|
|
||||||
|
os.remove('capture.pcap')
|
||||||
|
except RpcError as e:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
drone.stopTransmit(ports.tx)
|
||||||
|
|
3
test/pytest.ini
Normal file
3
test/pytest.ini
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[pytest]
|
||||||
|
; change file glob pattern after converting old test files to pytest
|
||||||
|
python_files=pktlentest.py
|
Loading…
Reference in New Issue
Block a user