615 lines
19 KiB
C#
615 lines
19 KiB
C#
using System;
|
|
using System.Threading;
|
|
using static ET.IKCP;
|
|
|
|
#pragma warning disable CS8601
|
|
#pragma warning disable CS8602
|
|
#pragma warning disable CS8625
|
|
|
|
// ReSharper disable IdentifierTypo
|
|
// ReSharper disable GrammarMistakeInComment
|
|
// ReSharper disable PossibleNullReferenceException
|
|
// ReSharper disable ConvertToAutoPropertyWithPrivateSetter
|
|
|
|
namespace ET
|
|
{
|
|
/// <summary>
|
|
/// Kcp
|
|
/// </summary>
|
|
public sealed unsafe partial class Kcp : IDisposable
|
|
{
|
|
/// <summary>
|
|
/// Kcp
|
|
/// </summary>
|
|
private IKCPCB* _kcp;
|
|
|
|
/// <summary>
|
|
/// Output function
|
|
/// </summary>
|
|
private KcpCallback _output;
|
|
|
|
/// <summary>
|
|
/// Disposed
|
|
/// </summary>
|
|
private int _disposed;
|
|
|
|
/// <summary>
|
|
/// Structure
|
|
/// </summary>
|
|
/// <param name="output">Output</param>
|
|
public Kcp(KcpCallback output) : this(0, output)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Structure
|
|
/// </summary>
|
|
/// <param name="conv">ConversationId</param>
|
|
/// <param name="output">Output</param>
|
|
public Kcp(uint conv, KcpCallback output)
|
|
{
|
|
_kcp = ikcp_create(conv);
|
|
_output = output;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set
|
|
/// </summary>
|
|
public bool IsSet => _kcp != null;
|
|
|
|
/// <summary>
|
|
/// Conversation id
|
|
/// </summary>
|
|
public uint ConversationId => _kcp->conv;
|
|
|
|
/// <summary>
|
|
/// Maximum transmission unit
|
|
/// </summary>
|
|
public uint MaximumTransmissionUnit => _kcp->mtu;
|
|
|
|
/// <summary>
|
|
/// Maximum segment size
|
|
/// </summary>
|
|
public uint MaximumSegmentSize => _kcp->mss;
|
|
|
|
/// <summary>
|
|
/// Connection state
|
|
/// </summary>
|
|
public int State => _kcp->state;
|
|
|
|
/// <summary>
|
|
/// The sequence number of the first unacknowledged packet
|
|
/// </summary>
|
|
public uint SendUna => _kcp->snd_una;
|
|
|
|
/// <summary>
|
|
/// The sequence number for the next packet to be sent
|
|
/// </summary>
|
|
public uint SendNext => _kcp->snd_nxt;
|
|
|
|
/// <summary>
|
|
/// The sequence number for the next packet expected to be received
|
|
/// </summary>
|
|
public uint ReceiveNext => _kcp->rcv_nxt;
|
|
|
|
/// <summary>
|
|
/// Slow start threshold for congestion control
|
|
/// </summary>
|
|
public uint SlowStartThreshold => _kcp->ssthresh;
|
|
|
|
/// <summary>
|
|
/// Round-trip time variance
|
|
/// </summary>
|
|
public int RxRttval => _kcp->rx_rttval;
|
|
|
|
/// <summary>
|
|
/// Smoothed round-trip time
|
|
/// </summary>
|
|
public int RxSrtt => _kcp->rx_srtt;
|
|
|
|
/// <summary>
|
|
/// Retransmission timeout
|
|
/// </summary>
|
|
public int RxRto => _kcp->rx_rto;
|
|
|
|
/// <summary>
|
|
/// Minimum retransmission timeout
|
|
/// </summary>
|
|
public int RxMinrto => _kcp->rx_minrto;
|
|
|
|
/// <summary>
|
|
/// Send window size
|
|
/// </summary>
|
|
public uint SendWindowSize => _kcp->snd_wnd;
|
|
|
|
/// <summary>
|
|
/// Receive window size
|
|
/// </summary>
|
|
public uint ReceiveWindowSize => _kcp->rcv_wnd;
|
|
|
|
/// <summary>
|
|
/// Remote window size
|
|
/// </summary>
|
|
public uint RemoteWindowSize => _kcp->rmt_wnd;
|
|
|
|
/// <summary>
|
|
/// Congestion window size
|
|
/// </summary>
|
|
public uint CongestionWindowSize => _kcp->cwnd;
|
|
|
|
/// <summary>
|
|
/// Probe variable for fast recovery
|
|
/// </summary>
|
|
public uint Probe => _kcp->probe;
|
|
|
|
/// <summary>
|
|
/// Current timestamp
|
|
/// </summary>
|
|
public uint Current => _kcp->current;
|
|
|
|
/// <summary>
|
|
/// Flush interval
|
|
/// </summary>
|
|
public uint Interval => _kcp->interval;
|
|
|
|
/// <summary>
|
|
/// Timestamp for the next flush
|
|
/// </summary>
|
|
public uint TimestampFlush => _kcp->ts_flush;
|
|
|
|
/// <summary>
|
|
/// Number of retransmissions
|
|
/// </summary>
|
|
public uint Transmissions => _kcp->xmit;
|
|
|
|
/// <summary>
|
|
/// Number of packets in the receive buffer
|
|
/// </summary>
|
|
public uint ReceiveBufferCount => _kcp->nrcv_buf;
|
|
|
|
/// <summary>
|
|
/// Number of packets in the receive queue
|
|
/// </summary>
|
|
public uint ReceiveQueueCount => _kcp->nrcv_que;
|
|
|
|
/// <summary>
|
|
/// Number of packets wait to receive
|
|
/// </summary>
|
|
public uint WaitReceiveCount => _kcp->nrcv_buf + _kcp->nrcv_que;
|
|
|
|
/// <summary>
|
|
/// Number of packets in the send buffer
|
|
/// </summary>
|
|
public uint SendBufferCount => _kcp->nsnd_buf;
|
|
|
|
/// <summary>
|
|
/// Number of packets in the send queue
|
|
/// </summary>
|
|
public uint SendQueueCount => _kcp->nsnd_que;
|
|
|
|
/// <summary>
|
|
/// Number of packets wait to send
|
|
/// </summary>
|
|
public uint WaitSendCount => _kcp->nsnd_buf + _kcp->nsnd_que;
|
|
|
|
/// <summary>
|
|
/// Whether Nagle's algorithm is disabled
|
|
/// </summary>
|
|
public uint NoDelay => _kcp->nodelay;
|
|
|
|
/// <summary>
|
|
/// Whether the KCP connection has been updated
|
|
/// </summary>
|
|
public uint Updated => _kcp->updated;
|
|
|
|
/// <summary>
|
|
/// Timestamp for the next probe
|
|
/// </summary>
|
|
public uint TimestampProbe => _kcp->ts_probe;
|
|
|
|
/// <summary>
|
|
/// Probe wait time
|
|
/// </summary>
|
|
public uint ProbeWait => _kcp->probe_wait;
|
|
|
|
/// <summary>
|
|
/// Incremental increase
|
|
/// </summary>
|
|
public uint Increment => _kcp->incr;
|
|
|
|
/// <summary>
|
|
/// Pointer to the acknowledge list
|
|
/// </summary>
|
|
public uint* AckList => _kcp->acklist;
|
|
|
|
/// <summary>
|
|
/// Count of acknowledges
|
|
/// </summary>
|
|
public uint AckCount => _kcp->ackcount;
|
|
|
|
/// <summary>
|
|
/// Number of acknowledge blocks
|
|
/// </summary>
|
|
public uint AckBlock => _kcp->ackblock;
|
|
|
|
/// <summary>
|
|
/// Fast resend trigger count
|
|
/// </summary>
|
|
public int FastResend => _kcp->fastresend;
|
|
|
|
/// <summary>
|
|
/// Fast resend limit
|
|
/// </summary>
|
|
public int FastResendLimit => _kcp->fastlimit;
|
|
|
|
/// <summary>
|
|
/// Whether congestion control is disabled
|
|
/// </summary>
|
|
public int NoCongestionWindow => _kcp->nocwnd;
|
|
|
|
/// <summary>
|
|
/// Whether stream mode is enabled
|
|
/// </summary>
|
|
public int StreamMode => _kcp->stream;
|
|
|
|
/// <summary>
|
|
/// Output function pointer
|
|
/// </summary>
|
|
public KcpCallback Output => _output;
|
|
|
|
/// <summary>
|
|
/// Dispose
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
if (Interlocked.CompareExchange(ref _disposed, 1, 0) != 0)
|
|
return;
|
|
ikcp_release(_kcp);
|
|
_kcp = null;
|
|
_output = null;
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set output
|
|
/// </summary>
|
|
/// <param name="output">Output</param>
|
|
public void SetOutput(KcpCallback output) => _output = output;
|
|
|
|
/// <summary>
|
|
/// Destructure
|
|
/// </summary>
|
|
~Kcp() => Dispose();
|
|
|
|
/// <summary>
|
|
/// Send
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <returns>Sent bytes</returns>
|
|
public int Send(byte[] buffer)
|
|
{
|
|
fixed (byte* src = &buffer[0])
|
|
return ikcp_send(_kcp, src, buffer.Length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <param name="length">Length</param>
|
|
/// <returns>Sent bytes</returns>
|
|
public int Send(byte[] buffer, int length)
|
|
{
|
|
fixed (byte* src = &buffer[0])
|
|
return ikcp_send(_kcp, src, length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <param name="offset">Offset</param>
|
|
/// <param name="length">Length</param>
|
|
/// <returns>Sent bytes</returns>
|
|
public int Send(byte[] buffer, int offset, int length)
|
|
{
|
|
fixed (byte* src = &buffer[offset])
|
|
return ikcp_send(_kcp, src, length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <returns>Sent bytes</returns>
|
|
public int Send(ReadOnlySpan<byte> buffer)
|
|
{
|
|
fixed (byte* src = &buffer[0])
|
|
return ikcp_send(_kcp, src, buffer.Length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <returns>Sent bytes</returns>
|
|
public int Send(ReadOnlyMemory<byte> buffer)
|
|
{
|
|
fixed (byte* src = &buffer.Span[0])
|
|
return ikcp_send(_kcp, src, buffer.Length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <returns>Sent bytes</returns>
|
|
public int Send(ArraySegment<byte> buffer)
|
|
{
|
|
fixed (byte* src = &buffer.Array[buffer.Offset])
|
|
return ikcp_send(_kcp, src, buffer.Count);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <param name="length">Length</param>
|
|
/// <returns>Sent bytes</returns>
|
|
public int Send(byte* buffer, int length) => ikcp_send(_kcp, buffer, length);
|
|
|
|
/// <summary>
|
|
/// Send
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <param name="offset">Offset</param>
|
|
/// <param name="length">Length</param>
|
|
/// <returns>Sent bytes</returns>
|
|
public int Send(byte* buffer, int offset, int length) => ikcp_send(_kcp, buffer + offset, length);
|
|
|
|
/// <summary>
|
|
/// Input
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <returns>Input bytes</returns>
|
|
public int Input(byte[] buffer)
|
|
{
|
|
fixed (byte* src = &buffer[0])
|
|
return ikcp_input(_kcp, src, buffer.Length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Input
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <param name="length">Length</param>
|
|
/// <returns>Input bytes</returns>
|
|
public int Input(byte[] buffer, int length)
|
|
{
|
|
fixed (byte* src = &buffer[0])
|
|
return ikcp_input(_kcp, src, length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Input
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <param name="offset">Offset</param>
|
|
/// <param name="length">Length</param>
|
|
/// <returns>Input bytes</returns>
|
|
public int Input(byte[] buffer, int offset, int length)
|
|
{
|
|
fixed (byte* src = &buffer[offset])
|
|
return ikcp_input(_kcp, src, length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Input
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <returns>Input bytes</returns>
|
|
public int Input(ReadOnlySpan<byte> buffer)
|
|
{
|
|
fixed (byte* src = &buffer[0])
|
|
return ikcp_input(_kcp, src, buffer.Length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Input
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <returns>Input bytes</returns>
|
|
public int Input(ReadOnlyMemory<byte> buffer)
|
|
{
|
|
fixed (byte* src = &buffer.Span[0])
|
|
return ikcp_input(_kcp, src, buffer.Length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Input
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <returns>Input bytes</returns>
|
|
public int Input(ArraySegment<byte> buffer)
|
|
{
|
|
fixed (byte* src = &buffer.Array[buffer.Offset])
|
|
return ikcp_input(_kcp, src, buffer.Count);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Input
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <param name="length">Length</param>
|
|
/// <returns>Input bytes</returns>
|
|
public int Input(byte* buffer, int length) => ikcp_input(_kcp, buffer, length);
|
|
|
|
/// <summary>
|
|
/// Input
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <param name="offset">Offset</param>
|
|
/// <param name="length">Length</param>
|
|
/// <returns>Input bytes</returns>
|
|
public int Input(byte* buffer, int offset, int length) => ikcp_input(_kcp, buffer + offset, length);
|
|
|
|
/// <summary>
|
|
/// Peek size
|
|
/// </summary>
|
|
/// <returns>Peeked size</returns>
|
|
public int PeekSize() => ikcp_peeksize(_kcp);
|
|
|
|
/// <summary>
|
|
/// Receive
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <returns>Received bytes</returns>
|
|
public int Receive(byte[] buffer)
|
|
{
|
|
fixed (byte* dest = &buffer[0])
|
|
return ikcp_recv(_kcp, dest, buffer.Length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Receive
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <param name="length">Length</param>
|
|
/// <returns>Received bytes</returns>
|
|
public int Receive(byte[] buffer, int length)
|
|
{
|
|
fixed (byte* dest = &buffer[0])
|
|
return ikcp_recv(_kcp, dest, length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Receive
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <param name="offset">Offset</param>
|
|
/// <param name="length">Length</param>
|
|
/// <returns>Received bytes</returns>
|
|
public int Receive(byte[] buffer, int offset, int length)
|
|
{
|
|
fixed (byte* dest = &buffer[offset])
|
|
return ikcp_recv(_kcp, dest, length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Receive
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <returns>Received bytes</returns>
|
|
public int Receive(Span<byte> buffer)
|
|
{
|
|
fixed (byte* dest = &buffer[0])
|
|
return ikcp_recv(_kcp, dest, buffer.Length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Receive
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <returns>Received bytes</returns>
|
|
public int Receive(Memory<byte> buffer)
|
|
{
|
|
fixed (byte* dest = &buffer.Span[0])
|
|
return ikcp_recv(_kcp, dest, buffer.Length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Receive
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <returns>Received bytes</returns>
|
|
public int Receive(ArraySegment<byte> buffer)
|
|
{
|
|
fixed (byte* dest = &buffer.Array[buffer.Offset])
|
|
return ikcp_recv(_kcp, dest, buffer.Count);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Receive
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <param name="length">Length</param>
|
|
/// <returns>Received bytes</returns>
|
|
public int Receive(byte* buffer, int length) => ikcp_recv(_kcp, buffer, length);
|
|
|
|
/// <summary>
|
|
/// Receive
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer</param>
|
|
/// <param name="offset">Offset</param>
|
|
/// <param name="length">Length</param>
|
|
/// <returns>Received bytes</returns>
|
|
public int Receive(byte* buffer, int offset, int length) => ikcp_recv(_kcp, buffer + offset, length);
|
|
|
|
/// <summary>
|
|
/// Update
|
|
/// </summary>
|
|
/// <param name="current">Timestamp</param>
|
|
/// <param name="bytes">Buffer</param>
|
|
public void Update(uint current, byte[] bytes) => ikcp_update(this._kcp, current, this._output, bytes);
|
|
|
|
/// <summary>
|
|
/// Check
|
|
/// </summary>
|
|
/// <param name="current">Timestamp</param>
|
|
/// <returns>Next flush timestamp</returns>
|
|
public uint Check(uint current) => ikcp_check(_kcp, current);
|
|
|
|
/// <summary>
|
|
/// Flush
|
|
/// </summary>
|
|
/// <param name="bytes">Buffer</param>
|
|
public void Flush(byte[] bytes) => ikcp_flush(this._kcp, this._output, bytes);
|
|
|
|
/// <summary>
|
|
/// Set maximum transmission unit
|
|
/// </summary>
|
|
/// <param name="mtu">Maximum transmission unit</param>
|
|
/// <returns>Set</returns>
|
|
public int SetMtu(int mtu) => ikcp_setmtu(_kcp, mtu);
|
|
|
|
/// <summary>
|
|
/// Set flush interval
|
|
/// </summary>
|
|
/// <param name="interval">Flush interval</param>
|
|
public void SetInterval(int interval) => ikcp_interval(_kcp, interval);
|
|
|
|
/// <summary>
|
|
/// Set no delay
|
|
/// </summary>
|
|
/// <param name="nodelay">Whether Nagle's algorithm is disabled</param>
|
|
/// <param name="interval">Flush interval</param>
|
|
/// <param name="resend">Fast resend trigger count</param>
|
|
/// <param name="nc">No congestion window</param>
|
|
public void SetNoDelay(int nodelay, int interval, int resend, int nc) => ikcp_nodelay(_kcp, nodelay, interval, resend, nc);
|
|
|
|
/// <summary>
|
|
/// Set window size
|
|
/// </summary>
|
|
/// <param name="sndwnd">Send window size</param>
|
|
/// <param name="rcvwnd">Receive window size</param>
|
|
public void SetWindowSize(int sndwnd, int rcvwnd) => ikcp_wndsize(_kcp, sndwnd, rcvwnd);
|
|
|
|
/// <summary>
|
|
/// Set fast resend limit
|
|
/// </summary>
|
|
/// <param name="fastlimit">Fast resend limit</param>
|
|
public void SetFastResendLimit(int fastlimit) => ikcp_fastresendlimit(_kcp, fastlimit);
|
|
|
|
/// <summary>
|
|
/// Set whether stream mode is enabled
|
|
/// </summary>
|
|
/// <param name="stream">Whether stream mode is enabled</param>
|
|
public void SetStreamMode(int stream) => ikcp_streammode(_kcp, stream);
|
|
|
|
/// <summary>
|
|
/// Set minimum retransmission timeout
|
|
/// </summary>
|
|
/// <param name="minrto">Minimum retransmission timeout</param>
|
|
public void SetMinrto(int minrto) => ikcp_minrto(_kcp, minrto);
|
|
}
|
|
} |