From d162ce80aa9be3b51aa102aec4ca9f009469a061 Mon Sep 17 00:00:00 2001 From: Spirtix Date: Sat, 9 Sep 2023 16:12:53 +0200 Subject: [PATCH] packet buffering and fixes --- .../SetPositionVariablesHandler.cs | 14 +++-- .../SetUserVariablesHandler.cs | 6 +-- src/Core/Client.cs | 26 ++++----- src/Core/Room.cs | 6 ++- src/Data/NetworkData.cs | 6 +++ src/Data/NetworkPacket.cs | 6 ++- src/Data/SocketBuffer.cs | 54 +++++++++++++++++++ src/Server.cs | 3 +- 8 files changed, 90 insertions(+), 31 deletions(-) create mode 100644 src/Data/SocketBuffer.cs diff --git a/src/CommandHandlers/SetPositionVariablesHandler.cs b/src/CommandHandlers/SetPositionVariablesHandler.cs index 3f90672..cbc3d50 100644 --- a/src/CommandHandlers/SetPositionVariablesHandler.cs +++ b/src/CommandHandlers/SetPositionVariablesHandler.cs @@ -9,6 +9,12 @@ class SetPositionVariablesHandler : ICommandHandler { Client client; NetworkObject spvData; public void Handle(Client client, NetworkObject receivedObject) { + if (client.Room == null) { + Console.WriteLine($"SPV Missing Room IID: {client.ClientID}"); + client.Send(NetworkObject.WrapObject(0, 1006, new NetworkObject()).Serialize()); + client.SheduleDisconnect(); + return; + } this.client = client; spvData = receivedObject; UpdatePositionVariables(); @@ -52,11 +58,9 @@ class SetPositionVariablesHandler : ICommandHandler { NetworkPacket packet = NetworkObject.WrapObject(1, 13, cmd).Serialize(); - lock (client.Room.roomLock) { - foreach (var roomClient in client.Room.Clients) { - if (roomClient != client) - roomClient.Send(packet); - } + foreach (var roomClient in client.Room.Clients) { + if (roomClient != client) + roomClient.Send(packet); } } } diff --git a/src/CommandHandlers/SetUserVariablesHandler.cs b/src/CommandHandlers/SetUserVariablesHandler.cs index 3a7036c..3a858f0 100644 --- a/src/CommandHandlers/SetUserVariablesHandler.cs +++ b/src/CommandHandlers/SetUserVariablesHandler.cs @@ -81,10 +81,8 @@ class SetUserVariablesHandler : ICommandHandler { data.Add("vl", vl); NetworkPacket packet = NetworkObject.WrapObject(0, 12, data).Serialize(); - lock (client.Room.roomLock) { - foreach (var roomClient in client.Room.Clients) - roomClient.Send(packet); - } + foreach (var roomClient in client.Room.Clients) + roomClient.Send(packet); NetworkObject cmd = new(); cmd.Add("c", "SUV"); diff --git a/src/Core/Client.cs b/src/Core/Client.cs index 7018cf5..08e09ec 100644 --- a/src/Core/Client.cs +++ b/src/Core/Client.cs @@ -10,12 +10,10 @@ public class Client { public int ClientID { get; private set; } public PlayerData PlayerData { get; set; } = new(); public Room Room { get; set; } - public object ClientLock = new(); private readonly Socket socket; - private NetworkData? lastData; - private NetworkPacket? incompleteData; - private bool hasIncompletePakcet = false; + SocketBuffer socketBuffer = new(); + private volatile bool scheduledDisconnect = false; public Client(Socket clientSocket) { socket = clientSocket; @@ -29,21 +27,11 @@ public class Client { int len = await socket.ReceiveAsync(buffer, SocketFlags.None); if (len == 0) throw new SocketException(); - lastData = new NetworkData(buffer); + socketBuffer.Write(buffer, len); } public bool TryGetNextPacket(out NetworkPacket packet) { - packet = new(); - if (hasIncompletePakcet) { - // TODO - } - byte header = lastData!.ReadByte(); - if (header != 0x80 && header != 0xa0) - return false; - short length = lastData.ReadShort(); - byte[] data = lastData.ReadChunk(length); - packet = new NetworkPacket(header, data); - return true; + return socketBuffer.ReadPacket(out packet); } public void Send(NetworkPacket packet) { @@ -78,9 +66,13 @@ public class Client { } } + public void SheduleDisconnect() { + scheduledDisconnect = true; + } + public bool Connected { get { - return socket.Connected; + return socket.Connected && !scheduledDisconnect; } } } diff --git a/src/Core/Room.cs b/src/Core/Room.cs index 133bf3c..3b51c27 100644 --- a/src/Core/Room.cs +++ b/src/Core/Room.cs @@ -17,7 +17,11 @@ public class Room { public IEnumerable Clients { get { - return new List(clients); + List list; + lock (roomLock) { + list = new List(clients); + } + return list; } } diff --git a/src/Data/NetworkData.cs b/src/Data/NetworkData.cs index e5e8602..b861d74 100644 --- a/src/Data/NetworkData.cs +++ b/src/Data/NetworkData.cs @@ -17,6 +17,12 @@ public class NetworkData { this.data = data; } + public int RemainingLength { + get { + return data.Length - offset; + } + } + public void Seek(int offset) { int newOffset = this.offset + offset; if (newOffset >= 0 && newOffset < data.Length) diff --git a/src/Data/NetworkPacket.cs b/src/Data/NetworkPacket.cs index 2f177ac..329a211 100644 --- a/src/Data/NetworkPacket.cs +++ b/src/Data/NetworkPacket.cs @@ -33,12 +33,14 @@ public class NetworkPacket { header = 0xa0; this.compressed = true; } - this.data = data.Data; + this.data = new byte[data.Data.Length]; + Buffer.BlockCopy(data.Data, 0, this.data, 0, data.Data.Length); } public NetworkPacket(byte header, byte[] data) { this.header = header; - this.data = data; + this.data = new byte[data.Length]; + Buffer.BlockCopy(data, 0, this.data, 0, data.Length); if (header == 0xa0) compressed = true; } diff --git a/src/Data/SocketBuffer.cs b/src/Data/SocketBuffer.cs new file mode 100644 index 0000000..1dfa6e2 --- /dev/null +++ b/src/Data/SocketBuffer.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace sodoffmmo.Data; +internal class SocketBuffer { + NetworkData data = new(); + Status status = Status.Header; + byte header; + short length; + byte[] value = new byte[0]; + public void Write(byte[] buffer, int length) { + data.WriteChunk(buffer, 0, length); + } + + public bool ReadPacket(out NetworkPacket packet) { + packet = new(); + if (status == Status.Header) + ReadHeader(); + + if (status == Status.Value) { + ReadValue(); + if (status == Status.Header) { + packet = new(header, value); + return true; + } + } + + return false; + } + + private void ReadHeader() { + if (data.RemainingLength < 3) + return; + header = data.ReadByte(); + length = data.ReadShort(); + status = Status.Value; + } + + private void ReadValue() { + if (data.RemainingLength < length) + return; + value = data.ReadChunk(length); + data = new(data.ReadChunk(data.RemainingLength)); + status = Status.Header; + } + + enum Status { + Header, + Value + } +} diff --git a/src/Server.cs b/src/Server.cs index 22834f8..fefb45a 100644 --- a/src/Server.cs +++ b/src/Server.cs @@ -47,12 +47,11 @@ public class Server { _ = Task.Run(() => HandleObjects(networkObjects, client)); } - } catch (SocketException) { - client.Disconnect(); } finally { try { client.LeaveRoom(); } catch (Exception) { } + client.Disconnect(); Console.WriteLine("Socket disconnected IID: " + client.ClientID); } }