UserScript Protocol "first cut" checked-in. Needs rework.
This commit is contained in:
Srivats P. 2009-11-23 08:08:22 +00:00
parent c9563b50eb
commit ebc0403fde
9 changed files with 740 additions and 5 deletions

View File

@ -1,6 +1,6 @@
TEMPLATE = app
CONFIG += qt debug
QT += network
QT += network script
INCLUDEPATH += "../rpc/" "../common/"
LIBS += -lprotobuf
win32:LIBS += -L"../common/debug" -lostproto

View File

@ -1,6 +1,6 @@
TEMPLATE = lib
CONFIG += qt staticlib
QT += network
QT += network script
LIBS += \
-lprotobuf
FORMS += \
@ -14,6 +14,7 @@ FORMS += \
ip4.ui \
tcp.ui \
udp.ui \
userscript.ui \
sample.ui
PROTOS += \
protocol.proto \
@ -31,6 +32,7 @@ PROTOS += \
ip4.proto \
tcp.proto \
udp.proto \
userscript.proto \
sample.proto
HEADERS += \
abstractprotocol.h \
@ -53,6 +55,7 @@ HEADERS += \
ip4.h \
tcp.h \
udp.h \
userscript.h \
sample.h
SOURCES += \
abstractprotocol.cpp \
@ -71,6 +74,7 @@ SOURCES += \
ip4.cpp \
tcp.cpp \
udp.cpp \
userscript.cpp \
sample.cpp
protobuf_decl.name = protobuf header

View File

@ -71,6 +71,7 @@ message Protocol {
kMacFieldNumber = 51;
kPayloadFieldNumber = 52;
kSampleFieldNumber = 53;
kUserScriptFieldNumber = 54;
kEth2FieldNumber = 121;
kDot3FieldNumber = 122;

View File

@ -2,7 +2,6 @@
#include "abstractprotocol.h"
#include "protocol.pb.h"
#include "sample.h"
#include "mac.h"
#include "payload.h"
#include "eth2.h"
@ -16,6 +15,8 @@
#include "ip4.h"
#include "tcp.h"
#include "udp.h"
#include "userscript.h"
#include "sample.h"
ProtocolManager OstProtocolManager;
@ -53,6 +54,8 @@ ProtocolManager::ProtocolManager()
registerProtocol(OstProto::Protocol::kUdpFieldNumber,
(void*) UdpProtocol::createInstance);
registerProtocol(OstProto::Protocol::kUserScriptFieldNumber,
(void*) UserScriptProtocol::createInstance);
registerProtocol(OstProto::Protocol::kSampleFieldNumber,
(void*) SampleProtocol::createInstance);
@ -64,7 +67,7 @@ void ProtocolManager::registerProtocol(int protoNumber,
{
AbstractProtocol *p;
//! \todo (MED) validate incoming params for duplicates with existing
Q_ASSERT(!factory.contains(protoNumber));
factory.insert(protoNumber, protoInstanceCreator);

492
common/userscript.cpp Normal file
View File

@ -0,0 +1,492 @@
#include "userscript.h"
#include <qendian.h>
#include <QMessageBox>
#include <QMetaEnum>
#include <QMetaObject>
UserScriptConfigForm::UserScriptConfigForm(UserScriptProtocol *protocol,
QWidget *parent) : QWidget(parent), _protocol(protocol)
{
setupUi(this);
}
void UserScriptConfigForm::on_programEdit_textChanged()
{
}
void UserScriptConfigForm::on_compileButton_clicked(bool checked)
{
_protocol->storeConfigWidget();
if (_protocol->userScriptErrorLineNumber() >= 0)
{
statusLabel->setText("<font color=\"red\">Fail</font>");
QMessageBox::critical(this, "Error",
QString("Line %1: %2").arg(
_protocol->userScriptErrorLineNumber()).arg(
_protocol->userScriptErrorText()));
}
else
{
statusLabel->setText("<font color=\"green\">Success</font>");
}
}
UserScriptProtocol::UserScriptProtocol(StreamBase *stream, AbstractProtocol *parent)
: AbstractProtocol(stream, parent),
_userProtocol(this)
{
configForm = NULL;
_isUpdated = false;
_errorLineNumber = -1;
_userProtocolScriptValue = _scriptEngine.newQObject(&_userProtocol);
_userProtocolScriptValue.setProperty("protocolId", _scriptEngine.newObject());
_scriptEngine.globalObject().setProperty("protocol", _userProtocolScriptValue);
QScriptValue meta = _scriptEngine.newQMetaObject(_userProtocol.metaObject());
_scriptEngine.globalObject().setProperty("Protocol", meta);
}
UserScriptProtocol::~UserScriptProtocol()
{
delete configForm;
}
AbstractProtocol* UserScriptProtocol::createInstance(StreamBase *stream,
AbstractProtocol *parent)
{
return new UserScriptProtocol(stream, parent);
}
quint32 UserScriptProtocol::protocolNumber() const
{
return OstProto::Protocol::kUserScriptFieldNumber;
}
void UserScriptProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const
{
protocol.MutableExtension(OstProto::userScript)->CopyFrom(data);
protocol.mutable_protocol_id()->set_id(protocolNumber());
}
void UserScriptProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol)
{
if (protocol.protocol_id().id() == protocolNumber() &&
protocol.HasExtension(OstProto::userScript))
data.MergeFrom(protocol.GetExtension(OstProto::userScript));
evaluateUserScript();
}
QString UserScriptProtocol::name() const
{
return QString("%1:{UserScript}").arg(_userProtocol.name());
}
QString UserScriptProtocol::shortName() const
{
return QString("%1:{Script}").arg(_userProtocol.shortName());
}
quint32 UserScriptProtocol::protocolId(ProtocolIdType type) const
{
if (_userProtocol._protocolId.contains(static_cast<int>(type)))
return _userProtocol._protocolId.value(static_cast<int>(type));
else
return AbstractProtocol::protocolId(type);
}
int UserScriptProtocol::fieldCount() const
{
return userScript_fieldCount;
}
QVariant UserScriptProtocol::fieldData(int index, FieldAttrib attrib,
int streamIndex) const
{
switch (index)
{
case userScript_program:
{
switch(attrib)
{
case FieldName:
return QString("UserProtocol");
case FieldValue:
case FieldTextValue:
return QString().fromStdString(data.program());
case FieldFrameValue:
{
QScriptValue userFunction;
QByteArray fv;
evaluateUserScript(); // FIXME: don't call everytime!
if (_userProtocol.isProtocolFrameFixed())
{
fv = _userProtocol.protocolFrameFixedValue();
if (fv.size())
return fv;
else
return QByteArray(4, 0); // FIXME
}
userFunction = _userProtocolScriptValue.property(
"protocolFrameValue");
qDebug("userscript protoFrameVal(): isValid:%d/isFunc:%d",
userFunction.isValid(), userFunction.isFunction());
if (userFunction.isValid() && userFunction.isFunction())
{
QScriptValue userValue;
userValue = userFunction.call(QScriptValue(),
QScriptValueList()
<< QScriptValue(&_scriptEngine, streamIndex));
qDebug("userscript value: isValid:%d/isArray:%d",
userValue.isValid(), userValue.isArray());
if (userValue.isArray())
{
QList<int> pktBuf;
qScriptValueToSequence(userValue, pktBuf);
fv.resize(pktBuf.size());
for (int i = 0; i < pktBuf.size(); i++)
fv[i] = pktBuf.at(i) & 0xFF;
}
}
if (fv.size())
return fv;
else
return QByteArray(4, 0); // FIXME
}
//case FieldBitSize:
//return 3;
default:
break;
}
break;
}
default:
qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__,
index);
break;
}
return AbstractProtocol::fieldData(index, attrib, streamIndex);
}
bool UserScriptProtocol::setFieldData(int index, const QVariant &value,
FieldAttrib attrib)
{
bool isOk = false;
if (attrib != FieldValue)
goto _exit;
switch (index)
{
case userScript_program:
{
data.set_program(value.toString().toStdString());
break;
}
default:
qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__,
index);
break;
}
_exit:
return isOk;
}
bool UserScriptProtocol::isProtocolFrameValueVariable() const
{
return _userProtocol.isProtocolFrameValueVariable();
}
bool UserScriptProtocol::isProtocolFrameSizeVariable() const
{
return _userProtocol.isProtocolFrameSizeVariable();
}
QWidget* UserScriptProtocol::configWidget()
{
if (configForm == NULL)
{
configForm = new UserScriptConfigForm(this);
loadConfigWidget();
}
return configForm;
}
void UserScriptProtocol::loadConfigWidget()
{
configWidget();
configForm->programEdit->setPlainText(
fieldData(userScript_program, FieldValue).toString());
}
void UserScriptProtocol::storeConfigWidget()
{
configWidget();
setFieldData(userScript_program, configForm->programEdit->toPlainText());
evaluateUserScript();
}
bool UserScriptProtocol::evaluateUserScript() const
{
QScriptValue userFunction;
QScriptValue userValue;
_errorLineNumber = -1;
_userProtocol.reset();
_userProtocolScriptValue.setProperty("protocolFrameValue", QScriptValue());
_scriptEngine.evaluate(
fieldData(userScript_program, FieldValue).toString());
if (_scriptEngine.hasUncaughtException())
goto _error_exception;
userFunction = _userProtocolScriptValue.property(
"protocolFrameValue");
qDebug("userscript eval protoFrameVal(): isValid:%d/isFunc:%d",
userFunction.isValid(), userFunction.isFunction());
if (!userFunction.isValid())
goto _error_frame_value_not_set;
if (userFunction.isArray())
{
QList<int> pktBuf;
userValue = userFunction;
_userProtocol.setProtocolFrameValueVariable(false);
qScriptValueToSequence(userValue, pktBuf);
_userProtocol.setProtocolFrameFixedValue(pktBuf);
}
else if (userFunction.isFunction())
{
userValue = userFunction.call();
if (_scriptEngine.hasUncaughtException())
goto _error_exception;
qDebug("userscript eval value: isValid:%d/isArray:%d",
userValue.isValid(), userValue.isArray());
if (!userValue.isArray())
goto _error_not_an_array;
if (_userProtocol.isProtocolFrameFixed())
{
QList<int> pktBuf;
qScriptValueToSequence(userValue, pktBuf);
_userProtocol.setProtocolFrameFixedValue(pktBuf);
}
}
else
goto _error_frame_value_type;
userValue = _userProtocolScriptValue.property("protocolId");
if (userValue.isValid() && userValue.isObject())
{
QMetaEnum meta;
QScriptValue userProtocolId;
meta = _userProtocol.metaObject()->enumerator(
_userProtocol.metaObject()->indexOfEnumerator("ProtocolIdType"));
for (int i = 0; i < meta.keyCount(); i++)
{
userProtocolId = userValue.property(meta.key(i));
qDebug("userscript protoId: isValid:%d/isNumber:%d",
userProtocolId.isValid(),
userProtocolId.isNumber());
if (userProtocolId.isValid() && userProtocolId.isNumber())
_userProtocol._protocolId.insert(
meta.value(i), userProtocolId.toUInt32());
}
}
_isUpdated = true;
return true;
_error_not_an_array:
_errorLineNumber = userScriptLineCount();
_errorText = QString("property 'protocolFrameValue' returns invalid array");
goto _error;
_error_frame_value_type:
_errorLineNumber = userScriptLineCount();
_errorText = QString("property 'protocolFrameValue' is neither an array nor a function");
goto _error;
_error_frame_value_not_set:
_errorLineNumber = userScriptLineCount();
_errorText = QString("mandatory property 'protocolFrameValue' is not set");
goto _error;
_error_exception:
_errorLineNumber = _scriptEngine.uncaughtExceptionLineNumber();
_errorText = _scriptEngine.uncaughtException().toString();
goto _error;
_error:
_userProtocol.reset();
return false;
}
int UserScriptProtocol::userScriptErrorLineNumber() const
{
return _errorLineNumber;
}
QString UserScriptProtocol::userScriptErrorText() const
{
return _errorText;
}
int UserScriptProtocol::userScriptLineCount() const
{
return fieldData(userScript_program, FieldValue).toString().count(
QChar('\n')) + 1;
}
//
// ---------------------------------------------------------------
//
UserProtocol::UserProtocol(AbstractProtocol *parent)
: _parent (parent)
{
reset();
}
bool UserProtocol::isProtocolFrameFixed() const
{
return !isProtocolFrameValueVariable() && !isProtocolFrameSizeVariable();
}
const QByteArray& UserProtocol::protocolFrameFixedValue() const
{
return _protocolFrameFixedValue;
}
void UserProtocol::setProtocolFrameFixedValue(const QByteArray& value)
{
_protocolFrameFixedValue = value;
}
void UserProtocol::setProtocolFrameFixedValue(const QList<int>& value)
{
_protocolFrameFixedValue.resize(value.size());
for (int i = 0; i < value.size(); i++)
_protocolFrameFixedValue[i] = value.at(i) & 0xFF;
}
void UserProtocol::reset()
{
_name = QString();
_shortName = QString();
_protocolId.clear();
_protocolFrameValueVariable = false;
_protocolFrameSizeVariable = false;
_protocolFrameFixedValue.resize(0);
}
QString UserProtocol::name() const
{
return _name;
}
void UserProtocol::setName(QString &name)
{
_name = name;
}
QString UserProtocol::shortName() const
{
return _shortName;
}
void UserProtocol::setShortName(QString &shortName)
{
_shortName = shortName;
}
bool UserProtocol::isProtocolFrameValueVariable() const
{
return _protocolFrameValueVariable;
}
void UserProtocol::setProtocolFrameValueVariable(bool variable)
{
qDebug("%s: %d", __FUNCTION__, variable);
_protocolFrameValueVariable = variable;
}
bool UserProtocol::isProtocolFrameSizeVariable() const
{
return _protocolFrameSizeVariable;
}
void UserProtocol::setProtocolFrameSizeVariable(bool variable)
{
_protocolFrameSizeVariable = variable;
}
quint32 UserProtocol::payloadProtocolId(UserProtocol::ProtocolIdType type) const
{
return _parent->payloadProtocolId(
static_cast<AbstractProtocol::ProtocolIdType>(type));
}
int UserProtocol::protocolFrameOffset(int streamIndex) const
{
return _parent->protocolFrameOffset(streamIndex);
}
int UserProtocol::protocolFramePayloadSize(int streamIndex) const
{
return _parent->protocolFramePayloadSize(streamIndex);
}
bool UserProtocol::isProtocolFramePayloadValueVariable() const
{
return _parent->isProtocolFramePayloadValueVariable();
}
bool UserProtocol::isProtocolFramePayloadSizeVariable() const
{
return _parent->isProtocolFramePayloadSizeVariable();
}
quint32 UserProtocol::protocolFrameHeaderCksum(int streamIndex,
AbstractProtocol::CksumType cksumType) const
{
return _parent->protocolFrameHeaderCksum(streamIndex, cksumType);
}
quint32 UserProtocol::protocolFramePayloadCksum(int streamIndex,
AbstractProtocol::CksumType cksumType) const
{
return _parent->protocolFramePayloadCksum(streamIndex, cksumType);
}
/* vim: set shiftwidth=4 tabstop=8 softtabstop=4 expandtab: */

160
common/userscript.h Normal file
View File

@ -0,0 +1,160 @@
#ifndef _USER_SCRIPT_H
#define _USER_SCRIPT_H
#include "abstractprotocol.h"
#include "userscript.pb.h"
#include "ui_userscript.h"
#include <QScriptEngine>
#include <QScriptValue>
class UserScriptProtocol;
class UserProtocol : public QObject
{
friend class UserScriptProtocol;
Q_OBJECT;
Q_ENUMS(ProtocolIdType);
Q_PROPERTY(QString name READ name WRITE setName);
Q_PROPERTY(QString shortName READ shortName WRITE setShortName);
Q_PROPERTY(bool protocolFrameValueVariable
READ isProtocolFrameValueVariable
WRITE setProtocolFrameValueVariable);
Q_PROPERTY(bool protocolFrameSizeVariable
READ isProtocolFrameSizeVariable
WRITE setProtocolFrameSizeVariable);
public:
enum ProtocolIdType
{
ProtocolIdLlc = AbstractProtocol::ProtocolIdLlc,
ProtocolIdEth = AbstractProtocol::ProtocolIdEth,
ProtocolIdIp = AbstractProtocol::ProtocolIdIp
};
UserProtocol(AbstractProtocol *parent);
bool isProtocolFrameFixed() const;
const QByteArray& protocolFrameFixedValue() const;
void setProtocolFrameFixedValue(const QByteArray& value);
void setProtocolFrameFixedValue(const QList<int>& value);
public slots:
void reset();
QString name() const;
void setName(QString &name);
QString shortName() const;
void setShortName(QString &shortName);
bool isProtocolFrameValueVariable() const;
void setProtocolFrameValueVariable(bool variable);
bool isProtocolFrameSizeVariable() const;
void setProtocolFrameSizeVariable(bool variable);
quint32 payloadProtocolId(UserProtocol::ProtocolIdType type) const;
int protocolFrameOffset(int streamIndex = 0) const;
int protocolFramePayloadSize(int streamIndex = 0) const;
bool isProtocolFramePayloadValueVariable() const;
bool isProtocolFramePayloadSizeVariable() const;
quint32 protocolFrameHeaderCksum(int streamIndex = 0,
AbstractProtocol::CksumType cksumType = AbstractProtocol::CksumIp) const;
quint32 protocolFramePayloadCksum(int streamIndex = 0,
AbstractProtocol::CksumType cksumType = AbstractProtocol::CksumIp) const;
private:
AbstractProtocol *_parent;
QString _name;
QString _shortName;
QMap<int, quint32> _protocolId;
bool _protocolFrameValueVariable;
bool _protocolFrameSizeVariable;
QByteArray _protocolFrameFixedValue;
};
class UserScriptConfigForm : public QWidget, public Ui::UserScript
{
Q_OBJECT
public:
UserScriptConfigForm(UserScriptProtocol *protocol, QWidget *parent = 0);
private:
UserScriptProtocol *_protocol;
private slots:
void on_programEdit_textChanged();
void on_compileButton_clicked(bool checked = false);
};
class UserScriptProtocol : public AbstractProtocol
{
friend class UserScriptConfigForm;
public:
UserScriptProtocol(StreamBase *stream, AbstractProtocol *parent = 0);
virtual ~UserScriptProtocol();
static AbstractProtocol* createInstance(StreamBase *stream,
AbstractProtocol *parent = 0);
virtual quint32 protocolNumber() const;
virtual void protoDataCopyInto(OstProto::Protocol &protocol) const;
virtual void protoDataCopyFrom(const OstProto::Protocol &protocol);
virtual quint32 protocolId(ProtocolIdType type) const;
virtual QString name() const;
virtual QString shortName() const;
virtual int fieldCount() const;
virtual QVariant fieldData(int index, FieldAttrib attrib,
int streamIndex = 0) const;
virtual bool setFieldData(int index, const QVariant &value,
FieldAttrib attrib = FieldValue);
virtual bool isProtocolFrameValueVariable() const;
virtual bool isProtocolFrameSizeVariable() const;
virtual QWidget* configWidget();
virtual void loadConfigWidget();
virtual void storeConfigWidget();
private:
bool evaluateUserScript() const;
int userScriptErrorLineNumber() const;
QString userScriptErrorText() const;
int userScriptLineCount() const;
OstProto::UserScript data;
UserScriptConfigForm *configForm;
enum userScriptfield
{
// Frame Fields
userScript_program = 0,
userScript_fieldCount
};
mutable QScriptEngine _scriptEngine;
mutable UserProtocol _userProtocol;
mutable QScriptValue _userProtocolScriptValue;
mutable bool _isUpdated;
mutable int _errorLineNumber;
mutable QString _errorText;
};
#endif
/* vim: set shiftwidth=4 tabstop=8 softtabstop=4 expandtab: */

14
common/userscript.proto Normal file
View File

@ -0,0 +1,14 @@
import "protocol.proto";
package OstProto;
// Sample Protocol
message UserScript {
optional string program = 1;
}
extend Protocol {
optional UserScript userScript = 54;
}

61
common/userscript.ui Normal file
View File

@ -0,0 +1,61 @@
<ui version="4.0" >
<class>UserScript</class>
<widget class="QWidget" name="UserScript" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>517</width>
<height>335</height>
</rect>
</property>
<property name="windowTitle" >
<string>Form</string>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="QTextEdit" name="programEdit" />
</item>
<item>
<layout class="QHBoxLayout" >
<item>
<widget class="QLabel" name="label" >
<property name="text" >
<string>Compilation Status:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="statusLabel" >
<property name="text" >
<string>Unknown</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="compileButton" >
<property name="text" >
<string>Compile</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,6 +1,6 @@
TEMPLATE = app
CONFIG += qt debug
QT += network
QT += network script
DEFINES += HAVE_REMOTE WPCAP
INCLUDEPATH += "../rpc"
LIBS += -lprotobuf