292 lines
9.0 KiB
C++
292 lines
9.0 KiB
C++
|
/****************************************************************************
|
||
|
Copyright (c) 2009, Radon Labs GmbH
|
||
|
Copyright (c) 2011-2013,WebJet Business Division,CYOU
|
||
|
|
||
|
http://www.genesis-3d.com.cn
|
||
|
|
||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
of this software and associated documentation files (the "Software"), to deal
|
||
|
in the Software without restriction, including without limitation the rights
|
||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
copies of the Software, and to permit persons to whom the Software is
|
||
|
furnished to do so, subject to the following conditions:
|
||
|
|
||
|
The above copyright notice and this permission notice shall be included in
|
||
|
all copies or substantial portions of the Software.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
|
THE SOFTWARE.
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include "stdneb.h"
|
||
|
#include "net/debugpacket.h"
|
||
|
#include "system/byteorder.h"
|
||
|
|
||
|
namespace Net
|
||
|
{
|
||
|
|
||
|
using namespace Util;
|
||
|
using namespace IO;
|
||
|
using namespace System;
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
DebugPacket::DebugPacket() :
|
||
|
hasData(false)
|
||
|
{
|
||
|
// empty
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
DebugPacket::~DebugPacket()
|
||
|
{
|
||
|
// empty
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
Write data to the packet. Returns the number of data written. If all
|
||
|
data could be written, the returned number is identical with the
|
||
|
requested size, and the packet's payload size will be set to that size.
|
||
|
This means the packet completes a message.
|
||
|
If not all data could be written, the actually written size (MaxPayloadSize)
|
||
|
will be returned, and the internal payloadSize will be set to 0xFFFF, meaning
|
||
|
that the packet contains incomplete data which will be continued with the
|
||
|
next packet.
|
||
|
*/
|
||
|
SizeT
|
||
|
DebugPacket::Write(ushort portNum, uint packetCount, const ubyte* buf, SizeT numBytes)
|
||
|
{
|
||
|
n_assert(0 != buf);
|
||
|
n_assert(numBytes > 0);
|
||
|
n_assert(!this->hasData);
|
||
|
this->hasData = true;
|
||
|
|
||
|
ByteOrder byteOrder(ByteOrder::Host, ByteOrder::Network);
|
||
|
union { ubyte *b; uint *u; ushort *us; } pun;
|
||
|
pun.b = this->buffer;
|
||
|
uint* uintHeader = pun.u;
|
||
|
ushort* ushortHeader = pun.us;
|
||
|
ubyte* payloadPtr = this->buffer + HeaderSize;
|
||
|
|
||
|
SizeT numActualBytes = numBytes < MaxPayloadSize ? numBytes : MaxPayloadSize;
|
||
|
if (numActualBytes < numBytes)
|
||
|
{
|
||
|
// setup the header for an incomplete packet
|
||
|
uintHeader[0] = byteOrder.Convert<uint>(FourCC('DPKT').AsUInt());
|
||
|
uintHeader[1] = byteOrder.Convert<uint>(packetCount);
|
||
|
ushortHeader[4] = byteOrder.Convert<ushort>(portNum);
|
||
|
ushortHeader[5] = byteOrder.Convert<ushort>(0xFFFF);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// setup the header for a complete packet
|
||
|
uintHeader[0] = byteOrder.Convert<uint>(FourCC('DPKT').AsUInt());
|
||
|
uintHeader[1] = byteOrder.Convert<uint>(packetCount);
|
||
|
ushortHeader[4] = byteOrder.Convert<ushort>(portNum);
|
||
|
ushortHeader[5] = byteOrder.Convert<ushort>((ushort)numActualBytes);
|
||
|
}
|
||
|
|
||
|
// copy the payload
|
||
|
Memory::Copy(buf, payloadPtr, numActualBytes);
|
||
|
|
||
|
// return number of bytes written
|
||
|
return numActualBytes;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
Write raw data to the packet. The source buffer must contain a valid
|
||
|
packet header and the size of the source data must equal
|
||
|
DebugPacket::PacketSize!
|
||
|
*/
|
||
|
void
|
||
|
DebugPacket::WriteRaw(const void* buf, SizeT bufSize)
|
||
|
{
|
||
|
n_assert(PacketSize == bufSize);
|
||
|
Memory::Copy(buf, this->buffer, PacketSize);
|
||
|
this->hasData = true;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
Get the magic code at the beginning of the message. Must be
|
||
|
FourCC('DPKT').
|
||
|
*/
|
||
|
FourCC
|
||
|
DebugPacket::GetMagic() const
|
||
|
{
|
||
|
n_assert(this->hasData);
|
||
|
ByteOrder byteOrder(ByteOrder::Network, ByteOrder::Host);
|
||
|
union pun { const uint *u; const ubyte *b; } pun;
|
||
|
pun.b = this->buffer;
|
||
|
FourCC magic = byteOrder.Convert<uint>(pun.u[0]);
|
||
|
return magic;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
Get the packet counter of this packet.
|
||
|
*/
|
||
|
uint
|
||
|
DebugPacket::GetCount() const
|
||
|
{
|
||
|
n_assert(this->hasData);
|
||
|
ByteOrder byteOrder(ByteOrder::Network, ByteOrder::Host);
|
||
|
union pun { const uint *u; const ubyte *b; } pun;
|
||
|
pun.b = this->buffer;
|
||
|
uint count = byteOrder.Convert<uint>(pun.u[1]);
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
Get the port number from the packet.
|
||
|
*/
|
||
|
ushort
|
||
|
DebugPacket::GetPort() const
|
||
|
{
|
||
|
n_assert(this->hasData);
|
||
|
ByteOrder byteOrder(ByteOrder::Network, ByteOrder::Host);
|
||
|
union pun { const ushort *us; const ubyte *b; } pun;
|
||
|
pun.b = this->buffer;
|
||
|
ushort portNum = byteOrder.Convert<ushort>(pun.us[4]);
|
||
|
return portNum;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
Return true if this is the final packet in a multi-packet message.
|
||
|
*/
|
||
|
bool
|
||
|
DebugPacket::IsFinalPacket() const
|
||
|
{
|
||
|
n_assert(this->hasData);
|
||
|
ByteOrder byteOrder(ByteOrder::Network, ByteOrder::Host);
|
||
|
union pun { const ushort *us; const ubyte *b; } pun;
|
||
|
pun.b = this->buffer;
|
||
|
ushort payloadSize = byteOrder.Convert<ushort>(pun.us[5]);
|
||
|
return (0xFFFF != payloadSize);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
Returns the number of payload data bytes in the packet. This will
|
||
|
always return a valid number, even if the payloadSize header member is
|
||
|
set to the special 0xFFFF code.
|
||
|
*/
|
||
|
SizeT
|
||
|
DebugPacket::GetPayloadSize() const
|
||
|
{
|
||
|
n_assert(this->hasData);
|
||
|
ByteOrder byteOrder(ByteOrder::Network, ByteOrder::Host);
|
||
|
union pun { const ushort *us; const ubyte *b; } pun;
|
||
|
pun.b = this->buffer;
|
||
|
ushort payloadSize = byteOrder.Convert<ushort>(pun.us[5]);
|
||
|
if (0xFFFF == payloadSize)
|
||
|
{
|
||
|
payloadSize = MaxPayloadSize;
|
||
|
}
|
||
|
return payloadSize;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
Get a pointer to the actual payload data.
|
||
|
*/
|
||
|
const ubyte*
|
||
|
DebugPacket::GetPayload() const
|
||
|
{
|
||
|
n_assert(this->hasData);
|
||
|
return this->buffer + HeaderSize;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
Get a pointer to the raw packet data.
|
||
|
*/
|
||
|
const ubyte*
|
||
|
DebugPacket::GetRawBuffer() const
|
||
|
{
|
||
|
return this->buffer;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
Array<DebugPacket>
|
||
|
DebugPacket::EncodeStream(ushort portNum, uint packetCounter, const GPtr<Stream>& stream)
|
||
|
{
|
||
|
n_assert(stream->CanBeMapped());
|
||
|
|
||
|
Array<DebugPacket> result;
|
||
|
SizeT bytesRemaining = stream->GetSize();
|
||
|
stream->SetAccessMode(Stream::ReadAccess);
|
||
|
bool streamOpenResult = stream->Open();
|
||
|
n_assert(streamOpenResult);
|
||
|
uchar* srcPtr = (uchar*) stream->Map();
|
||
|
do
|
||
|
{
|
||
|
DebugPacket packet;
|
||
|
|
||
|
// write next chunk of data
|
||
|
SizeT bytesWritten = packet.Write(portNum, packetCounter++, srcPtr, bytesRemaining);
|
||
|
srcPtr += bytesWritten;
|
||
|
bytesRemaining -= bytesWritten;
|
||
|
|
||
|
// add packet to result
|
||
|
result.Append(packet);
|
||
|
}
|
||
|
while (bytesRemaining > 0);
|
||
|
stream->Unmap();
|
||
|
stream->Close();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
/**
|
||
|
*/
|
||
|
void
|
||
|
DebugPacket::DecodePackets(const Array<DebugPacket>& packets,
|
||
|
const GPtr<Stream>& stream,
|
||
|
ushort& outPortNum)
|
||
|
{
|
||
|
n_assert(packets.Back().IsFinalPacket());
|
||
|
n_assert(packets.Size() > 0);
|
||
|
|
||
|
// read port number from first packet
|
||
|
outPortNum = packets[0].GetPort();
|
||
|
|
||
|
// open stream for writing and iterate over packets
|
||
|
stream->SetAccessMode(Stream::WriteAccess);
|
||
|
bool streamOpenResult = stream->Open();
|
||
|
n_assert(streamOpenResult);
|
||
|
IndexT i;
|
||
|
for (i = 0; i < packets.Size(); i++)
|
||
|
{
|
||
|
const DebugPacket& curPacket = packets[i];
|
||
|
n_assert(curPacket.HasData());
|
||
|
if (i < (packets.Size() - 1))
|
||
|
{
|
||
|
// make sure there aren't any final packets inbetween
|
||
|
n_assert(!curPacket.IsFinalPacket());
|
||
|
}
|
||
|
|
||
|
// make sure the port number is consistent across all packets
|
||
|
n_assert(curPacket.GetPort() == outPortNum);
|
||
|
|
||
|
// copy the packets payload into the stream
|
||
|
stream->Write(curPacket.GetPayload(), curPacket.GetPayloadSize());
|
||
|
}
|
||
|
stream->Close();
|
||
|
}
|
||
|
|
||
|
} // namespace Net
|