您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
276 行
8.8 KiB
276 行
8.8 KiB
using System;
|
|
using System.Net;
|
|
using LiteNetLib.Utils;
|
|
|
|
namespace LiteNetLib
|
|
{
|
|
internal enum PacketProperty : byte
|
|
{
|
|
Unreliable,
|
|
Channeled,
|
|
Ack,
|
|
Ping,
|
|
Pong,
|
|
ConnectRequest,
|
|
ConnectAccept,
|
|
Disconnect,
|
|
UnconnectedMessage,
|
|
MtuCheck,
|
|
MtuOk,
|
|
Broadcast,
|
|
Merged,
|
|
ShutdownOk,
|
|
PeerNotFound,
|
|
InvalidProtocol,
|
|
NatMessage,
|
|
Empty
|
|
}
|
|
|
|
internal sealed class NetPacket
|
|
{
|
|
private static readonly int LastProperty = Enum.GetValues(typeof(PacketProperty)).Length;
|
|
private static readonly int[] HeaderSizes;
|
|
|
|
static NetPacket()
|
|
{
|
|
HeaderSizes = new int[LastProperty+1];
|
|
for (int i = 0; i < HeaderSizes.Length; i++)
|
|
{
|
|
switch ((PacketProperty)i)
|
|
{
|
|
case PacketProperty.Channeled:
|
|
case PacketProperty.Ack:
|
|
HeaderSizes[i] = NetConstants.ChanneledHeaderSize;
|
|
break;
|
|
case PacketProperty.Ping:
|
|
HeaderSizes[i] = NetConstants.HeaderSize + 2;
|
|
break;
|
|
case PacketProperty.ConnectRequest:
|
|
HeaderSizes[i] = NetConnectRequestPacket.HeaderSize;
|
|
break;
|
|
case PacketProperty.ConnectAccept:
|
|
HeaderSizes[i] = NetConnectAcceptPacket.Size;
|
|
break;
|
|
case PacketProperty.Disconnect:
|
|
HeaderSizes[i] = NetConstants.HeaderSize + 8;
|
|
break;
|
|
case PacketProperty.Pong:
|
|
HeaderSizes[i] = NetConstants.HeaderSize + 10;
|
|
break;
|
|
default:
|
|
HeaderSizes[i] = NetConstants.HeaderSize;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Header
|
|
public PacketProperty Property
|
|
{
|
|
get { return (PacketProperty)(RawData[0] & 0x1F); }
|
|
set { RawData[0] = (byte)((RawData[0] & 0xE0) | (byte)value); }
|
|
}
|
|
|
|
public byte ConnectionNumber
|
|
{
|
|
get { return (byte)((RawData[0] & 0x60) >> 5); }
|
|
set { RawData[0] = (byte) ((RawData[0] & 0x9F) | (value << 5)); }
|
|
}
|
|
|
|
public ushort Sequence
|
|
{
|
|
get { return BitConverter.ToUInt16(RawData, 1); }
|
|
set { FastBitConverter.GetBytes(RawData, 1, value); }
|
|
}
|
|
|
|
public bool IsFragmented
|
|
{
|
|
get { return (RawData[0] & 0x80) != 0; }
|
|
}
|
|
|
|
public void MarkFragmented()
|
|
{
|
|
RawData[0] |= 0x80; //set first bit
|
|
}
|
|
|
|
public byte ChannelId
|
|
{
|
|
get { return RawData[3]; }
|
|
set { RawData[3] = value; }
|
|
}
|
|
|
|
public ushort FragmentId
|
|
{
|
|
get { return BitConverter.ToUInt16(RawData, 4); }
|
|
set { FastBitConverter.GetBytes(RawData, 4, value); }
|
|
}
|
|
|
|
public ushort FragmentPart
|
|
{
|
|
get { return BitConverter.ToUInt16(RawData, 6); }
|
|
set { FastBitConverter.GetBytes(RawData, 6, value); }
|
|
}
|
|
|
|
public ushort FragmentsTotal
|
|
{
|
|
get { return BitConverter.ToUInt16(RawData, 8); }
|
|
set { FastBitConverter.GetBytes(RawData, 8, value); }
|
|
}
|
|
|
|
//Data
|
|
public byte[] RawData;
|
|
public int Size;
|
|
|
|
//Delivery
|
|
public object UserData;
|
|
|
|
//Pool node
|
|
public NetPacket Next;
|
|
|
|
public NetPacket(int size)
|
|
{
|
|
RawData = new byte[size];
|
|
Size = size;
|
|
}
|
|
|
|
public NetPacket(PacketProperty property, int size)
|
|
{
|
|
size += GetHeaderSize(property);
|
|
RawData = new byte[size];
|
|
Property = property;
|
|
Size = size;
|
|
}
|
|
|
|
public static int GetHeaderSize(PacketProperty property)
|
|
{
|
|
return HeaderSizes[(int)property];
|
|
}
|
|
|
|
public int GetHeaderSize()
|
|
{
|
|
return HeaderSizes[RawData[0] & 0x1F];
|
|
}
|
|
|
|
//Packet constructor from byte array
|
|
public bool FromBytes(byte[] data, int start, int packetSize)
|
|
{
|
|
//Reading property
|
|
byte property = (byte)(data[start] & 0x1F);
|
|
bool fragmented = (data[start] & 0x80) != 0;
|
|
int headerSize = HeaderSizes[property];
|
|
|
|
if (property > LastProperty || packetSize < headerSize ||
|
|
(fragmented && packetSize < headerSize + NetConstants.FragmentHeaderSize) ||
|
|
data.Length < start + packetSize)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Buffer.BlockCopy(data, start, RawData, 0, packetSize);
|
|
Size = (ushort)packetSize;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
internal sealed class NetConnectRequestPacket
|
|
{
|
|
public const int HeaderSize = 14;
|
|
public readonly long ConnectionTime;
|
|
public readonly byte ConnectionNumber;
|
|
public readonly byte[] TargetAddress;
|
|
public readonly NetDataReader Data;
|
|
|
|
private NetConnectRequestPacket(long connectionTime, byte connectionNumber, byte[] targetAddress, NetDataReader data)
|
|
{
|
|
ConnectionTime = connectionTime;
|
|
ConnectionNumber = connectionNumber;
|
|
TargetAddress = targetAddress;
|
|
Data = data;
|
|
}
|
|
|
|
public static int GetProtocolId(NetPacket packet)
|
|
{
|
|
return BitConverter.ToInt32(packet.RawData, 1);
|
|
}
|
|
|
|
public static NetConnectRequestPacket FromData(NetPacket packet)
|
|
{
|
|
if (packet.ConnectionNumber >= NetConstants.MaxConnectionNumber)
|
|
return null;
|
|
|
|
//Getting new id for peer
|
|
long connectionId = BitConverter.ToInt64(packet.RawData, 5);
|
|
|
|
//Get target address
|
|
int addrSize = packet.RawData[13];
|
|
if (addrSize != 16 && addrSize != 28)
|
|
return null;
|
|
byte[] addressBytes = new byte[addrSize];
|
|
Buffer.BlockCopy(packet.RawData, 14, addressBytes, 0, addrSize);
|
|
|
|
// Read data and create request
|
|
var reader = new NetDataReader(null, 0, 0);
|
|
if (packet.Size > HeaderSize+addrSize)
|
|
reader.SetSource(packet.RawData, HeaderSize + addrSize, packet.Size);
|
|
|
|
return new NetConnectRequestPacket(connectionId, packet.ConnectionNumber, addressBytes, reader);
|
|
}
|
|
|
|
public static NetPacket Make(NetDataWriter connectData, SocketAddress addressBytes, long connectId)
|
|
{
|
|
//Make initial packet
|
|
var packet = new NetPacket(PacketProperty.ConnectRequest, connectData.Length+addressBytes.Size);
|
|
|
|
//Add data
|
|
FastBitConverter.GetBytes(packet.RawData, 1, NetConstants.ProtocolId);
|
|
FastBitConverter.GetBytes(packet.RawData, 5, connectId);
|
|
packet.RawData[13] = (byte)addressBytes.Size;
|
|
for (int i = 0; i < addressBytes.Size; i++)
|
|
packet.RawData[14+i] = addressBytes[i];
|
|
Buffer.BlockCopy(connectData.Data, 0, packet.RawData, 14+addressBytes.Size, connectData.Length);
|
|
return packet;
|
|
}
|
|
}
|
|
|
|
internal sealed class NetConnectAcceptPacket
|
|
{
|
|
public const int Size = 11;
|
|
public readonly long ConnectionId;
|
|
public readonly byte ConnectionNumber;
|
|
public readonly bool IsReusedPeer;
|
|
|
|
private NetConnectAcceptPacket(long connectionId, byte connectionNumber, bool isReusedPeer)
|
|
{
|
|
ConnectionId = connectionId;
|
|
ConnectionNumber = connectionNumber;
|
|
IsReusedPeer = isReusedPeer;
|
|
}
|
|
|
|
public static NetConnectAcceptPacket FromData(NetPacket packet)
|
|
{
|
|
if (packet.Size > Size)
|
|
return null;
|
|
|
|
long connectionId = BitConverter.ToInt64(packet.RawData, 1);
|
|
//check connect num
|
|
byte connectionNumber = packet.RawData[9];
|
|
if (connectionNumber >= NetConstants.MaxConnectionNumber)
|
|
return null;
|
|
//check reused flag
|
|
byte isReused = packet.RawData[10];
|
|
if (isReused > 1)
|
|
return null;
|
|
|
|
return new NetConnectAcceptPacket(connectionId, connectionNumber, isReused == 1);
|
|
}
|
|
|
|
public static NetPacket Make(long connectId, byte connectNum, bool reusedPeer)
|
|
{
|
|
var packet = new NetPacket(PacketProperty.ConnectAccept, 0);
|
|
FastBitConverter.GetBytes(packet.RawData, 1, connectId);
|
|
packet.RawData[9] = connectNum;
|
|
packet.RawData[10] = (byte)(reusedPeer ? 1 : 0);
|
|
return packet;
|
|
}
|
|
}
|
|
}
|