KcpServerConnection.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // server needs to store a separate KcpPeer for each connection.
  2. // as well as remoteEndPoint so we know where to send data to.
  3. using System;
  4. using System.Net;
  5. namespace kcp2k
  6. {
  7. public class KcpServerConnection : KcpPeer
  8. {
  9. public readonly EndPoint remoteEndPoint;
  10. // callbacks
  11. // even for errors, to allow liraries to show popups etc.
  12. // instead of logging directly.
  13. // (string instead of Exception for ease of use and to avoid user panic)
  14. //
  15. // events are readonly, set in constructor.
  16. // this ensures they are always initialized when used.
  17. // fixes https://github.com/MirrorNetworking/Mirror/issues/3337 and more
  18. protected readonly Action<KcpServerConnection> OnConnectedCallback;
  19. protected readonly Action<ArraySegment<byte>, KcpChannel> OnDataCallback;
  20. protected readonly Action OnDisconnectedCallback;
  21. protected readonly Action<ErrorCode, string> OnErrorCallback;
  22. protected readonly Action<ArraySegment<byte>> RawSendCallback;
  23. public KcpServerConnection(
  24. Action<KcpServerConnection> OnConnected,
  25. Action<ArraySegment<byte>, KcpChannel> OnData,
  26. Action OnDisconnected,
  27. Action<ErrorCode, string> OnError,
  28. Action<ArraySegment<byte>> OnRawSend,
  29. KcpConfig config,
  30. uint cookie,
  31. EndPoint remoteEndPoint)
  32. : base(config, cookie)
  33. {
  34. OnConnectedCallback = OnConnected;
  35. OnDataCallback = OnData;
  36. OnDisconnectedCallback = OnDisconnected;
  37. OnErrorCallback = OnError;
  38. RawSendCallback = OnRawSend;
  39. this.remoteEndPoint = remoteEndPoint;
  40. }
  41. // callbacks ///////////////////////////////////////////////////////////
  42. protected override void OnAuthenticated()
  43. {
  44. // once we receive the first client hello,
  45. // immediately reply with hello so the client knows the security cookie.
  46. SendHello();
  47. OnConnectedCallback(this);
  48. }
  49. protected override void OnData(ArraySegment<byte> message, KcpChannel channel) =>
  50. OnDataCallback(message, channel);
  51. protected override void OnDisconnected() =>
  52. OnDisconnectedCallback();
  53. protected override void OnError(ErrorCode error, string message) =>
  54. OnErrorCallback(error, message);
  55. protected override void RawSend(ArraySegment<byte> data) =>
  56. RawSendCallback(data);
  57. ////////////////////////////////////////////////////////////////////////
  58. // insert raw IO. usually from socket.Receive.
  59. // offset is useful for relays, where we may parse a header and then
  60. // feed the rest to kcp.
  61. public void RawInput(ArraySegment<byte> segment)
  62. {
  63. // ensure valid size: at least 1 byte for channel + 4 bytes for cookie
  64. if (segment.Count <= 5) return;
  65. // parse channel
  66. // byte channel = segment[0]; ArraySegment[i] isn't supported in some older Unity Mono versions
  67. byte channel = segment.Array[segment.Offset + 0];
  68. // all server->client messages include the server's security cookie.
  69. // all client->server messages except for the initial 'hello' include it too.
  70. // parse the cookie and make sure it matches (except for initial hello).
  71. Utils.Decode32U(segment.Array, segment.Offset + 1, out uint messageCookie);
  72. // compare cookie to protect against UDP spoofing.
  73. // messages won't have a cookie until after handshake.
  74. // so only compare if we are authenticated.
  75. // simply drop the message if the cookie doesn't match.
  76. if (state == KcpState.Authenticated)
  77. {
  78. if (messageCookie != cookie)
  79. {
  80. Log.Warning($"KcpServerConnection: dropped message with invalid cookie: {messageCookie} expected: {cookie} state: {state}");
  81. return;
  82. }
  83. }
  84. // parse message
  85. ArraySegment<byte> message = new ArraySegment<byte>(segment.Array, segment.Offset + 1+4, segment.Count - 1-4);
  86. switch (channel)
  87. {
  88. case (byte)KcpChannel.Reliable:
  89. {
  90. OnRawInputReliable(message);
  91. break;
  92. }
  93. case (byte)KcpChannel.Unreliable:
  94. {
  95. OnRawInputUnreliable(message);
  96. break;
  97. }
  98. default:
  99. {
  100. // invalid channel indicates random internet noise.
  101. // servers may receive random UDP data.
  102. // just ignore it, but log for easier debugging.
  103. Log.Warning($"KcpServerConnection: invalid channel header: {channel}, likely internet noise");
  104. break;
  105. }
  106. }
  107. }
  108. }
  109. }