mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 11:00:32 +00:00
fix: kcp2k V1.8: fixes empty message sending/receiving undefined behaviour and fixes IPv6 errors on Nintendo Switch
This commit is contained in:
parent
4cc9f2ea6a
commit
66b64f010f
@ -53,6 +53,15 @@ public abstract class KcpConnection
|
|||||||
// may not be a bug in original kcp. but since it uses the define, we
|
// may not be a bug in original kcp. but since it uses the define, we
|
||||||
// can use that here too.
|
// can use that here too.
|
||||||
// -> we add 1 byte KcpHeader enum to each message, so -1
|
// -> we add 1 byte KcpHeader enum to each message, so -1
|
||||||
|
//
|
||||||
|
// IMPORTANT: max message is MTU * WND_RCV, in other words it completely
|
||||||
|
// fills the receive window! due to head of line blocking,
|
||||||
|
// all other messages have to wait while a maxed size message
|
||||||
|
// is being delivered.
|
||||||
|
// => in other words, DO NOT use max size all the time like
|
||||||
|
// for batching.
|
||||||
|
// => sending UNRELIABLE max message size most of the time is
|
||||||
|
// best for performance (use that one for batching!)
|
||||||
public const int ReliableMaxMessageSize = (Kcp.MTU_DEF - Kcp.OVERHEAD - CHANNEL_HEADER_SIZE) * (Kcp.WND_RCV - 1) - 1;
|
public const int ReliableMaxMessageSize = (Kcp.MTU_DEF - Kcp.OVERHEAD - CHANNEL_HEADER_SIZE) * (Kcp.WND_RCV - 1) - 1;
|
||||||
|
|
||||||
// unreliable max message size is simply MTU - channel header size
|
// unreliable max message size is simply MTU - channel header size
|
||||||
@ -185,7 +194,7 @@ void HandleChoked()
|
|||||||
$"* Try to Enable NoDelay, decrease INTERVAL, disable Congestion Window (= enable NOCWND!), increase SEND/RECV WINDOW or compress data.\n" +
|
$"* Try to Enable NoDelay, decrease INTERVAL, disable Congestion Window (= enable NOCWND!), increase SEND/RECV WINDOW or compress data.\n" +
|
||||||
$"* Or perhaps the network is simply too slow on our end, or on the other end.\n");
|
$"* Or perhaps the network is simply too slow on our end, or on the other end.\n");
|
||||||
|
|
||||||
// let's clear all pending sends before disconnecting with 'Bye'.
|
// let's clear all pending sends before disconnting with 'Bye'.
|
||||||
// otherwise a single Flush in Disconnect() won't be enough to
|
// otherwise a single Flush in Disconnect() won't be enough to
|
||||||
// flush thousands of messages to finally deliver 'Bye'.
|
// flush thousands of messages to finally deliver 'Bye'.
|
||||||
// this is just faster and more robust.
|
// this is just faster and more robust.
|
||||||
@ -315,8 +324,18 @@ void TickAuthenticated(uint time)
|
|||||||
}
|
}
|
||||||
case KcpHeader.Data:
|
case KcpHeader.Data:
|
||||||
{
|
{
|
||||||
//Log.Warning($"Kcp recv msg: {BitConverter.ToString(message.Array, message.Offset, message.Count)}");
|
// call OnData IF the message contained actual data
|
||||||
OnData?.Invoke(message);
|
if (message.Count > 0)
|
||||||
|
{
|
||||||
|
//Log.Warning($"Kcp recv msg: {BitConverter.ToString(message.Array, message.Offset, message.Count)}");
|
||||||
|
OnData?.Invoke(message);
|
||||||
|
}
|
||||||
|
// empty data = attacker, or something went wrong
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Warning("KCP: received empty Data message while Authenticated. Disconnecting the connection.");
|
||||||
|
Disconnect();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case KcpHeader.Ping:
|
case KcpHeader.Ping:
|
||||||
@ -521,6 +540,17 @@ public void SendHandshake()
|
|||||||
|
|
||||||
public void SendData(ArraySegment<byte> data, KcpChannel channel)
|
public void SendData(ArraySegment<byte> data, KcpChannel channel)
|
||||||
{
|
{
|
||||||
|
// sending empty segments is not allowed.
|
||||||
|
// nobody should ever try to send empty data.
|
||||||
|
// it means that something went wrong, e.g. in Mirror/DOTSNET.
|
||||||
|
// let's make it obvious so it's easy to debug.
|
||||||
|
if (data.Count == 0)
|
||||||
|
{
|
||||||
|
Log.Warning("KcpConnection: tried sending empty message. This should never happen. Disconnecting.");
|
||||||
|
Disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (channel)
|
switch (channel)
|
||||||
{
|
{
|
||||||
case KcpChannel.Reliable:
|
case KcpChannel.Reliable:
|
||||||
@ -539,9 +569,7 @@ public void SendData(ArraySegment<byte> data, KcpChannel channel)
|
|||||||
// disconnect info needs to be delivered, so it goes over reliable
|
// disconnect info needs to be delivered, so it goes over reliable
|
||||||
void SendDisconnect() => SendReliable(KcpHeader.Disconnect, default);
|
void SendDisconnect() => SendReliable(KcpHeader.Disconnect, default);
|
||||||
|
|
||||||
protected virtual void Dispose()
|
protected virtual void Dispose() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// disconnect this connection
|
// disconnect this connection
|
||||||
public void Disconnect()
|
public void Disconnect()
|
||||||
|
@ -39,7 +39,12 @@ public class KcpServer
|
|||||||
|
|
||||||
// state
|
// state
|
||||||
Socket socket;
|
Socket socket;
|
||||||
|
#if UNITY_SWITCH
|
||||||
|
// switch does not support ipv6
|
||||||
|
EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0);
|
||||||
|
#else
|
||||||
EndPoint newClientEP = new IPEndPoint(IPAddress.IPv6Any, 0);
|
EndPoint newClientEP = new IPEndPoint(IPAddress.IPv6Any, 0);
|
||||||
|
#endif
|
||||||
// IMPORTANT: raw receive buffer always needs to be of 'MTU' size, even
|
// IMPORTANT: raw receive buffer always needs to be of 'MTU' size, even
|
||||||
// if MaxMessageSize is larger. kcp always sends in MTU
|
// if MaxMessageSize is larger. kcp always sends in MTU
|
||||||
// segments and having a buffer smaller than MTU would
|
// segments and having a buffer smaller than MTU would
|
||||||
@ -82,9 +87,15 @@ public void Start(ushort port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// listen
|
// listen
|
||||||
|
#if UNITY_SWITCH
|
||||||
|
// Switch does not support ipv6
|
||||||
|
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||||
|
socket.Bind(new IPEndPoint(IPAddress.Any, port));
|
||||||
|
#else
|
||||||
socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
|
socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
|
||||||
socket.DualMode = true;
|
socket.DualMode = true;
|
||||||
socket.Bind(new IPEndPoint(IPAddress.IPv6Any, port));
|
socket.Bind(new IPEndPoint(IPAddress.IPv6Any, port));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Send(int connectionId, ArraySegment<byte> segment, KcpChannel channel)
|
public void Send(int connectionId, ArraySegment<byte> segment, KcpChannel channel)
|
||||||
|
Loading…
Reference in New Issue
Block a user