ostinato/common/abstractprotocol.cpp
Srivats P. 84c7fe1e06 Features
- Added support for retrieving the packet capture buffer from server to client (does not work consistently however - needs investigation)
		- getCaptureBuffer() Rpc signature changed
	- RPC: Added support in Rpc Channel (client) to queue calls
	- RPC: Added support for transferring arbitrary binary data from server to client (used to get packet capture files)
		- Rpc header changed - length is now 4 bytes instead of 2; there is no rsvd field any longer

Fixes
	- RPC: Fix for the case when a msg is not received all at once over the socket
	- StreamConfigDialog: fixed display issue in packet view for combo protocols containing meta fields
	- Fixed issue with Stacked Vlan not retaining data for both CVlan and SVlan
	- Fixed incorrect payload size issue with increment/decrement frame length modes

Refactoring, Cleanup etc.
	- RPC: Minor code and TODOs cleanup
	- Server: Minor code and TODOs cleanup
	- Server: Removed unused file(s): rxtx.cpp, rxtx.h
	- Server: Replaced direct use of ProtocolList with the ProtocolListIterator
	- Common: Minor code and TODOs cleanup
	- StreamBase::frameLen() now returns the length based on the mode/min/max and the passed in streamIndex
	- AbstractProtocol interface changed for methods - protocolFrameSize(), protocolFrameOffset(), protocolFramePayloadSize() : all of them now take streamIndex as an optional param with 0 as the default value
		- Protocols implementing the above methods changed accordingly
2009-11-03 14:02:09 +00:00

492 lines
12 KiB
C++

#include <qendian.h>
#include "abstractprotocol.h"
#include "streambase.h"
#include "protocollistiterator.h"
/*!
\class AbstractProtocol
\todo (MED) update AbstractProtocol documentation
Bare Minimum set of methods that a subclass needs to reimplement
- protoDataCopyInto() [pure virtual]
- protoDataCopyFrom() [pure virtual]
- fieldCount()
Any useful protocol should also provide implementations for
- name()
- shortName()
- fieldName()
Protocols with meta fields should additionally implement
- metaFieldCount()
- isMetaField()
*/
AbstractProtocol::AbstractProtocol(StreamBase *stream, AbstractProtocol *parent)
{
//qDebug("%s: &prev = %p &next = %p", __FUNCTION__, &prev, &next);
mpStream = stream;
this->parent = parent;
prev = next = NULL;
metaCount = -1;
protoSize = -1;
}
AbstractProtocol::~AbstractProtocol()
{
}
AbstractProtocol* AbstractProtocol::createInstance(StreamBase *stream,
AbstractProtocol *parent)
{
return NULL;
}
quint32 AbstractProtocol::protocolNumber() const
{
qDebug("Something wrong!!!");
return 0xFFFFFFFF;
}
/*!
\fn virtual void protoDataCopyInto(OstProto::OstProto::StreamCore &stream) = 0;
Copy the protocol's protobuf into the passed in stream \n
In the base class this is a pure virtual function. Subclasses should
implement this function by using - \n
stream.AddExtension(<ExtId>)->CopyFrom(<protobuf_data>) */
/*
\fn virtual void protoDataCopyFrom(const OstProto::OstProto::StreamCore &stream) = 0;
*/
/*! Returns the full name of the protocol \n
The default implementation returns a null string */
QString AbstractProtocol::name() const
{
return QString();
}
/*! Returns the short name or abbreviation of the protocol \n
The default implementation forms and returns a abbreviation composed
of all the upper case chars in name() \n
The default implementation caches the abbreviation on its first invocation
and subsequently returns the cached abbreviation */
QString AbstractProtocol::shortName() const
{
if (protoAbbr.isNull())
{
QString abbr;
for (int i = 0; i < name().size(); i++)
if (name().at(i).isUpper()) abbr.append(name().at(i));
if (abbr.size())
protoAbbr = abbr;
else
protoAbbr = QString("");
}
return protoAbbr;
}
/*! Returns the number of fields (both Frame and Meta fields) \n
The default implementation returns zero */
int AbstractProtocol::fieldCount() const
{
return 0;
}
/*! Returns the number of meta fields \n
The default implementation counts and returns the number of fields for which
the FieldIsMeta flag is set\n
The default implementation caches the count on its first invocation
and subsequently returns the cached count */
int AbstractProtocol::metaFieldCount() const
{
if (metaCount < 0)
{
int c = 0;
for (int i = 0; i < fieldCount() ; i++)
if (fieldFlags(i).testFlag(FieldIsMeta))
c++;
metaCount = c;
}
return metaCount;
}
/*! Returns the number of frame fields \n
Convenience method - same as fieldCount() minus metaFieldCount() */
int AbstractProtocol::frameFieldCount() const
{
//qDebug("%s:%d, %d", __FUNCTION__, fieldCount(), metaFieldCount());
return (fieldCount() - metaFieldCount());
}
AbstractProtocol::FieldFlags AbstractProtocol::fieldFlags(int index) const
{
return FieldIsNormal;
}
/*! Returns the requested field attribute data \n
Protocols which have meta fields that vary a frame field across
streams may use the streamIndex to return the appropriate field value \n
Some field attriubutes e.g. FieldName may be invariant across streams\n
The default implementation returns the fieldValue() converted to string
The FieldTextValue attribute may include additional information about
the field's value e.g. a checksum field may include "(correct)" or
"(incorrect)" alongwith the actual checksum value. \n
The default implementation returns a empty string for FieldName and
FieldTextValue; empty byte array of size 0 for FieldFrameValue; 0 for
FieldValue; subclasses are expected to return meaning values for all
these attributes. The only exception is the 'FieldBitSize' attribute -
the default implementation takes the (byte) size of FieldFrameValue,
multiplies it with 8 and returns the result - this can be used by
subclasses for fields which are an integral multiple of bytes; for
fields whose size are a non-integral multiple of bytes or smaller than
a byte, subclasses should return the correct value. Also for fields
which represent checksums, subclasses should return a value for
FieldBitSize - even if it is an integral multiple of bytes
\note If a subclass uses any of the below functions to derive
FieldFrameValue, the subclass should handle and return a value for
FieldBitSize to prevent endless recrusion -
- protocolFrameCksum()
- protocolFramePayloadSize()
*/
QVariant AbstractProtocol::fieldData(int index, FieldAttrib attrib,
int streamIndex) const
{
switch (attrib)
{
case FieldName:
return QString();
case FieldBitSize:
Q_ASSERT_X(!fieldFlags(index).testFlag(FieldIsCksum),
"AbstractProtocol::fieldData()",
"FieldBitSize for checksum fields need to be handled by the subclass");
return fieldData(index, FieldFrameValue, streamIndex).
toByteArray().size() * 8;
case FieldValue:
return 0;
case FieldFrameValue:
return QByteArray();
case FieldTextValue:
return QString();
default:
qFatal("%s:%d: unhandled case %d\n", __FUNCTION__, __LINE__,
attrib);
}
return QVariant();
}
/*! Sets the value of a field corresponding to index \n
Returns true if field is successfully set, false otherwise \n
The default implementation always returns false */
bool AbstractProtocol::setFieldData(int index, const QVariant &value,
FieldAttrib attrib)
{
return false;
}
quint32 AbstractProtocol::protocolId(ProtocolIdType type) const
{
return 0;
}
quint32 AbstractProtocol::payloadProtocolId(ProtocolIdType type) const
{
quint32 id;
if (next)
id = next->protocolId(type);
else if (parent)
id = parent->payloadProtocolId(type);
else
id = 0xFFFFFFFF;
qDebug("%s: payloadProtocolId = 0x%x", __FUNCTION__, id);
return id;
}
int AbstractProtocol::protocolFrameSize(int streamIndex) const
{
if (protoSize < 0)
{
int bitsize = 0;
for (int i = 0; i < fieldCount(); i++)
{
if (!fieldFlags(i).testFlag(FieldIsMeta))
bitsize += fieldData(i, FieldBitSize, streamIndex).toUInt();
}
protoSize = (bitsize+7)/8;
}
qDebug("%s: protoSize = %d", __FUNCTION__, protoSize);
return protoSize;
}
int AbstractProtocol::protocolFrameOffset(int streamIndex) const
{
int size = 0;
AbstractProtocol *p = prev;
while (p)
{
size += p->protocolFrameSize(streamIndex);
p = p->prev;
}
if (parent)
size += parent->protocolFrameOffset(streamIndex);
qDebug("%s: ofs = %d", __FUNCTION__, size);
return size;
}
int AbstractProtocol::protocolFramePayloadSize(int streamIndex) const
{
int size = 0;
AbstractProtocol *p = next;
while (p)
{
size += p->protocolFrameSize(streamIndex);
p = p->next;
}
if (parent)
size += parent->protocolFramePayloadSize(streamIndex);
qDebug("%s: payloadSize = %d", __FUNCTION__, size);
return size;
}
/*! Returns a byte array encoding the protocol (and its fields) which can be
inserted into the stream's frame
The default implementation forms and returns an ordered concatenation of
the FrameValue of all the 'frame' fields of the protocol taking care of fields
which are not an integral number of bytes\n */
QByteArray AbstractProtocol::protocolFrameValue(int streamIndex, bool forCksum) const
{
QByteArray proto, field;
uint bits, lastbitpos = 0;
FieldFlags flags;
for (int i=0; i < fieldCount() ; i++)
{
flags = fieldFlags(i);
if (!flags.testFlag(FieldIsMeta))
{
bits = fieldData(i, FieldBitSize, streamIndex).toUInt();
Q_ASSERT(bits > 0);
if (forCksum && flags.testFlag(FieldIsCksum))
{
field.resize((bits+7)/8);
field.fill('\0');
}
else
field = fieldData(i, FieldFrameValue, streamIndex).toByteArray();
qDebug("<<< %d, %d/%d >>>>", proto.size(), bits, field.size());
if (bits == (uint) field.size() * 8)
{
if (lastbitpos == 0)
proto.append(field);
else
{
Q_ASSERT(field.size() > 0);
char c = proto[proto.size() - 1];
proto[proto.size() - 1] = c | (field.at(0) >> lastbitpos);
for (int j = 0; j < field.size() - 1; j++)
proto.append(field.at(j) << lastbitpos |
field.at(j+1) >> lastbitpos);
}
}
else if (bits < (uint) field.size() * 8)
{
uchar c;
uint v;
v = (field.size()*8) - bits;
Q_ASSERT(v < 8);
if (lastbitpos == 0)
{
for (int j = 0; j < field.size(); j++)
{
c = field.at(j) << v;
if ((j+1) < field.size())
c |= ((uchar)field.at(j+1) >> (8-v));
proto.append(c);
}
lastbitpos = (lastbitpos + bits) % 8;
}
else
{
Q_ASSERT(proto.size() > 0);
for (int j = 0; j < field.size(); j++)
{
uchar d;
c = field.at(j) << v;
if ((j+1) < field.size())
c |= ((uchar) field.at(j+1) >> (8-v));
d = proto[proto.size() - 1];
proto[proto.size() - 1] = d | ((uchar) c >> lastbitpos);
if (bits > (8*j + (8 - v)))
proto.append(c << (8-lastbitpos));
}
lastbitpos = (lastbitpos + bits) % 8;
}
}
else // if (bits > field.size() * 8)
{
qFatal("bitsize more than FrameValue size. skipping...");
continue;
}
}
}
return proto;
}
/*!
\note If a subclass uses protocolFrameCksum() from within fieldData() to
derive a cksum field, it MUST handle and return the 'FieldBitSize'
attribute also for that particular field instead of using the default
AbstractProtocol implementation for 'FieldBitSize' - this is required
to prevent infinite recursion
*/
quint32 AbstractProtocol::protocolFrameCksum(int streamIndex,
CksumType cksumType) const
{
static int recursionCount = 0;
quint32 cksum = 0xFFFFFFFF;
recursionCount++;
Q_ASSERT_X(recursionCount < 10, "protocolFrameCksum", "potential infinite recursion - does a protocol checksum field not implement FieldBitSize?");
switch(cksumType)
{
case CksumIp:
{
QByteArray fv;
quint16 *ip;
quint32 len, sum = 0;
fv = protocolFrameValue(streamIndex, true);
ip = (quint16*) fv.constData();
len = fv.size();
while(len > 1)
{
sum += *ip;
if(sum & 0x80000000)
sum = (sum & 0xFFFF) + (sum >> 16);
ip++;
len -= 2;
}
if (len)
sum += (unsigned short) *(unsigned char *)ip;
while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);
cksum = qFromBigEndian((quint16) ~sum);
break;
}
case CksumTcpUdp:
{
quint16 cks;
quint32 sum = 0;
cks = protocolFrameCksum(streamIndex, CksumIp);
sum += (quint16) ~cks;
cks = protocolFramePayloadCksum(streamIndex, CksumIp);
sum += (quint16) ~cks;
cks = protocolFrameHeaderCksum(streamIndex, CksumIpPseudo);
sum += (quint16) ~cks;
while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);
cksum = (~sum) & 0xFFFF;
break;
}
default:
break;
}
recursionCount--;
return cksum;
}
quint32 AbstractProtocol::protocolFrameHeaderCksum(int streamIndex,
CksumType cksumType) const
{
quint32 sum = 0;
quint16 cksum;
AbstractProtocol *p = prev;
Q_ASSERT(cksumType == CksumIpPseudo);
while (p)
{
cksum = p->protocolFrameCksum(streamIndex, cksumType);
sum += (quint16) ~cksum;
p = p->prev;
qDebug("%s: sum = %u, cksum = %u", __FUNCTION__, sum, cksum);
}
if (parent)
{
cksum = parent->protocolFrameHeaderCksum(streamIndex, cksumType);
sum += (quint16) ~cksum;
}
while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);
return (quint16) ~sum;
}
quint32 AbstractProtocol::protocolFramePayloadCksum(int streamIndex,
CksumType cksumType) const
{
quint32 sum = 0;
quint16 cksum;
AbstractProtocol *p = next;
Q_ASSERT(cksumType == CksumIp);
while (p)
{
cksum = p->protocolFrameCksum(streamIndex, cksumType);
sum += (quint16) ~cksum;
p = p->next;
}
if (parent)
{
cksum = parent->protocolFramePayloadCksum(streamIndex, cksumType);
sum += (quint16) ~cksum;
}
while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);
return (quint16) ~sum;
}