using System;
using System.IO;
using System.Net;
using UnityEngine;
using zlib;
namespace BF
{
///
/// @TODO GC
///
internal class NetChannelMessageService : INetChannelMessageService
{
private readonly bool isLittleEndian;
private readonly bool isCompress;
private NetAesEncrypt encrypt;
private NetAesEncrypt decrypt;
///
/// 数据包的头部长度,version + Compress + Seq + Group + Cmd 共8位
///
private int HeaderLength => 4;
///
/// 数据包头部长度,使用int类型表示,四个字节
///
private int HeaderLengthBytesSize => 4;
public NetChannelMessageService()
{
isLittleEndian = BitConverter.IsLittleEndian;
isCompress = false;
}
public void SetEncrypt(NetAesEncrypt encrypt)
{
this.encrypt = encrypt;
}
public void SetDecrypt(NetAesEncrypt decrypt)
{
this.decrypt = decrypt;
}
public int ReadBodyLength(CircularBuffer circularBuffer)
{
int bodyLength = 0;
if (circularBuffer.HowManyCanRead >= HeaderLengthBytesSize)
{
byte[] head1 = circularBuffer.Read(HeaderLengthBytesSize);
byte[] head = new byte[4];
head[0] = head1[3];
head[1] = head1[2];
head[2] = head1[1];
head[3] = head1[0];
bodyLength = BitConverter.ToInt32(head, 0);
if (isLittleEndian)
{
bodyLength = IPAddress.NetworkToHostOrder(bodyLength);
}
if (bodyLength <= 0)
{
bodyLength = -1;
}
}
return bodyLength;
}
public bool Serialize(NetOutgoingMessage message, MemoryStream destination)
{
try
{
//first write data package size, packageSize = header.length + data.length
byte[] packageLengthData = null;
// short packageLength = 0;
int packageLength = 0;
if (message.Group != 0)
{
// packageLength = (short)(message.PackDataLength + HeaderLength);
packageLength = message.PackDataLength + HeaderLength*2;
}
else
{
// packageLength = (short)message.PackDataLength;
packageLength = message.PackDataLength;
}
if (isLittleEndian)
{
packageLengthData = BitConverter.GetBytes(packageLength);
}
else
{
packageLengthData = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(packageLength));
}
destination.Write(packageLengthData, 0, packageLengthData.Length);
var realSendBuffer = SerializeRaw(message);
//is need encrypt
if (message.Group != 0)
{
if (encrypt == null)
{
throw new NotImplementedException("Serialize Error! NetAesEncrypt is null");
}
encrypt.Encrypt(realSendBuffer, 0, realSendBuffer.Length, realSendBuffer, 0);
}
destination.Write(realSendBuffer, 0, realSendBuffer.Length);
return true;
}
catch (Exception)
{
return false;
}
}
internal byte[] SerializeRaw(NetOutgoingMessage message)
{
if (message.Group != 0)
{
byte[] realSendBuffer = new byte[message.PackDataLength + HeaderLength*2];
byte[] seqBytes = null;
if (isLittleEndian)
{
seqBytes = BitConverter.GetBytes(message.Seq);
}
else
{
seqBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(message.Seq));
}
Array.Copy(seqBytes, 0, realSendBuffer, 0, HeaderLength);
//create send buffer
if (BitConverter.IsLittleEndian)
{
realSendBuffer[7] = (byte)((message.Group >> 24) & 0xFF);
realSendBuffer[6] = (byte)((message.Group >> 16) & 0xFF);
realSendBuffer[5] = (byte)((message.Group >> 8) & 0xFF);
realSendBuffer[4] = (byte)(message.Group & 0xFF);
}
else
{
realSendBuffer[4] = (byte)((message.Group >> 24) & 0xFF);
realSendBuffer[5] = (byte)((message.Group >> 16) & 0xFF);
realSendBuffer[6] = (byte)((message.Group >> 8) & 0xFF);
realSendBuffer[7] = (byte)(message.Group & 0xFF);
}
//write data
Array.Copy(message.Data, 0, realSendBuffer, HeaderLength*2, message.PackDataLength);
return realSendBuffer;
}
else
{
//create send buffer
byte[] realSendBuffer = new byte[message.PackDataLength];
Array.Copy(message.Data, 0, realSendBuffer, 0, message.PackDataLength);
return realSendBuffer;
}
}
///
/// @TODO Array GC
///
///
///
public bool Deserialize(NetIncomingMessage message, uint receiveSeq)
{
try
{
decrypt.Decrypt(message.buffer, 0, message.buffer.Length, message.buffer, 0);
DeserializeRaw(message, receiveSeq);
if (message.IsCompress)
{
message.buffer = DeCompressBuffer(message.buffer);
}
return true;
}
catch (Exception)
{
return false;
}
}
internal void DeserializeRaw(NetIncomingMessage message, uint receiveSeq)
{
//head
// message.Version = message.buffer[0];
// message.IsCompress = message.buffer[1] != 0;
// message.Group = message.buffer[2];
// message.CMD = message.buffer[3];
message.Group = (uint)(((message.buffer[7] & 0xFF) << 24)
| ((message.buffer[6] & 0xFF) << 16)
| ((message.buffer[5] & 0xFF) << 8)
| (message.buffer[4] & 0xFF));
message.CMD = receiveSeq;
var seq = BitConverter.ToInt32(message.buffer, 0);
if (isLittleEndian)
{
message.Seq = (uint) seq;
}
else
{
message.Seq = (uint) IPAddress.NetworkToHostOrder(seq);
}
//data, @TODO only copy
Array.Reverse(message.buffer);
Array.Resize(ref message.buffer, message.buffer.Length - HeaderLength*2);
Array.Reverse(message.buffer);
}
private byte[] DeCompressBuffer(byte[] byteArray)
{
using (MemoryStream outMemoryStream = new MemoryStream())
{
using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream))
{
using (Stream inMemoryStream = new MemoryStream(byteArray))
{
byte[] buffer = new byte[inMemoryStream.Length];
int len;
while ((len = inMemoryStream.Read(buffer, 0, buffer.Length)) > 0)
{
outZStream.Write(buffer, 0, len);
}
outZStream.Flush();
outZStream.finish();
return outMemoryStream.ToArray();
}
}
}
}
private byte[] CompressBuffer(byte[] byteArray)
{
using (MemoryStream outMemoryStream = new MemoryStream())
{
using (ZInputStream zInputStream = new ZInputStream(outMemoryStream))
{
using (Stream inMemoryStream = new MemoryStream(byteArray))
{
byte[] buffer = new byte[inMemoryStream.Length];
int len;
while ((len = inMemoryStream.Read(buffer, 0, buffer.Length)) > 0)
{
zInputStream.Read(buffer, 0, len);
}
inMemoryStream.Flush();
return outMemoryStream.ToArray();
}
}
}
}
}
}