diff --git a/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs b/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs index fd2673b44..dd3c2d319 100644 --- a/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs +++ b/Assets/Mirror/Runtime/Transport/KCP/MirrorTransport/KcpTransport.cs @@ -162,35 +162,14 @@ public override void ClientSend(ArraySegment segment, int channelId) // process incoming in early update public override void ClientEarlyUpdate() { - // scene change messages disable transports to stop them from - // processing while changing the scene. - // -> we need to check enabled here - // -> and in kcp's internal loops, see Awake() OnCheckEnabled setup! + // only process messages while transport is enabled. + // scene change messsages disable it to stop processing. // (see also: https://github.com/vis2k/Mirror/pull/379) if (enabled) client.TickIncoming(); } // process outgoing in late update public override void ClientLateUpdate() => client.TickOutgoing(); - // scene change message will disable transports. - // kcp processes messages in an internal loop which should be - // stopped immediately after scene change (= after disabled) - // => kcp has tests to guaranteed that calling .Pause() during the - // receive loop stops the receive loop immediately, not after. - void OnEnable() - { - // unpause when enabled again - client?.Unpause(); - server?.Unpause(); - } - - void OnDisable() - { - // pause immediately when not enabled anymore - client?.Pause(); - server?.Pause(); - } - // server public override Uri ServerUri() { @@ -211,10 +190,8 @@ public override void ServerSend(int connectionId, ArraySegment segment, in public override void ServerStop() => server.Stop(); public override void ServerEarlyUpdate() { - // scene change messages disable transports to stop them from - // processing while changing the scene. - // -> we need to check enabled here - // -> and in kcp's internal loops, see Awake() OnCheckEnabled setup! + // only process messages while transport is enabled. + // scene change messsages disable it to stop processing. // (see also: https://github.com/vis2k/Mirror/pull/379) if (enabled) server.TickIncoming(); } diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/VERSION b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/VERSION index 9dd33a21a..6ba02c111 100755 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/VERSION +++ b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/VERSION @@ -1,3 +1,8 @@ +V1.16 [2022-01-06] +- fix: SendUnreliable respects ArraySegment.Offset +- fix: potential bug with negative length (see PR #2) +- breaking: removed pause handling because it's not necessary for Mirror anymore + V1.15 [2021-12-11] - feature: feature: MaxRetransmits aka dead_link now configurable - dead_link disconnect message improved to show exact retransmit count diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs index f77694a24..1dcda6b3f 100644 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs +++ b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClient.cs @@ -111,10 +111,5 @@ public void Tick() TickIncoming(); TickOutgoing(); } - - // pause/unpause to safely support mirror scene handling and to - // immediately pause the receive while loop if needed. - public void Pause() => connection?.Pause(); - public void Unpause() => connection?.Unpause(); } } diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClientConnection.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClientConnection.cs index f8f4feee3..90d6d26b0 100644 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClientConnection.cs +++ b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpClientConnection.cs @@ -17,6 +17,7 @@ public static bool ResolveHostname(string hostname, out IPAddress[] addresses) { try { + // NOTE: dns lookup is blocking. this can take a second. addresses = Dns.GetHostAddresses(hostname); return addresses.Length >= 1; } diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs index 3c84bcf24..8abbc2eef 100644 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs +++ b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpConnection.cs @@ -20,12 +20,6 @@ public abstract class KcpConnection public Action, KcpChannel> OnData; public Action OnDisconnected; - // Mirror needs a way to stop the kcp message processing while loop - // immediately after a scene change message. Mirror can't process any - // other messages during a scene change. - // (could be useful for others too) - bool paused; - // If we don't receive anything these many milliseconds // then consider us disconnected public const int DEFAULT_TIMEOUT = 10000; @@ -315,19 +309,7 @@ void TickIncoming_Authenticated(uint time) HandleChoked(); // process all received messages - // - // Mirror scene changing requires transports to immediately stop - // processing any more messages after a scene message was - // received. and since we are in a while loop here, we need this - // extra check. - // - // note while that this is mainly for Mirror, but might be - // useful in other applications too. - // - // note that we check it BEFORE ever calling ReceiveNext. otherwise - // we would silently eat the received message and never process it. - while (!paused && - ReceiveNextReliable(out KcpHeader header, out ArraySegment message)) + while (ReceiveNextReliable(out KcpHeader header, out ArraySegment message)) { // message type FSM. no default so we never miss a case. switch (header) @@ -499,15 +481,8 @@ public void RawInput(byte[] buffer, int msgLength) // the current state allows it. if (state == KcpState.Authenticated) { - // only process messages while not paused for Mirror - // scene switching etc. - // -> if an unreliable message comes in while - // paused, simply drop it. it's unreliable! - if (!paused) - { - ArraySegment message = new ArraySegment(buffer, 1, msgLength - 1); - OnData?.Invoke(message, KcpChannel.Unreliable); - } + ArraySegment message = new ArraySegment(buffer, 1, msgLength - 1); + OnData?.Invoke(message, KcpChannel.Unreliable); // set last receive time to avoid timeout. // -> we do this in ANY case even if not enabled. @@ -578,7 +553,7 @@ void SendUnreliable(ArraySegment message) { // copy channel header, data into raw send buffer, then send rawSendBuffer[0] = (byte)KcpChannel.Unreliable; - Buffer.BlockCopy(message.Array, 0, rawSendBuffer, 1, message.Count); + Buffer.BlockCopy(message.Array, message.Offset, rawSendBuffer, 1, message.Count); RawSend(rawSendBuffer, message.Count + 1); } // otherwise content is larger than MaxMessageSize. let user know! @@ -668,24 +643,5 @@ public void Disconnect() // get remote endpoint public EndPoint GetRemoteEndPoint() => remoteEndPoint; - - // pause/unpause to safely support mirror scene handling and to - // immediately pause the receive while loop if needed. - public void Pause() => paused = true; - public void Unpause() - { - // unpause - paused = false; - - // reset the timeout. - // we have likely been paused for > timeout seconds, but that - // doesn't mean we should disconnect. for example, Mirror pauses - // kcp during scene changes which could easily take > 10s timeout: - // see also: https://github.com/vis2k/kcp2k/issues/8 - // => Unpause completely resets the timeout instead of restoring the - // time difference when we started pausing. it's more simple and - // it's a good idea to start counting from 0 after we unpaused! - lastReceiveTime = (uint)refTime.ElapsedMilliseconds; - } } } diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServer.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServer.cs index 14b9f45db..5ba9150c1 100644 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServer.cs +++ b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/highlevel/KcpServer.cs @@ -323,19 +323,5 @@ public void Stop() socket?.Close(); socket = null; } - - // pause/unpause to safely support mirror scene handling and to - // immediately pause the receive while loop if needed. - public void Pause() - { - foreach (KcpServerConnection connection in connections.Values) - connection.Pause(); - } - - public void Unpause() - { - foreach (KcpServerConnection connection in connections.Values) - connection.Unpause(); - } } } diff --git a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Kcp.cs b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Kcp.cs index d5174c155..dff49e18e 100755 --- a/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Kcp.cs +++ b/Assets/Mirror/Runtime/Transport/KCP/kcp2k/kcp/Kcp.cs @@ -27,7 +27,7 @@ public class Kcp public const int INTERVAL = 100; public const int OVERHEAD = 24; public const int FRG_MAX = byte.MaxValue; // kcp encodes 'frg' as byte. so we can only ever send up to 255 fragments. - public const int DEADLINK = 20; // default maximum amount of 'xmit' retransmissions until a message is considered lost + public const int DEADLINK = 20; // default maximum amount of 'xmit' retransmissions until a segment is considered lost public const int THRESH_INIT = 2; public const int THRESH_MIN = 2; public const int PROBE_INIT = 7000; // 7 secs to probe window size @@ -65,7 +65,7 @@ internal struct AckItem internal bool updated; internal uint ts_probe; // timestamp probe internal uint probe_wait; - internal uint dead_link; // maximum amount of 'xmit' retransmissions until a message is considered lost + internal uint dead_link; // maximum amount of 'xmit' retransmissions until a segment is considered lost internal uint incr; internal uint current; // current time (milliseconds). set by Update. @@ -535,7 +535,8 @@ public int Input(byte[] data, int offset, int size) size -= OVERHEAD; // enough remaining to read 'len' bytes of the actual payload? - if (size < len || len < 0) return -2; + // note: original kcp casts uint len to int for <0 check. + if (size < len || (int)len < 0) return -2; if (cmd != CMD_PUSH && cmd != CMD_ACK && cmd != CMD_WASK && cmd != CMD_WINS)