diff --git a/.hgignore b/.hgignore
index cd5490f..c268bf1 100644
--- a/.hgignore
+++ b/.hgignore
@@ -31,3 +31,5 @@ version.cpp
# ctags
tags
+
+pcaps\*
diff --git a/client/port.cpp b/client/port.cpp
index c1e402c..e3c873b 100644
--- a/client/port.cpp
+++ b/client/port.cpp
@@ -20,7 +20,7 @@ along with this program. If not, see
#include "port.h"
#include "fileformat.h"
-#include "pdmlfileformat.h"
+#include "pcapfileformat.h"
#include
#include
@@ -229,7 +229,7 @@ bool Port::openStreams(QString fileName, bool append, QString &error)
OstProto::StreamConfigList streams;
//if (!fileFormat.openStreams(fileName, streams, error))
- if (!pdmlFileFormat.openStreams(fileName, streams, error))
+ if (!pcapFileFormat.openStreams(fileName, streams, error))
goto _fail;
if (!append)
@@ -262,5 +262,6 @@ bool Port::saveStreams(QString fileName, QString &error)
mStreams[i]->protoDataCopyInto(*s);
}
- return fileFormat.saveStreams(streams, fileName, error);
+ //return fileFormat.saveStreams(streams, fileName, error);
+ return pcapFileFormat.saveStreams(streams, fileName, error);
}
diff --git a/common/ostproto.pro b/common/ostproto.pro
index 26aefae..ef829da 100644
--- a/common/ostproto.pro
+++ b/common/ostproto.pro
@@ -58,6 +58,7 @@ HEADERS += \
abstractprotocol.h \
comboprotocol.h \
fileformat.h \
+ pcapfileformat.h \
pdmlfileformat.h \
pdml_p.h \
protocolmanager.h \
@@ -98,6 +99,7 @@ SOURCES += \
abstractprotocol.cpp \
crc32c.cpp \
fileformat.cpp \
+ pcapfileformat.cpp \
pdmlfileformat.cpp \
pdml_p.cpp \
protocolmanager.cpp \
diff --git a/common/pcapfileformat.cpp b/common/pcapfileformat.cpp
new file mode 100644
index 0000000..3ef8c76
--- /dev/null
+++ b/common/pcapfileformat.cpp
@@ -0,0 +1,252 @@
+/*
+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
+*/
+
+#include "pcapfileformat.h"
+#include "streambase.h"
+#include "hexdump.pb.h"
+
+#include
+#include
+#include
+
+static inline quint32 swap32(quint32 val)
+{
+ return (((val >> 24) && 0x000000FF) |
+ ((val >> 16) && 0x0000FF00) |
+ ((val << 16) && 0x00FF0000) |
+ ((val << 24) && 0xFF000000));
+}
+
+static inline quint16 swap16(quint16 val)
+{
+ return (((val >> 8) && 0x00FF) |
+ ((val << 8) && 0xFF00));
+}
+
+typedef struct {
+ quint32 magicNumber; /* magic number */
+ quint16 versionMajor; /* major version number */
+ quint16 versionMinor; /* minor version number */
+ qint32 thisZone; /* GMT to local correction */
+ quint32 sigfigs; /* accuracy of timestamps */
+ quint32 snapLen; /* max length of captured packets, in octets */
+ quint32 network; /* data link type */
+} PcapFileHeader;
+
+const quint32 kPcapFileMagic = 0xa1b2c3d4;
+const quint32 kPcapFileMagicSwapped = 0xd4c3b2a1;
+const quint16 kPcapFileVersionMajor = 2;
+const quint16 kPcapFileVersionMinor = 4;
+const quint32 kMaxSnapLen = 65535;
+
+typedef struct {
+ quint32 tsSec; /* timestamp seconds */
+ quint32 tsUsec; /* timestamp microseconds */
+ quint32 inclLen; /* number of octets of packet saved in file */
+ quint32 origLen; /* actual length of packet */
+} PcapPacketHeader;
+
+PcapFileFormat pcapFileFormat;
+
+PcapFileFormat::PcapFileFormat()
+{
+}
+
+PcapFileFormat::~PcapFileFormat()
+{
+}
+
+bool PcapFileFormat::openStreams(const QString fileName,
+ OstProto::StreamConfigList &streams, QString &error)
+{
+ bool isOk = false;
+ QFile file(fileName);
+ QDataStream fd;
+ quint32 magic;
+ PcapFileHeader fileHdr;
+ PcapPacketHeader pktHdr;
+ quint32 len;
+ int pktCount = 1;
+ QByteArray pktBuf;
+
+ if (!file.open(QIODevice::ReadOnly))
+ goto _err_open;
+
+ if (file.size() < sizeof(fileHdr))
+ goto _err_truncated;
+
+ fd.setDevice(&file);
+
+ fd >> magic;
+
+
+ if (magic == kPcapFileMagicSwapped)
+ {
+ // Toggle Byte order
+ if (fd.byteOrder() == QDataStream::BigEndian)
+ fd.setByteOrder(QDataStream::LittleEndian);
+ else
+ fd.setByteOrder(QDataStream::BigEndian);
+ }
+ else if (magic != kPcapFileMagic)
+ goto _err_bad_magic;
+
+ fd >> fileHdr.versionMajor;
+ fd >> fileHdr.versionMinor;
+ fd >> fileHdr.thisZone;
+ fd >> fileHdr.sigfigs;
+ fd >> fileHdr.snapLen;
+ fd >> fileHdr.network;
+
+ if ((fileHdr.versionMajor != kPcapFileVersionMajor) ||
+ (fileHdr.versionMinor != kPcapFileVersionMinor))
+ goto _err_unsupported_version;
+
+ // TODO: what do we do about non-ethernet networks?
+
+ pktBuf.resize(fileHdr.snapLen);
+
+ while (!fd.atEnd())
+ {
+ OstProto::Stream *stream = streams.add_stream();
+ OstProto::Protocol *proto = stream->add_protocol();
+ OstProto::HexDump *hexDump = proto->MutableExtension(OstProto::hexDump);
+
+ stream->mutable_stream_id()->set_id(pktCount);
+ stream->mutable_core()->set_is_enabled(true);
+ proto->mutable_protocol_id()->set_id(
+ OstProto::Protocol::kHexDumpFieldNumber);
+
+ // read PcapPacketHeader
+ fd >> pktHdr.tsSec;
+ fd >> pktHdr.tsUsec;
+ fd >> pktHdr.inclLen;
+ fd >> pktHdr.origLen;
+
+ // TODO: chk fd.status()
+
+ // validations on inclLen <= origLen && inclLen <= snapLen
+ Q_ASSERT(pktHdr.inclLen <= fileHdr.snapLen); // TODO: convert to if
+
+ // read Pkt contents
+ len = fd.readRawData(pktBuf.data(), pktHdr.inclLen); // TODO: use while?
+ Q_ASSERT(len == pktHdr.inclLen); // TODO: remove assert
+
+ hexDump->set_content(pktBuf.data(), pktHdr.inclLen);
+ hexDump->set_pad_until_end(false);
+
+ stream->mutable_core()->set_frame_len(pktHdr.inclLen+4); // FCS
+
+ pktCount++;
+ }
+
+ isOk = true;
+ goto _exit;
+
+_err_unsupported_version:
+ error = QString(tr("%1 is in PCAP version %2.%3 format which is "
+ "not supported - Sorry!"))
+ .arg(fileName).arg(fileHdr.versionMajor).arg(fileHdr.versionMinor);
+ goto _exit;
+
+_err_bad_magic:
+ error = QString(tr("%1 is not a valid PCAP file")).arg(fileName);
+ goto _exit;
+
+_err_truncated:
+ error = QString(tr("%1 is too short")).arg(fileName);
+ goto _exit;
+
+_err_open:
+ error = QString(tr("Unable to open file: %1")).arg(fileName);
+ goto _exit;
+
+_exit:
+ return isOk;
+}
+
+bool PcapFileFormat::saveStreams(const OstProto::StreamConfigList streams,
+ const QString fileName, QString &error)
+{
+ bool isOk = false;
+ QFile file(fileName);
+ QDataStream fd;
+ PcapFileHeader fileHdr;
+ PcapPacketHeader pktHdr;
+ QByteArray pktBuf;
+
+ if (!file.open(QIODevice::WriteOnly))
+ goto _err_open;
+
+ fd.setDevice(&file);
+
+ fileHdr.magicNumber = kPcapFileMagic;
+ fileHdr.versionMajor = kPcapFileVersionMajor;
+ fileHdr.versionMinor = kPcapFileVersionMinor;
+ fileHdr.thisZone = 0;
+ fileHdr.sigfigs = 0;
+ fileHdr.snapLen = kMaxSnapLen;
+ fileHdr.network = 1; // Ethernet; FIXME: Hardcoding
+
+ fd << fileHdr.magicNumber;
+ fd << fileHdr.versionMajor;
+ fd << fileHdr.versionMinor;
+ fd << fileHdr.thisZone;
+ fd << fileHdr.sigfigs;
+ fd << fileHdr.snapLen;
+ fd << fileHdr.network;
+
+ pktBuf.resize(kMaxSnapLen);
+
+ for (int i = 0; i < streams.stream_size(); i++)
+ {
+ StreamBase s;
+
+ s.setId(i);
+ s.protoDataCopyFrom(streams.stream(i));
+ // TODO: expand frameIndex for each stream
+ s.frameValue((uchar*)pktBuf.data(), pktBuf.size(), 0);
+
+ // TODO: write actual timing!?!?
+ pktHdr.tsSec = 0;
+ pktHdr.tsUsec = 0;
+ pktHdr.inclLen = pktHdr.origLen = s.frameLen() - 4; // FCS; FIXME: Hardcoding
+ if (pktHdr.inclLen > fileHdr.snapLen)
+ pktHdr.inclLen = fileHdr.snapLen;
+
+ fd << pktHdr.tsSec;
+ fd << pktHdr.tsUsec;
+ fd << pktHdr.inclLen;
+ fd << pktHdr.origLen;
+ fd.writeRawData(pktBuf.data(), pktHdr.inclLen);
+ }
+
+ file.close();
+
+ isOk = true;
+ goto _exit;
+
+_err_open:
+ error = QString(tr("Unable to open file: %1")).arg(fileName);
+ goto _exit;
+
+_exit:
+ return isOk;
+}
+
diff --git a/common/pcapfileformat.h b/common/pcapfileformat.h
new file mode 100644
index 0000000..a515e32
--- /dev/null
+++ b/common/pcapfileformat.h
@@ -0,0 +1,42 @@
+/*
+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
+*/
+#ifndef _PCAP_FILE_FORMAT_H
+#define _PCAP_FILE_FORMAT_H
+
+#include "protocol.pb.h"
+
+#include
+
+class PcapFileFormat : public QObject
+{
+ Q_OBJECT
+
+public:
+ PcapFileFormat();
+ ~PcapFileFormat();
+
+ bool openStreams(const QString fileName,
+ OstProto::StreamConfigList &streams, QString &error);
+ bool saveStreams(const OstProto::StreamConfigList streams,
+ const QString fileName, QString &error);
+};
+
+extern PcapFileFormat pcapFileFormat;
+
+#endif
diff --git a/common/pdml_p.cpp b/common/pdml_p.cpp
index e887f33..fbc4a0e 100644
--- a/common/pdml_p.cpp
+++ b/common/pdml_p.cpp
@@ -43,6 +43,11 @@ PdmlDefaultProtocol::~PdmlDefaultProtocol()
{
}
+PdmlDefaultProtocol* PdmlDefaultProtocol::createInstance()
+{
+ return new PdmlDefaultProtocol();
+}
+
QString PdmlDefaultProtocol::pdmlProtoName() const
{
return pdmlProtoName_;
@@ -64,7 +69,12 @@ int PdmlDefaultProtocol::fieldId(QString name) const
}
void PdmlDefaultProtocol::preProtocolHandler(QString name,
- const QXmlAttributes &attributes, OstProto::Stream *stream)
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream)
+{
+ return; // do nothing!
+}
+
+void PdmlDefaultProtocol::prematureEndHandler(int pos, OstProto::Stream *stream)
{
return; // do nothing!
}
@@ -75,13 +85,14 @@ void PdmlDefaultProtocol::postProtocolHandler(OstProto::Stream *stream)
}
void PdmlDefaultProtocol::unknownFieldHandler(QString name,
- int pos, int size, const QXmlAttributes &attributes,
+ int pos, int size, const QXmlStreamAttributes &attributes,
OstProto::Stream *stream)
{
return; // do nothing!
}
+#if 0
// ---------------------------------------------------------- //
// PdmlParser
// ---------------------------------------------------------- //
@@ -328,6 +339,392 @@ bool PdmlParser::fatalError(const QXmlParseException &exception)
.arg(extra));
return false;
}
+#endif
+
+// ---------------------------------------------------------- //
+// PdmlReader //
+// ---------------------------------------------------------- //
+PdmlReader::PdmlReader(OstProto::StreamConfigList *streams)
+{
+ streams_ = streams;
+
+ factory_.insert("hexdump", PdmlUnknownProtocol::createInstance);
+ factory_.insert("geninfo", PdmlGenInfoProtocol::createInstance);
+ factory_.insert("frame", PdmlFrameProtocol::createInstance);
+#if 0
+ factory_.insert("fake-field-wrapper",
+ new PdmlFakeFieldWrapperProtocol());
+#endif
+ factory_.insert("eth",PdmlEthProtocol::createInstance);
+ factory_.insert("ip",PdmlIp4Protocol::createInstance);
+ factory_.insert("ipv6",PdmlIp6Protocol::createInstance);
+ factory_.insert("tcp",PdmlTcpProtocol::createInstance);
+}
+
+PdmlReader::~PdmlReader()
+{
+}
+
+bool PdmlReader::read(QIODevice *device)
+{
+ setDevice(device);
+ packetCount_ = 0;
+
+ while (!atEnd())
+ {
+ readNext();
+ if (isStartElement())
+ {
+ if (name() == "pdml")
+ readPdml();
+ else
+ raiseError("Not a pdml file!");
+ }
+ }
+
+ return !error();
+}
+
+// TODO: use a temp pool to avoid a lot of new/delete
+PdmlDefaultProtocol* PdmlReader::allocPdmlProtocol(QString protoName)
+{
+ if (!factory_.contains(protoName))
+ protoName = "hexdump";
+
+ return (*(factory_.value(protoName)))();
+}
+
+void PdmlReader::freePdmlProtocol(PdmlDefaultProtocol *proto)
+{
+ delete proto;
+}
+
+bool PdmlReader::isDontCareProto()
+{
+ Q_ASSERT(isStartElement() && name() == "proto");
+
+ QString protoName = attributes().value("name").toString();
+
+ if (protoName.isEmpty() || (protoName == "expert"))
+ return true;
+ else
+ return false;
+}
+
+void PdmlReader::readUnexpectedElement()
+{
+ Q_ASSERT(isStartElement());
+
+ // XXX: add to 'log'
+ qDebug("unexpected element - <%s>; skipping ...",
+ name().toString().toAscii().constData());
+ while (!atEnd())
+ {
+ readNext();
+ if (isEndElement())
+ break;
+
+ if (isStartElement())
+ readUnexpectedElement();
+ }
+}
+
+void PdmlReader::skipElement()
+{
+ Q_ASSERT(isStartElement());
+
+ // XXX: add to 'log'
+ qDebug("skipping element - <%s>",
+ name().toString().toAscii().constData());
+ while (!atEnd())
+ {
+ readNext();
+ if (isEndElement())
+ break;
+
+ if (isStartElement())
+ skipElement();
+ }
+}
+
+void PdmlReader::readPdml()
+{
+ Q_ASSERT(isStartElement() && name() == "pdml");
+
+ packetCount_ = 0;
+
+ while (!atEnd())
+ {
+ readNext();
+ if (isEndElement())
+ break;
+
+ if (isStartElement())
+ {
+ if (name() == "packet")
+ readPacket();
+ else
+ readUnexpectedElement();
+ }
+ }
+}
+
+void PdmlReader::readPacket()
+{
+ Q_ASSERT(isStartElement() && name() == "packet");
+
+ packetCount_++;
+ qDebug("packetNum = %d", packetCount_);
+
+ // XXX: For now, each packet is converted to a stream
+ currentStream_ = streams_->add_stream();
+ currentStream_->mutable_stream_id()->set_id(packetCount_);
+ currentStream_->mutable_core()->set_is_enabled(true);
+
+ while (!atEnd())
+ {
+ readNext();
+
+ if (isEndElement())
+ break;
+
+ if (isStartElement())
+ {
+ if (name() == "proto")
+ readProto();
+ else if (name() == "field")
+ readField(NULL, NULL); // TODO: top level field!!!!
+ else
+ readUnexpectedElement();
+ }
+ }
+
+ if (currentStream_->core().name().size())
+ {
+ OstProto::Protocol *proto = currentStream_->add_protocol();
+
+ proto->mutable_protocol_id()->set_id(
+ OstProto::Protocol::kHexDumpFieldNumber);
+
+ OstProto::HexDump *hexDump = proto->MutableExtension(OstProto::hexDump);
+
+ hexDump->set_content(currentStream_->core().name());
+ hexDump->set_pad_until_end(false);
+ currentStream_->mutable_core()->set_name("");
+ }
+}
+
+
+void PdmlReader::readProto()
+{
+ PdmlDefaultProtocol *pdmlProto = NULL;
+ google::protobuf::Message *pbProto = NULL;
+
+ Q_ASSERT(isStartElement() && name() == "proto");
+
+ QString protoName = attributes().value("name").toString();
+ qDebug("proto: %s", protoName.toAscii().constData());
+
+#if 0
+ if (protoName.isEmpty() || (protoName == "expert"))
+ {
+ skipElement();
+ return;
+ }
+#endif
+
+ pdmlProto = allocPdmlProtocol(protoName);
+ Q_ASSERT(pdmlProto != NULL);
+
+ int protoId = pdmlProto->ostProtoId();
+
+ // Non PdmlDefaultProtocol
+ if (protoId > 0)
+ {
+ OstProto::Protocol *proto = currentStream_->add_protocol();
+
+ proto->mutable_protocol_id()->set_id(protoId);
+
+ const google::protobuf::Reflection *msgRefl = proto->GetReflection();
+ const google::protobuf::FieldDescriptor *fieldDesc =
+ msgRefl->FindKnownExtensionByNumber(protoId);
+
+ // TODO: if !fDesc
+ // init default values of all fields in protocol
+ pbProto = msgRefl->MutableMessage(proto, fieldDesc);
+
+ }
+
+ pdmlProto->preProtocolHandler(protoName, attributes(), currentStream_);
+
+ while (!atEnd())
+ {
+ readNext();
+
+ if (isEndElement())
+ break;
+
+ if (isStartElement())
+ {
+ if (name() == "proto")
+ {
+ int endPos = -1;
+ // an embedded proto
+ qDebug("embedded proto: %s\n", attributes().value("name")
+ .toString().toAscii().constData());
+ if (isDontCareProto())
+ {
+ skipElement();
+ continue;
+ }
+
+ if (!attributes().value("pos").isEmpty())
+ endPos = attributes().value("pos").toString().toInt();
+
+
+ // pdmlProto may be NULL for a sequence of embedded protos
+ if (pdmlProto)
+ {
+ pdmlProto->prematureEndHandler(endPos, currentStream_);
+ pdmlProto->postProtocolHandler(currentStream_);
+ }
+ readProto();
+ pdmlProto = NULL;
+ pbProto = NULL;
+ }
+ else if (name() == "field")
+ {
+ if (pdmlProto == NULL)
+ {
+ pdmlProto = allocPdmlProtocol(protoName);
+ protoId = pdmlProto->ostProtoId();
+
+ // Non PdmlDefaultProtocol
+ if (protoId > 0)
+ {
+ OstProto::Protocol *proto = currentStream_->add_protocol();
+
+ proto->mutable_protocol_id()->set_id(protoId);
+
+ const google::protobuf::Reflection *msgRefl = proto->GetReflection();
+ const google::protobuf::FieldDescriptor *fieldDesc =
+ msgRefl->FindKnownExtensionByNumber(protoId);
+
+ // TODO: if !fDesc
+ // init default values of all fields in protocol
+ pbProto = msgRefl->MutableMessage(proto, fieldDesc);
+
+ }
+ pdmlProto->preProtocolHandler(protoName, attributes(), currentStream_);
+ }
+ readField(pdmlProto, pbProto);
+ }
+ else
+ readUnexpectedElement();
+ }
+ }
+
+ if (pdmlProto)
+ {
+ pdmlProto->postProtocolHandler(currentStream_);
+ freePdmlProtocol(pdmlProto);
+ }
+}
+
+void PdmlReader::readField(PdmlDefaultProtocol *pdmlProto,
+ google::protobuf::Message *pbProto)
+{
+ Q_ASSERT(isStartElement() && name() == "field");
+
+ // fields with "hide='yes'" are informational and should be skipped
+ if (attributes().value("hide") == "yes")
+ {
+ skipElement();
+ return;
+ }
+
+ QString fieldName = attributes().value("name").toString();
+ QString valueHexStr = attributes().value("value").toString();
+ int pos = -1;
+ int size = -1;
+
+ if (!attributes().value("pos").isEmpty())
+ pos = attributes().value("pos").toString().toInt();
+ if (!attributes().value("size").isEmpty())
+ size = attributes().value("size").toString().toInt();
+
+ qDebug("\tfieldName:%s, pos:%d, size:%d value:%s",
+ fieldName.toAscii().constData(),
+ pos,
+ size,
+ valueHexStr.toAscii().constData());
+
+ if (pdmlProto->hasField(fieldName))
+ {
+ int fieldId = pdmlProto->fieldId(fieldName);
+ const google::protobuf::Descriptor *msgDesc =
+ pbProto->GetDescriptor();
+ const google::protobuf::FieldDescriptor *fieldDesc =
+ msgDesc->FindFieldByNumber(fieldId);
+ const google::protobuf::Reflection *msgRefl =
+ pbProto->GetReflection();
+
+ bool isOk;
+
+ switch(fieldDesc->cpp_type())
+ {
+ case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: // TODO
+ case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
+ msgRefl->SetUInt32(pbProto, fieldDesc,
+ valueHexStr.toUInt(&isOk, kBaseHex));
+ break;
+ case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
+ msgRefl->SetUInt64(pbProto, fieldDesc,
+ valueHexStr.toULongLong(&isOk, kBaseHex));
+ break;
+ case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
+ {
+ QByteArray hexVal = QByteArray::fromHex(valueHexStr.toUtf8());
+ std::string str(hexVal.constData(), hexVal.size());
+ msgRefl->SetString(pbProto, fieldDesc, str);
+ break;
+ }
+ default:
+ qDebug("%s: unhandled cpptype = %d", __FUNCTION__,
+ fieldDesc->cpp_type());
+ }
+ }
+ else
+ {
+ pdmlProto->unknownFieldHandler(fieldName, pos, size, attributes(),
+ currentStream_);
+ }
+
+ while (!atEnd())
+ {
+ readNext();
+
+ if (isEndElement())
+ break;
+
+ if (isStartElement())
+ {
+ if (name() == "proto")
+ {
+ if (isDontCareProto())
+ {
+ skipElement();
+ continue;
+ }
+ readProto();
+ }
+ else if (name() == "field")
+ readField(pdmlProto, pbProto);
+ else
+ readUnexpectedElement();
+ }
+ }
+}
// ---------------------------------------------------------- //
@@ -336,22 +733,27 @@ bool PdmlParser::fatalError(const QXmlParseException &exception)
PdmlUnknownProtocol::PdmlUnknownProtocol()
{
- pdmlProtoName_ = "OST:HexDump";
+ pdmlProtoName_ = "";
ostProtoId_ = OstProto::Protocol::kHexDumpFieldNumber;
endPos_ = expPos_ = -1;
}
+PdmlDefaultProtocol* PdmlUnknownProtocol::createInstance()
+{
+ return new PdmlUnknownProtocol();
+}
+
void PdmlUnknownProtocol::preProtocolHandler(QString name,
- const QXmlAttributes &attributes, OstProto::Stream *stream)
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream)
{
bool isOk;
int size;
- int pos = attributes.value("pos").toUInt(&isOk);
+ int pos = attributes.value("pos").toString().toUInt(&isOk);
if (!isOk)
goto _skip_pos_size_proc;
- size = attributes.value("size").toUInt(&isOk);
+ size = attributes.value("size").toString().toUInt(&isOk);
if (!isOk)
goto _skip_pos_size_proc;
@@ -364,6 +766,11 @@ _skip_pos_size_proc:
hexDump->set_pad_until_end(false);
}
+void PdmlUnknownProtocol::prematureEndHandler(int pos, OstProto::Stream *stream)
+{
+ endPos_ = pos;
+}
+
void PdmlUnknownProtocol::postProtocolHandler(OstProto::Stream *stream)
{
OstProto::HexDump *hexDump = stream->mutable_protocol(
@@ -378,7 +785,7 @@ void PdmlUnknownProtocol::postProtocolHandler(OstProto::Stream *stream)
expPos_ += hexVal.size();
}
- qDebug("%s: expPos_ = %d, endPos_ = %d\n", __FUNCTION__, expPos_, endPos_);
+ qDebug(" hexdump: expPos_ = %d, endPos_ = %d\n", expPos_, endPos_);
//Q_ASSERT(expPos_ == endPos_);
hexDump->set_pad_until_end(false);
@@ -386,13 +793,13 @@ void PdmlUnknownProtocol::postProtocolHandler(OstProto::Stream *stream)
}
void PdmlUnknownProtocol::unknownFieldHandler(QString name, int pos, int size,
- const QXmlAttributes &attributes, OstProto::Stream *stream)
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream)
{
OstProto::HexDump *hexDump = stream->mutable_protocol(
stream->protocol_size()-1)->MutableExtension(OstProto::hexDump);
- qDebug("%s: %s, pos = %d, expPos_ = %d, endPos_ = %d\n",
- __PRETTY_FUNCTION__, name.toAscii().constData(),
+ qDebug(" hexdump: %s, pos = %d, expPos_ = %d, endPos_ = %d\n",
+ name.toAscii().constData(),
pos, expPos_, endPos_);
// Skipped field? Pad with zero!
@@ -407,8 +814,8 @@ void PdmlUnknownProtocol::unknownFieldHandler(QString name, int pos, int size,
if ((pos == expPos_) /*&& (pos < endPos_)*/)
{
QByteArray hexVal = attributes.value("unmaskedvalue").isEmpty() ?
- QByteArray::fromHex(attributes.value("value").toUtf8()) :
- QByteArray::fromHex(attributes.value("unmaskedvalue").toUtf8());
+ QByteArray::fromHex(attributes.value("value").toString().toUtf8()) :
+ QByteArray::fromHex(attributes.value("unmaskedvalue").toString().toUtf8());
hexDump->mutable_content()->append(hexVal.constData(), hexVal.size());
expPos_ += hexVal.size();
@@ -425,8 +832,13 @@ PdmlGenInfoProtocol::PdmlGenInfoProtocol()
pdmlProtoName_ = "geninfo";
}
+PdmlDefaultProtocol* PdmlGenInfoProtocol::createInstance()
+{
+ return new PdmlGenInfoProtocol();
+}
+
void PdmlGenInfoProtocol::unknownFieldHandler(QString name, int pos,
- int size, const QXmlAttributes &attributes, OstProto::Stream *stream)
+ int size, const QXmlStreamAttributes &attributes, OstProto::Stream *stream)
{
stream->mutable_core()->set_frame_len(size+4); // TODO:check FCS
}
@@ -440,6 +852,11 @@ PdmlFrameProtocol::PdmlFrameProtocol()
pdmlProtoName_ = "frame";
}
+PdmlDefaultProtocol* PdmlFrameProtocol::createInstance()
+{
+ return new PdmlFrameProtocol();
+}
+
#if 1
// ---------------------------------------------------------- //
// PdmlFakeFieldWrapperProtocol //
@@ -453,8 +870,13 @@ PdmlFakeFieldWrapperProtocol::PdmlFakeFieldWrapperProtocol()
expPos_ = -1;
}
+PdmlDefaultProtocol* PdmlFakeFieldWrapperProtocol::createInstance()
+{
+ return new PdmlFakeFieldWrapperProtocol();
+}
+
void PdmlFakeFieldWrapperProtocol::preProtocolHandler(QString name,
- const QXmlAttributes &attributes, OstProto::Stream *stream)
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream)
{
expPos_ = 0;
OstProto::HexDump *hexDump = stream->mutable_protocol(
@@ -474,7 +896,7 @@ void PdmlFakeFieldWrapperProtocol::postProtocolHandler(OstProto::Stream *stream)
}
void PdmlFakeFieldWrapperProtocol::unknownFieldHandler(QString name, int pos,
- int size, const QXmlAttributes &attributes, OstProto::Stream *stream)
+ int size, const QXmlStreamAttributes &attributes, OstProto::Stream *stream)
{
OstProto::HexDump *hexDump = stream->mutable_protocol(
stream->protocol_size()-1)->MutableExtension(OstProto::hexDump);
@@ -484,8 +906,8 @@ void PdmlFakeFieldWrapperProtocol::unknownFieldHandler(QString name, int pos,
!attributes.value("value").isEmpty()))
{
QByteArray hexVal = attributes.value("unmaskedvalue").isEmpty() ?
- QByteArray::fromHex(attributes.value("value").toUtf8()) :
- QByteArray::fromHex(attributes.value("unmaskedvalue").toUtf8());
+ QByteArray::fromHex(attributes.value("value").toString().toUtf8()) :
+ QByteArray::fromHex(attributes.value("unmaskedvalue").toString().toUtf8());
hexDump->mutable_content()->append(hexVal.constData(), hexVal.size());
expPos_ += hexVal.size();
@@ -506,8 +928,13 @@ PdmlEthProtocol::PdmlEthProtocol()
fieldMap_.insert("eth.src", OstProto::Mac::kSrcMacFieldNumber);
}
+PdmlDefaultProtocol* PdmlEthProtocol::createInstance()
+{
+ return new PdmlEthProtocol();
+}
+
void PdmlEthProtocol::unknownFieldHandler(QString name, int pos, int size,
- const QXmlAttributes &attributes, OstProto::Stream *stream)
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream)
{
if (name == "eth.type")
{
@@ -519,7 +946,7 @@ void PdmlEthProtocol::unknownFieldHandler(QString name, int pos, int size,
OstProto::Eth2 *eth2 = proto->MutableExtension(OstProto::eth2);
bool isOk;
- eth2->set_type(attributes.value("value").toUInt(&isOk, kBaseHex));
+ eth2->set_type(attributes.value("value").toString().toUInt(&isOk, kBaseHex));
eth2->set_is_override_type(true);
}
}
@@ -547,8 +974,13 @@ PdmlIp4Protocol::PdmlIp4Protocol()
fieldMap_.insert("ip.dst", 18);
}
+PdmlDefaultProtocol* PdmlIp4Protocol::createInstance()
+{
+ return new PdmlIp4Protocol();
+}
+
void PdmlIp4Protocol::unknownFieldHandler(QString name, int pos, int size,
- const QXmlAttributes &attributes, OstProto::Stream *stream)
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream)
{
bool isOk;
@@ -557,7 +989,7 @@ void PdmlIp4Protocol::unknownFieldHandler(QString name, int pos, int size,
OstProto::Ip4 *ip4 = stream->mutable_protocol(
stream->protocol_size()-1)->MutableExtension(OstProto::ip4);
- ip4->set_flags(attributes.value("value").toUInt(&isOk, kBaseHex) >> 5);
+ ip4->set_flags(attributes.value("value").toString().toUInt(&isOk, kBaseHex) >> 5);
}
}
@@ -592,8 +1024,13 @@ PdmlIp6Protocol::PdmlIp6Protocol()
// ipv6.src and ipv6.dst handled as unknown fields
}
+PdmlDefaultProtocol* PdmlIp6Protocol::createInstance()
+{
+ return new PdmlIp6Protocol();
+}
+
void PdmlIp6Protocol::unknownFieldHandler(QString name, int pos, int size,
- const QXmlAttributes &attributes, OstProto::Stream *stream)
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream)
{
bool isOk;
@@ -601,7 +1038,7 @@ void PdmlIp6Protocol::unknownFieldHandler(QString name, int pos, int size,
{
OstProto::Ip6 *ip6 = stream->mutable_protocol(
stream->protocol_size()-1)->MutableExtension(OstProto::ip6);
- QString addrHexStr = attributes.value("value");
+ QString addrHexStr = attributes.value("value").toString();
ip6->set_src_addr_hi(addrHexStr.left(16).toULongLong(&isOk, kBaseHex));
ip6->set_src_addr_lo(addrHexStr.right(16).toULongLong(&isOk, kBaseHex));
@@ -610,7 +1047,7 @@ void PdmlIp6Protocol::unknownFieldHandler(QString name, int pos, int size,
{
OstProto::Ip6 *ip6 = stream->mutable_protocol(
stream->protocol_size()-1)->MutableExtension(OstProto::ip6);
- QString addrHexStr = attributes.value("value");
+ QString addrHexStr = attributes.value("value").toString();
ip6->set_dst_addr_hi(addrHexStr.left(16).toULongLong(&isOk, kBaseHex));
ip6->set_dst_addr_lo(addrHexStr.right(16).toULongLong(&isOk, kBaseHex));
@@ -647,15 +1084,20 @@ PdmlTcpProtocol::PdmlTcpProtocol()
fieldMap_.insert("tcp.urgent_pointer", OstProto::Tcp::kUrgPtrFieldNumber);
}
+PdmlDefaultProtocol* PdmlTcpProtocol::createInstance()
+{
+ return new PdmlTcpProtocol();
+}
+
void PdmlTcpProtocol::unknownFieldHandler(QString name, int pos, int size,
- const QXmlAttributes &attributes, OstProto::Stream *stream)
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream)
{
if (name == "tcp.options")
- options_ = QByteArray::fromHex(attributes.value("value").toUtf8());
+ options_ = QByteArray::fromHex(attributes.value("value").toString().toUtf8());
else if (name == ""
- && attributes.value("show").startsWith("TCP segment data"))
+ && attributes.value("show").toString().startsWith("TCP segment data"))
{
- segmentData_ = QByteArray::fromHex(attributes.value("value").toUtf8());
+ segmentData_ = QByteArray::fromHex(attributes.value("value").toString().toUtf8());
stream->mutable_core()->mutable_name()->append(segmentData_.constData(),
segmentData_.size());
}
@@ -666,6 +1108,8 @@ void PdmlTcpProtocol::postProtocolHandler(OstProto::Stream *stream)
OstProto::Tcp *tcp = stream->mutable_protocol(
stream->protocol_size()-1)->MutableExtension(OstProto::tcp);
+ qDebug("Tcp: post\n");
+
tcp->set_is_override_src_port(true); // FIXME
tcp->set_is_override_dst_port(true); // FIXME
tcp->set_is_override_hdrlen(true); // FIXME
diff --git a/common/pdml_p.h b/common/pdml_p.h
index e125dd6..174442c 100644
--- a/common/pdml_p.h
+++ b/common/pdml_p.h
@@ -26,6 +26,7 @@ along with this program. If not, see
#include
#include
#include
+#include
// TODO: add const where possible
@@ -35,19 +36,22 @@ class QXmlInputSource;
class PdmlDefaultProtocol
{
public:
- PdmlDefaultProtocol();
+ PdmlDefaultProtocol(); // TODO: make private
virtual ~PdmlDefaultProtocol();
+ static PdmlDefaultProtocol* createInstance();
+
QString pdmlProtoName() const;
int ostProtoId() const;
bool hasField(QString name) const;
int fieldId(QString name) const;
virtual void preProtocolHandler(QString name,
- const QXmlAttributes &attributes, OstProto::Stream *stream);
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream);
+ virtual void prematureEndHandler(int pos, OstProto::Stream *stream);
virtual void postProtocolHandler(OstProto::Stream *stream);
virtual void unknownFieldHandler(QString name, int pos, int size,
- const QXmlAttributes &attributes, OstProto::Stream *stream);
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream);
protected:
QString pdmlProtoName_; // TODO: needed? duplicated in protocolMap_
@@ -55,6 +59,7 @@ protected:
QMap fieldMap_;
};
+#if 0
class PdmlParser : public QXmlDefaultHandler
{
public:
@@ -83,17 +88,53 @@ private:
OstProto::Stream *currentStream_;
google::protobuf::Message *currentProtocolMsg_;
};
+#endif
+
+class PdmlReader : public QXmlStreamReader
+{
+public:
+ PdmlReader(OstProto::StreamConfigList *streams);
+ ~PdmlReader();
+
+ bool read(QIODevice *device);
+
+private:
+ PdmlDefaultProtocol* allocPdmlProtocol(QString protoName);
+ void freePdmlProtocol(PdmlDefaultProtocol *proto);
+
+ bool isDontCareProto();
+ void readPdml();
+ void skipElement();
+ void readUnexpectedElement();
+ void readPacket();
+ void readProto();
+ void readField(PdmlDefaultProtocol *pdmlProto,
+ google::protobuf::Message *pbProto);
+
+ typedef PdmlDefaultProtocol* (*FactoryMethod)();
+ QMap factory_;
+
+ OstProto::StreamConfigList *streams_;
+
+ int packetCount_;
+ OstProto::Stream *currentStream_;
+ //PdmlDefaultProtocol *currentPdmlProtocol_;
+ //google::protobuf::Message *currentProtocolMsg_;
+};
class PdmlUnknownProtocol : public PdmlDefaultProtocol
{
public:
PdmlUnknownProtocol();
+ static PdmlDefaultProtocol* createInstance();
+
virtual void preProtocolHandler(QString name,
- const QXmlAttributes &attributes, OstProto::Stream *stream);
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream);
+ virtual void prematureEndHandler(int pos, OstProto::Stream *stream);
virtual void postProtocolHandler(OstProto::Stream *stream);
virtual void unknownFieldHandler(QString name, int pos, int size,
- const QXmlAttributes &attributes, OstProto::Stream *stream);
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream);
private:
int endPos_;
int expPos_;
@@ -104,14 +145,18 @@ class PdmlGenInfoProtocol : public PdmlDefaultProtocol
public:
PdmlGenInfoProtocol();
+ static PdmlDefaultProtocol* createInstance();
+
virtual void unknownFieldHandler(QString name, int pos, int size,
- const QXmlAttributes &attributes, OstProto::Stream *stream);
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream);
};
class PdmlFrameProtocol : public PdmlDefaultProtocol
{
public:
PdmlFrameProtocol();
+
+ static PdmlDefaultProtocol* createInstance();
};
#if 1
@@ -120,11 +165,13 @@ class PdmlFakeFieldWrapperProtocol : public PdmlDefaultProtocol
public:
PdmlFakeFieldWrapperProtocol();
+ static PdmlDefaultProtocol* createInstance();
+
virtual void preProtocolHandler(QString name,
- const QXmlAttributes &attributes, OstProto::Stream *stream);
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream);
virtual void postProtocolHandler(OstProto::Stream *stream);
virtual void unknownFieldHandler(QString name, int pos, int size,
- const QXmlAttributes &attributes, OstProto::Stream *stream);
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream);
private:
int expPos_;
};
@@ -135,16 +182,21 @@ class PdmlEthProtocol : public PdmlDefaultProtocol
public:
PdmlEthProtocol();
+ static PdmlDefaultProtocol* createInstance();
+
virtual void unknownFieldHandler(QString name, int pos, int size,
- const QXmlAttributes &attributes, OstProto::Stream *stream);
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream);
};
class PdmlIp4Protocol : public PdmlDefaultProtocol
{
public:
PdmlIp4Protocol();
+
+ static PdmlDefaultProtocol* createInstance();
+
virtual void unknownFieldHandler(QString name, int pos, int size,
- const QXmlAttributes &attributes, OstProto::Stream *stream);
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream);
virtual void postProtocolHandler(OstProto::Stream *stream);
};
@@ -152,8 +204,11 @@ class PdmlIp6Protocol : public PdmlDefaultProtocol
{
public:
PdmlIp6Protocol();
+
+ static PdmlDefaultProtocol* createInstance();
+
virtual void unknownFieldHandler(QString name, int pos, int size,
- const QXmlAttributes &attributes, OstProto::Stream *stream);
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream);
virtual void postProtocolHandler(OstProto::Stream *stream);
};
@@ -161,8 +216,11 @@ class PdmlTcpProtocol : public PdmlDefaultProtocol
{
public:
PdmlTcpProtocol();
+
+ static PdmlDefaultProtocol* createInstance();
+
virtual void unknownFieldHandler(QString name, int pos, int size,
- const QXmlAttributes &attributes, OstProto::Stream *stream);
+ const QXmlStreamAttributes &attributes, OstProto::Stream *stream);
virtual void postProtocolHandler(OstProto::Stream *stream);
private:
QByteArray options_;
diff --git a/common/pdmlfileformat.cpp b/common/pdmlfileformat.cpp
index 091924b..3f86084 100644
--- a/common/pdmlfileformat.cpp
+++ b/common/pdmlfileformat.cpp
@@ -30,6 +30,7 @@ PdmlFileFormat::~PdmlFileFormat()
{
}
+#if 0
bool PdmlFileFormat::openStreams(const QString fileName,
OstProto::StreamConfigList &streams, QString &error)
{
@@ -61,6 +62,32 @@ _exit:
return isOk;
}
+#else
+bool PdmlFileFormat::openStreams(const QString fileName,
+ OstProto::StreamConfigList &streams, QString &error)
+{
+ bool isOk = false;
+ QFile file(fileName);
+ PdmlReader *reader = new PdmlReader(&streams);
+
+ if (!file.open(QIODevice::ReadOnly))
+ goto _open_fail;
+
+ // TODO: fill in error string
+
+ isOk = reader->read(&file);
+
+ goto _exit;
+
+_open_fail:
+ isOk = false;
+
+_exit:
+ delete reader;
+
+ return isOk;
+}
+#endif
bool PdmlFileFormat::saveStreams(const OstProto::StreamConfigList streams,
const QString fileName, QString &error)