2024-10-17 17:23:05 +03:00

79 lines
3.0 KiB
C#

using System.IO;
namespace kcp2k
{
// KCP Segment Definition
internal class Segment
{
internal uint conv; // conversation
internal uint cmd; // command, e.g. Kcp.CMD_ACK etc.
// fragment (sent as 1 byte).
// 0 if unfragmented, otherwise fragment numbers in reverse: N,..,32,1,0
// this way the first received segment tells us how many fragments there are.
internal uint frg;
internal uint wnd; // window size that the receive can currently receive
internal uint ts; // timestamp
internal uint sn; // sequence number
internal uint una;
internal uint resendts; // resend timestamp
internal int rto;
internal uint fastack;
internal uint xmit; // retransmit count
// we need an auto scaling byte[] with a WriteBytes function.
// MemoryStream does that perfectly, no need to reinvent the wheel.
// note: no need to pool it, because Segment is already pooled.
// -> default MTU as initial capacity to avoid most runtime resizing/allocations
//
// .data is only used for Encode(), which always fits it into a buffer.
// the buffer is always Kcp.buffer. Kcp ctor creates the buffer of size:
// (mtu + OVERHEAD) * 3 bytes.
// in other words, Encode only ever writes up to the above amount of bytes.
internal MemoryStream data = new MemoryStream(Kcp.MTU_DEF);
// ikcp_encode_seg
// encode a segment into buffer.
// buffer is always Kcp.buffer. Kcp ctor creates the buffer of size:
// (mtu + OVERHEAD) * 3 bytes.
// in other words, Encode only ever writes up to the above amount of bytes.
internal int Encode(byte[] ptr, int offset)
{
int previousPosition = offset;
offset += Utils.Encode32U(ptr, offset, conv);
offset += Utils.Encode8u(ptr, offset, (byte)cmd);
// IMPORTANT kcp encodes 'frg' as 1 byte.
// so we can only support up to 255 fragments.
// (which limits max message size to around 288 KB)
offset += Utils.Encode8u(ptr, offset, (byte)frg);
offset += Utils.Encode16U(ptr, offset, (ushort)wnd);
offset += Utils.Encode32U(ptr, offset, ts);
offset += Utils.Encode32U(ptr, offset, sn);
offset += Utils.Encode32U(ptr, offset, una);
offset += Utils.Encode32U(ptr, offset, (uint)data.Position);
int written = offset - previousPosition;
return written;
}
// reset to return a fresh segment to the pool
internal void Reset()
{
conv = 0;
cmd = 0;
frg = 0;
wnd = 0;
ts = 0;
sn = 0;
una = 0;
rto = 0;
xmit = 0;
resendts = 0;
fastack = 0;
// keep buffer for next pool usage, but reset length (= bytes written)
data.SetLength(0);
}
}
}