* Rewrote the Header class as a struct and optimize for speed. This shouldn't be a breaking change for most apps, but GridProxy and WinGridProxy will need to be tested as thoroughly as possible. Important to note is that Packet.Header.AckList can be null now

* 404 checking in SeedRequestCompleteHandler
* A few new big endian conversion methods in Utils

git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@2709 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
John Hurliman
2009-05-08 06:38:28 +00:00
parent 9d0c803450
commit 79beceeb1d
11 changed files with 3082 additions and 3853 deletions

View File

@@ -52,69 +52,65 @@ namespace OpenMetaverse.Packets
}
/// <summary>
/// The header of a message template packet. Either 5, 6, or 8 bytes in
/// length at the beginning of the packet, and encapsulates any
/// appended ACKs at the end of the packet as well
/// The header of a message template packet. Holds packet flags, sequence
/// number, packet ID, and any ACKs that will be appended at the end of
/// the packet
/// </summary>
public abstract class Header
public struct Header
{
/// <summary>Raw header data, does not include appended ACKs</summary>
public byte[] Data;
/// <summary>Raw value of the flags byte</summary>
public byte Flags
{
get { return Data[0]; }
set { Data[0] = value; }
}
/// <summary>Reliable flag, whether this packet requires an ACK</summary>
public bool Reliable
{
get { return (Data[0] & Helpers.MSG_RELIABLE) != 0; }
set { if (value) { Data[0] |= (byte)Helpers.MSG_RELIABLE; } else { byte mask = (byte)Helpers.MSG_RELIABLE ^ 0xFF; Data[0] &= mask; } }
}
/// <summary>Resent flag, whether this same packet has already been
/// sent</summary>
public bool Resent
{
get { return (Data[0] & Helpers.MSG_RESENT) != 0; }
set { if (value) { Data[0] |= (byte)Helpers.MSG_RESENT; } else { byte mask = (byte)Helpers.MSG_RESENT ^ 0xFF; Data[0] &= mask; } }
}
/// <summary>Zerocoded flag, whether this packet is compressed with
/// zerocoding</summary>
public bool Zerocoded
{
get { return (Data[0] & Helpers.MSG_ZEROCODED) != 0; }
set { if (value) { Data[0] |= (byte)Helpers.MSG_ZEROCODED; } else { byte mask = (byte)Helpers.MSG_ZEROCODED ^ 0xFF; Data[0] &= mask; } }
}
/// <summary>Appended ACKs flag, whether this packet has ACKs appended
/// to the end</summary>
public bool AppendedAcks
{
get { return (Data[0] & Helpers.MSG_APPENDED_ACKS) != 0; }
set { if (value) { Data[0] |= (byte)Helpers.MSG_APPENDED_ACKS; } else { byte mask = (byte)Helpers.MSG_APPENDED_ACKS ^ 0xFF; Data[0] &= mask; } }
}
/// <summary>Packet sequence number</summary>
public uint Sequence
{
get { return (uint)((Data[1] << 24) + (Data[2] << 16) + (Data[3] << 8) + Data[4]); }
set
{
Data[1] = (byte)(value >> 24); Data[2] = (byte)(value >> 16);
Data[3] = (byte)(value >> 8); Data[4] = (byte)(value % 256);
}
}
/// <summary>Numeric ID number of this packet</summary>
public abstract ushort ID { get; set; }
/// <summary>Frequency classification of this packet, Low Medium or
/// High</summary>
public abstract PacketFrequency Frequency { get; }
/// <summary>Convert this header to a byte array, not including any
/// appended ACKs</summary>
public abstract void ToBytes(byte[] bytes, ref int i);
/// <summary>Array containing all the appended ACKs of this packet</summary>
public bool Reliable;
public bool Resent;
public bool Zerocoded;
public bool AppendedAcks;
public uint Sequence;
public ushort ID;
public PacketFrequency Frequency;
public uint[] AckList;
public abstract void FromBytes(byte[] bytes, ref int pos, ref int packetEnd);
public void ToBytes(byte[] bytes, ref int i)
{
byte flags = 0;
if (Reliable) flags |= Helpers.MSG_RELIABLE;
if (Resent) flags |= Helpers.MSG_RESENT;
if (Zerocoded) flags |= Helpers.MSG_ZEROCODED;
if (AppendedAcks) flags |= Helpers.MSG_APPENDED_ACKS;
// Flags
bytes[i++] = flags;
// Sequence number
Utils.UIntToBytesBig(Sequence, bytes, i);
i += 4;
// Extra byte
bytes[i++] = 0;
// Packet ID
switch (Frequency)
{
case PacketFrequency.High:
// 1 byte ID
bytes[i++] = (byte)ID;
break;
case PacketFrequency.Medium:
// 2 byte ID
bytes[i++] = 0xFF;
bytes[i++] = (byte)ID;
break;
case PacketFrequency.Low:
// 4 byte ID
bytes[i++] = 0xFF;
bytes[i++] = 0xFF;
Utils.UInt16ToBytesBig(ID, bytes, i);
i += 2;
break;
}
}
public void FromBytes(byte[] bytes, ref int pos, ref int packetEnd)
{
this = BuildHeader(bytes, ref pos, ref packetEnd);
}
/// <summary>
/// Convert the AckList to a byte array, used for packet serializing
@@ -126,10 +122,8 @@ namespace OpenMetaverse.Packets
{
foreach (uint ack in AckList)
{
bytes[i++] = (byte)((ack >> 24) % 256);
bytes[i++] = (byte)((ack >> 16) % 256);
bytes[i++] = (byte)((ack >> 8) % 256);
bytes[i++] = (byte)(ack % 256);
Utils.UIntToBytesBig(ack, bytes, i);
i += 4;
}
if (AckList.Length > 0) { bytes[i++] = (byte)AckList.Length; }
}
@@ -143,21 +137,48 @@ namespace OpenMetaverse.Packets
/// <returns></returns>
public static Header BuildHeader(byte[] bytes, ref int pos, ref int packetEnd)
{
if (bytes[6] == 0xFF)
Header header;
byte flags = bytes[pos];
header.AppendedAcks = (flags & Helpers.MSG_APPENDED_ACKS) != 0;
header.Reliable = (flags & Helpers.MSG_RELIABLE) != 0;
header.Resent = (flags & Helpers.MSG_RESENT) != 0;
header.Zerocoded = (flags & Helpers.MSG_ZEROCODED) != 0;
header.Sequence = (uint)((bytes[pos + 1] << 24) + (bytes[pos + 2] << 16) + (bytes[pos + 3] << 8) + bytes[pos + 4]);
// Set the frequency and packet ID number
if (bytes[pos + 6] == 0xFF)
{
if (bytes[7] == 0xFF)
if (bytes[pos + 7] == 0xFF)
{
return new LowHeader(bytes, ref pos, ref packetEnd);
header.Frequency = PacketFrequency.Low;
if (header.Zerocoded && bytes[pos + 8] == 0)
header.ID = bytes[pos + 10];
else
header.ID = (ushort)((bytes[pos + 8] << 8) + bytes[pos + 9]);
pos += 10;
}
else
{
return new MediumHeader(bytes, ref pos, ref packetEnd);
header.Frequency = PacketFrequency.Medium;
header.ID = bytes[pos + 7];
pos += 8;
}
}
else
{
return new HighHeader(bytes, ref pos, ref packetEnd);
header.Frequency = PacketFrequency.High;
header.ID = bytes[pos + 6];
pos += 7;
}
header.AckList = null;
CreateAckList(ref header, bytes, ref packetEnd);
return header;
}
/// <summary>
@@ -165,216 +186,24 @@ namespace OpenMetaverse.Packets
/// </summary>
/// <param name="bytes"></param>
/// <param name="packetEnd"></param>
protected void CreateAckList(byte[] bytes, ref int packetEnd)
static void CreateAckList(ref Header header, byte[] bytes, ref int packetEnd)
{
if (AppendedAcks)
if (header.AppendedAcks)
{
try
int count = bytes[packetEnd--];
header.AckList = new uint[count];
for (int i = 0; i < count; i++)
{
int count = bytes[packetEnd--];
AckList = new uint[count];
for (int i = 0; i < count; i++)
{
AckList[i] = (uint)(
(bytes[(packetEnd - i * 4) - 3] << 24) |
(bytes[(packetEnd - i * 4) - 2] << 16) |
(bytes[(packetEnd - i * 4) - 1] << 8) |
(bytes[(packetEnd - i * 4) ]));
}
header.AckList[i] = (uint)(
(bytes[(packetEnd - i * 4) - 3] << 24) |
(bytes[(packetEnd - i * 4) - 2] << 16) |
(bytes[(packetEnd - i * 4) - 1] << 8) |
(bytes[(packetEnd - i * 4) ]));
}
packetEnd -= (count * 4);
}
catch (Exception)
{
AckList = new uint[0];
throw new MalformedDataException();
}
packetEnd -= (count * 4);
}
else
{
AckList = new uint[0];
}
}
}
/// <summary>
///
/// </summary>
public class LowHeader : Header
{
/// <summary></summary>
public override ushort ID
{
get { return (ushort)((Data[8] << 8) + Data[9]); }
set { Data[8] = (byte)(value >> 8); Data[9] = (byte)(value % 256); }
}
/// <summary></summary>
public override PacketFrequency Frequency { get { return PacketFrequency.Low; } }
/// <summary>
///
/// </summary>
public LowHeader()
{
Data = new byte[10];
Data[6] = Data[7] = 0xFF;
AckList = new uint[0];
}
/// <summary>
///
/// </summary>
/// <param name="bytes"></param>
/// <param name="pos"></param>
/// <param name="packetEnd"></param>
public LowHeader(byte[] bytes, ref int pos, ref int packetEnd)
{
FromBytes(bytes, ref pos, ref packetEnd);
}
override public void FromBytes(byte[] bytes, ref int pos, ref int packetEnd)
{
if (bytes.Length < 10) { throw new MalformedDataException(); }
Data = new byte[10];
Buffer.BlockCopy(bytes, 0, Data, 0, 10);
if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0 && bytes[8] == 0)
{
if (bytes[9] == 1)
{
Data[9] = bytes[10];
}
else
{
throw new MalformedDataException();
}
}
pos = 10;
CreateAckList(bytes, ref packetEnd);
}
/// <summary>
///
/// </summary>
/// <param name="bytes"></param>
/// <param name="i"></param>
public override void ToBytes(byte[] bytes, ref int i)
{
Buffer.BlockCopy(Data, 0, bytes, i, 10);
i += 10;
}
}
/// <summary>
///
/// </summary>
public class MediumHeader : Header
{
/// <summary></summary>
public override ushort ID
{
get { return (ushort)Data[7]; }
set { Data[7] = (byte)value; }
}
/// <summary></summary>
public override PacketFrequency Frequency { get { return PacketFrequency.Medium; } }
/// <summary>
///
/// </summary>
public MediumHeader()
{
Data = new byte[8];
Data[6] = 0xFF;
AckList = new uint[0];
}
/// <summary>
///
/// </summary>
/// <param name="bytes"></param>
/// <param name="pos"></param>
/// <param name="packetEnd"></param>
public MediumHeader(byte[] bytes, ref int pos, ref int packetEnd)
{
FromBytes(bytes, ref pos, ref packetEnd);
}
override public void FromBytes(byte[] bytes, ref int pos, ref int packetEnd)
{
if (bytes.Length < 8) { throw new MalformedDataException(); }
Data = new byte[8];
Buffer.BlockCopy(bytes, 0, Data, 0, 8);
pos = 8;
CreateAckList(bytes, ref packetEnd);
}
/// <summary>
///
/// </summary>
/// <param name="bytes"></param>
/// <param name="i"></param>
public override void ToBytes(byte[] bytes, ref int i)
{
Buffer.BlockCopy(Data, 0, bytes, i, 8);
i += 8;
}
}
/// <summary>
///
/// </summary>
public class HighHeader : Header
{
/// <summary></summary>
public override ushort ID
{
get { return (ushort)Data[6]; }
set { Data[6] = (byte)value; }
}
/// <summary></summary>
public override PacketFrequency Frequency { get { return PacketFrequency.High; } }
/// <summary>
///
/// </summary>
public HighHeader()
{
Data = new byte[7];
AckList = new uint[0];
}
/// <summary>
///
/// </summary>
/// <param name="bytes"></param>
/// <param name="pos"></param>
/// <param name="packetEnd"></param>
public HighHeader(byte[] bytes, ref int pos, ref int packetEnd)
{
FromBytes(bytes, ref pos, ref packetEnd);
}
override public void FromBytes(byte[] bytes, ref int pos, ref int packetEnd)
{
if (bytes.Length < 7) { throw new MalformedDataException(); }
Data = new byte[7];
Buffer.BlockCopy(bytes, 0, Data, 0, 7);
pos = 7;
CreateAckList(bytes, ref packetEnd);
}
/// <summary>
///
/// </summary>
/// <param name="bytes"></param>
/// <param name="i"></param>
public override void ToBytes(byte[] bytes, ref int i)
{
Buffer.BlockCopy(Data, 0, bytes, i, 7);
i += 7;
}
}