115 lines
4.8 KiB
C#
115 lines
4.8 KiB
C#
using System;
|
|
using System.Buffers.Binary;
|
|
|
|
namespace ShrinkNetwork
|
|
{
|
|
internal enum ShrinkKcpEnvelopeKind : byte
|
|
{
|
|
ConnectRequest = 1,
|
|
ConnectAccept = 2,
|
|
Disconnect = 3,
|
|
Data = 4
|
|
}
|
|
|
|
internal static class ShrinkKcpTransportProtocol
|
|
{
|
|
private const int KindSize = 1;
|
|
private const int ConversationSize = 4;
|
|
private const int NonceSize = 8;
|
|
|
|
public static byte[] CreateConnectRequest(long nonce, uint requestedConversationId)
|
|
{
|
|
var buffer = new byte[KindSize + NonceSize + ConversationSize];
|
|
buffer[0] = (byte)ShrinkKcpEnvelopeKind.ConnectRequest;
|
|
BinaryPrimitives.WriteInt64LittleEndian(buffer.AsSpan(1, NonceSize), nonce);
|
|
BinaryPrimitives.WriteUInt32LittleEndian(buffer.AsSpan(1 + NonceSize, ConversationSize), requestedConversationId);
|
|
return buffer;
|
|
}
|
|
|
|
public static bool TryReadConnectRequest(byte[] datagram, out long nonce, out uint requestedConversationId)
|
|
{
|
|
nonce = default;
|
|
requestedConversationId = default;
|
|
if (datagram == null || datagram.Length != KindSize + NonceSize + ConversationSize)
|
|
return false;
|
|
if (datagram[0] != (byte)ShrinkKcpEnvelopeKind.ConnectRequest)
|
|
return false;
|
|
|
|
nonce = BinaryPrimitives.ReadInt64LittleEndian(datagram.AsSpan(1, NonceSize));
|
|
requestedConversationId = BinaryPrimitives.ReadUInt32LittleEndian(datagram.AsSpan(1 + NonceSize, ConversationSize));
|
|
return true;
|
|
}
|
|
|
|
public static byte[] CreateConnectAccept(long nonce, uint conversationId)
|
|
{
|
|
var buffer = new byte[KindSize + NonceSize + ConversationSize];
|
|
buffer[0] = (byte)ShrinkKcpEnvelopeKind.ConnectAccept;
|
|
BinaryPrimitives.WriteInt64LittleEndian(buffer.AsSpan(1, NonceSize), nonce);
|
|
BinaryPrimitives.WriteUInt32LittleEndian(buffer.AsSpan(1 + NonceSize, ConversationSize), conversationId);
|
|
return buffer;
|
|
}
|
|
|
|
public static bool TryReadConnectAccept(byte[] datagram, out long nonce, out uint conversationId)
|
|
{
|
|
nonce = default;
|
|
conversationId = default;
|
|
if (datagram == null || datagram.Length != KindSize + NonceSize + ConversationSize)
|
|
return false;
|
|
if (datagram[0] != (byte)ShrinkKcpEnvelopeKind.ConnectAccept)
|
|
return false;
|
|
|
|
nonce = BinaryPrimitives.ReadInt64LittleEndian(datagram.AsSpan(1, NonceSize));
|
|
conversationId = BinaryPrimitives.ReadUInt32LittleEndian(datagram.AsSpan(1 + NonceSize, ConversationSize));
|
|
return true;
|
|
}
|
|
|
|
public static byte[] CreateDisconnect(uint conversationId)
|
|
{
|
|
var buffer = new byte[KindSize + ConversationSize];
|
|
buffer[0] = (byte)ShrinkKcpEnvelopeKind.Disconnect;
|
|
BinaryPrimitives.WriteUInt32LittleEndian(buffer.AsSpan(1, ConversationSize), conversationId);
|
|
return buffer;
|
|
}
|
|
|
|
public static bool TryReadDisconnect(byte[] datagram, out uint conversationId)
|
|
{
|
|
conversationId = default;
|
|
if (datagram == null || datagram.Length != KindSize + ConversationSize)
|
|
return false;
|
|
if (datagram[0] != (byte)ShrinkKcpEnvelopeKind.Disconnect)
|
|
return false;
|
|
|
|
conversationId = BinaryPrimitives.ReadUInt32LittleEndian(datagram.AsSpan(1, ConversationSize));
|
|
return true;
|
|
}
|
|
|
|
public static byte[] CreateDataPacket(uint conversationId, byte[] payload)
|
|
{
|
|
payload ??= Array.Empty<byte>();
|
|
|
|
var buffer = new byte[KindSize + ConversationSize + payload.Length];
|
|
buffer[0] = (byte)ShrinkKcpEnvelopeKind.Data;
|
|
BinaryPrimitives.WriteUInt32LittleEndian(buffer.AsSpan(1, ConversationSize), conversationId);
|
|
if (payload.Length > 0)
|
|
Buffer.BlockCopy(payload, 0, buffer, KindSize + ConversationSize, payload.Length);
|
|
return buffer;
|
|
}
|
|
|
|
public static bool TryReadDataPacket(byte[] datagram, out uint conversationId, out int payloadOffset, out int payloadLength)
|
|
{
|
|
conversationId = default;
|
|
payloadOffset = default;
|
|
payloadLength = default;
|
|
if (datagram == null || datagram.Length < KindSize + ConversationSize)
|
|
return false;
|
|
if (datagram[0] != (byte)ShrinkKcpEnvelopeKind.Data)
|
|
return false;
|
|
|
|
conversationId = BinaryPrimitives.ReadUInt32LittleEndian(datagram.AsSpan(1, ConversationSize));
|
|
payloadOffset = KindSize + ConversationSize;
|
|
payloadLength = datagram.Length - payloadOffset;
|
|
return payloadLength >= 0;
|
|
}
|
|
}
|
|
}
|