From 580ecc4fa0bd5687cf3db0c8ff1fb98ec88b2703 Mon Sep 17 00:00:00 2001 From: frg_kova Date: Sun, 27 Nov 2022 07:54:43 +0100 Subject: [PATCH] merged from unity project to fork of git master --- DarkRift.Client/BichannelClientConnection.cs | 258 +++++++++++++------ DarkRift.Client/DarkRift.Client.csproj | 1 + DarkRift.Client/DarkRiftClient.cs | 55 ++-- DarkRift.Server/DarkRift.Server.csproj | 1 + DarkRift/DarkRift.csproj | 1 + DarkRift/DarkRiftWriter.cs | 15 +- DarkRift/Message.cs | 19 +- DarkRift/MessageBuffer.cs | 3 + DarkRift/ObjectCache.cs | 10 + 9 files changed, 245 insertions(+), 118 deletions(-) diff --git a/DarkRift.Client/BichannelClientConnection.cs b/DarkRift.Client/BichannelClientConnection.cs index 21be3ff..e2ee1d6 100644 --- a/DarkRift.Client/BichannelClientConnection.cs +++ b/DarkRift.Client/BichannelClientConnection.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using System.Runtime.CompilerServices; using System.Text; namespace DarkRift.Client @@ -27,11 +28,12 @@ public sealed class BichannelClientConnection : NetworkClientConnection, IDispos /// The IP address of the remote client. /// public IPEndPoint RemoteUdpEndPoint { get; } - + /// /// Whether Nagel's algorithm should be disabled or not. /// - public bool NoDelay { + public bool NoDelay + { get => tcpSocket.NoDelay; set => tcpSocket.NoDelay = value; } @@ -64,7 +66,7 @@ public bool NoDelay { /// The port (UDP and TCP) the server is listening on. /// Whether to disable Nagle's algorithm or not. public BichannelClientConnection(IPAddress ipAddress, int port, bool noDelay) - : this (ipAddress, port, port, noDelay) + : this(ipAddress, port, port, noDelay) { } @@ -76,7 +78,7 @@ public BichannelClientConnection(IPAddress ipAddress, int port, bool noDelay) /// The port the server is listening on for TCP. /// Whether to disable Nagle's algorithm or not. public BichannelClientConnection(IPAddress ipAddress, int tcpPort, int udpPort, bool noDelay) - : base () + : base() { RemoteTcpEndPoint = new IPEndPoint(ipAddress, tcpPort); RemoteUdpEndPoint = new IPEndPoint(ipAddress, udpPort); @@ -105,7 +107,7 @@ public BichannelClientConnection(IPVersion ipVersion, IPAddress ipAddress, int p tcpSocket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp); udpSocket = new Socket(tcpSocket.AddressFamily, SocketType.Dgram, ProtocolType.Udp); - + NoDelay = noDelay; } @@ -139,13 +141,13 @@ public override void Connect() //Receive auth token from TCP byte[] buffer = new byte[9]; - tcpSocket.ReceiveTimeout = 5000; + tcpSocket.ReceiveTimeout = 5000; // 5s connection timeout int receivedTcp = tcpSocket.Receive(buffer); - tcpSocket.ReceiveTimeout = 0; //Reset to infinite + tcpSocket.ReceiveTimeout = 10000; // reset to 10s if (receivedTcp != 9 || buffer[0] != 0) { - tcpSocket.Shutdown(SocketShutdown.Both); + Disconnect(); throw new DarkRiftConnectionException("Timeout waiting for auth token from server.", SocketError.ConnectionAborted); } @@ -154,26 +156,26 @@ public override void Connect() //Receive response from server to initiate the connection buffer = new byte[1]; - udpSocket.ReceiveTimeout = 5000; + udpSocket.ReceiveTimeout = 5000; // 5s connection timeout int receivedUdp = udpSocket.Receive(buffer); - udpSocket.ReceiveTimeout = 0; //Reset to infinite + udpSocket.ReceiveTimeout = 10000; // reset to 10s if (receivedUdp != 1 || buffer[0] != 0) { - tcpSocket.Shutdown(SocketShutdown.Both); + Disconnect(); throw new DarkRiftConnectionException("Timeout waiting for UDP acknowledgement from server.", SocketError.ConnectionAborted); } } catch (DarkRiftConnectionException) { // If any exceptions get thrown reset the connection state - connectionState = ConnectionState.Disconnected; + Disconnect(); throw; } catch (SocketException) { // If any exceptions get thrown reset the connection state - connectionState = ConnectionState.Disconnected; + Disconnect(); throw; } @@ -207,17 +209,9 @@ public override bool SendMessageReliable(MessageBuffer message) if (connectionState == ConnectionState.Disconnected) return false; - byte[] header = new byte[4]; - BigEndianHelper.WriteBytes(header, 0, message.Count); - SocketAsyncEventArgs args = ObjectCache.GetSocketAsyncEventArgs(); - args.SetBuffer(null, 0, 0); - args.BufferList = new List>() - { - new ArraySegment(header), - new ArraySegment(message.Buffer, message.Offset, message.Count) - }; + args.SetBuffer(message.Buffer, message.Offset, message.Count); args.UserToken = message; args.Completed += TcpSendCompleted; @@ -227,8 +221,14 @@ public override bool SendMessageReliable(MessageBuffer message) { completingAsync = tcpSocket.SendAsync(args); } + catch (ObjectDisposedException) + { + TcpSendCompleted(this, args); + return false; + } catch (Exception) { + TcpSendCompleted(this, args); return false; } @@ -258,6 +258,7 @@ public override bool SendMessageUnreliable(MessageBuffer message) } catch (Exception) { + UdpSendCompleted(this, args); return false; } @@ -274,8 +275,21 @@ public override bool Disconnect() return false; connectionState = ConnectionState.Disconnected; - tcpSocket.Shutdown(SocketShutdown.Both); - + try + { + tcpSocket.Shutdown(SocketShutdown.Both); + udpSocket.Shutdown(SocketShutdown.Both); + } + catch (SocketException) + { + //Ignore exception as socket is already shutdown + } + finally + { + tcpSocket.Close(); + udpSocket.Close(); + } + return true; } @@ -310,6 +324,7 @@ private void ReceiveHeaderAndBody(SocketAsyncEventArgs args) try { + // header not fully received yet, wait for it bool headerContinueCompletingAsync = tcpSocket.ReceiveAsync(args); if (headerContinueCompletingAsync) return; @@ -319,7 +334,13 @@ private void ReceiveHeaderAndBody(SocketAsyncEventArgs args) HandleDisconnectionDuringHeaderReceive(args); return; } + catch (Exception) + { + HandleDisconnectionDuringHeaderReceive(args); + return; + } + // keep getting header in a loop until received continue; } @@ -339,6 +360,11 @@ private void ReceiveHeaderAndBody(SocketAsyncEventArgs args) HandleDisconnectionDuringBodyReceive(args); return; } + catch (Exception) + { + HandleDisconnectionDuringBodyReceive(args); + return; + } if (!WasBodyReceiveSucessful(args)) { @@ -352,6 +378,7 @@ private void ReceiveHeaderAndBody(SocketAsyncEventArgs args) UpdateBufferPointers(args); } + // body received, process it MessageBuffer bodyBuffer = ProcessBody(args); // Start next receive before invoking events @@ -361,7 +388,12 @@ private void ReceiveHeaderAndBody(SocketAsyncEventArgs args) { headerCompletingAsync = tcpSocket.ReceiveAsync(args); } - catch (ObjectDisposedException) + catch (ObjectDisposedException) + { + HandleDisconnectionDuringHeaderReceive(args); + return; + } + catch (Exception) { HandleDisconnectionDuringHeaderReceive(args); return; @@ -413,7 +445,12 @@ private void AsyncReceiveBodyCompleted(object sender, SocketAsyncEventArgs args) } catch (ObjectDisposedException) { - HandleDisconnectionDuringBodyReceive(args); + HandleDisconnectionDuringHeaderReceive(args); + return; + } + catch (Exception) + { + HandleDisconnectionDuringHeaderReceive(args); return; } } @@ -427,7 +464,12 @@ private void AsyncReceiveBodyCompleted(object sender, SocketAsyncEventArgs args) { headerCompletingAsync = tcpSocket.ReceiveAsync(args); } - catch (ObjectDisposedException) + catch (ObjectDisposedException) + { + HandleDisconnectionDuringHeaderReceive(args); + return; + } + catch (Exception) { HandleDisconnectionDuringHeaderReceive(args); return; @@ -438,7 +480,7 @@ private void AsyncReceiveBodyCompleted(object sender, SocketAsyncEventArgs args) if (headerCompletingAsync) return; - //Now move back into main loop until no more data is present + // header not recieved async, move back into main loop until no more data is present ReceiveHeaderAndBody(args); } @@ -447,11 +489,12 @@ private void AsyncReceiveBodyCompleted(object sender, SocketAsyncEventArgs args) /// /// The socket args used during the operation. /// If the whole header has been received. + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(256)] private bool IsHeaderReceiveComplete(SocketAsyncEventArgs args) { - MessageBuffer headerBuffer = (MessageBuffer)args.UserToken; - - return args.Offset + args.BytesTransferred - headerBuffer.Offset >= headerBuffer.Count; + // header size is 4 bytes, an int + return args.Offset + args.BytesTransferred >= Message.HEADER_RESERVED_BYTES_COUNT; } /// @@ -459,11 +502,15 @@ private bool IsHeaderReceiveComplete(SocketAsyncEventArgs args) /// /// The socket args used during the operation. /// If the whole body has been received. + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(256)] private bool IsBodyReceiveComplete(SocketAsyncEventArgs args) { - MessageBuffer bodyBuffer = (MessageBuffer)args.UserToken; + MessageBuffer buffer = (MessageBuffer)args.UserToken; + return args.Offset + args.BytesTransferred >= buffer.Count; - return args.Offset + args.BytesTransferred - bodyBuffer.Offset >= bodyBuffer.Count; + // DEBUG when using byte[] of exact size an not pooled MessageBuffer + //return args.Offset + args.BytesTransferred >= args.Buffer.Length; } /// @@ -473,14 +520,9 @@ private bool IsBodyReceiveComplete(SocketAsyncEventArgs args) /// The number of bytes in the body. private int ProcessHeader(SocketAsyncEventArgs args) { - MessageBuffer headerBuffer = (MessageBuffer)args.UserToken; - - int bodyLength = BigEndianHelper.ReadInt32(headerBuffer.Buffer, headerBuffer.Offset); - - headerBuffer.Dispose(); - args.Completed -= AsyncReceiveHeaderCompleted; + int bodyLength = BigEndianHelper.ReadInt32(args.Buffer, args.Offset); return bodyLength; } @@ -489,20 +531,29 @@ private int ProcessHeader(SocketAsyncEventArgs args) /// /// The socket args used during the operation. /// The buffer received. + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(256)] private MessageBuffer ProcessBody(SocketAsyncEventArgs args) { args.Completed -= AsyncReceiveBodyCompleted; return (MessageBuffer)args.UserToken; + + // DEBUG MODE: create a buffer rather then getting it from the pool + //var buffer = MessageBuffer.Create(args.Buffer.Length); + //buffer.Count = args.Buffer.Length; + //Buffer.BlockCopy(args.Buffer, 0, buffer.Buffer, 0, args.Buffer.Length); + //return buffer; } /// /// Invokes message recevied events and cleans up. /// /// The TCP body received. + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(256)] private void ProcessMessage(MessageBuffer buffer) { HandleMessageReceived(buffer, SendMode.Reliable); - buffer.Dispose(); } @@ -511,6 +562,8 @@ private void ProcessMessage(MessageBuffer buffer) /// /// The socket args used during the operation. /// If the receive completed correctly. + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(256)] private bool WasHeaderReceiveSucessful(SocketAsyncEventArgs args) { return args.BytesTransferred != 0 && args.SocketError == SocketError.Success; @@ -521,6 +574,7 @@ private bool WasHeaderReceiveSucessful(SocketAsyncEventArgs args) /// /// The socket args used during the operation. /// If the receive completed correctly. + //[MethodImpl(MethodImplOptions.AggressiveInlining)] private bool WasBodyReceiveSucessful(SocketAsyncEventArgs args) { return args.BytesTransferred != 0 && args.SocketError == SocketError.Success; @@ -532,12 +586,10 @@ private bool WasBodyReceiveSucessful(SocketAsyncEventArgs args) /// The socket args used during the operation. private void HandleDisconnectionDuringHeaderReceive(SocketAsyncEventArgs args) { - Disconnect(args.SocketError); + args.Completed -= AsyncReceiveHeaderCompleted; - MessageBuffer buffer = (MessageBuffer)args.UserToken; - buffer.Dispose(); + Disconnect(args.SocketError); - args.Completed -= AsyncReceiveHeaderCompleted; ObjectCache.ReturnSocketAsyncEventArgs(args); } @@ -547,13 +599,13 @@ private void HandleDisconnectionDuringHeaderReceive(SocketAsyncEventArgs args) /// The socket args used during the operation. private void HandleDisconnectionDuringBodyReceive(SocketAsyncEventArgs args) { - Disconnect(args.SocketError); + args.Completed -= AsyncReceiveBodyCompleted; MessageBuffer buffer = (MessageBuffer)args.UserToken; - buffer.Dispose(); + Disconnect(args.SocketError); - args.Completed -= AsyncReceiveBodyCompleted; ObjectCache.ReturnSocketAsyncEventArgs(args); + buffer.Dispose(); } /// @@ -562,10 +614,8 @@ private void HandleDisconnectionDuringBodyReceive(SocketAsyncEventArgs args) /// The socket args to use during the operation. private void SetupReceiveHeader(SocketAsyncEventArgs args) { - MessageBuffer headerBuffer = MessageBuffer.Create(4); - - args.SetBuffer(headerBuffer.Buffer, headerBuffer.Offset, 4); - args.UserToken = headerBuffer; + // TODO tiny alloc + args.SetBuffer(new byte[4], 0, 4); args.Completed += AsyncReceiveHeaderCompleted; } @@ -576,11 +626,19 @@ private void SetupReceiveHeader(SocketAsyncEventArgs args) /// The number of bytes in the body. private void SetupReceiveBody(SocketAsyncEventArgs args, int length) { + // here we're setting the buffer count as a marker on how much data received we need exactly for the body MessageBuffer bodyBuffer = MessageBuffer.Create(length); bodyBuffer.Count = length; - args.SetBuffer(bodyBuffer.Buffer, bodyBuffer.Offset, length); + args.SetBuffer(bodyBuffer.Buffer, 0, length); args.UserToken = bodyBuffer; + //Debug.Log($"Receive buffer created. Size: [{length}], Capacity: [{bodyBuffer.Buffer.Length}], Offset: [{bodyBuffer.Offset}]"); + + // DEBUG: use byte[] as buffer rather then pooled MessageBuffer + //byte[] bodyReceiveBuffer = new byte[length]; + //args.SetBuffer(bodyReceiveBuffer, 0, length); + //Debug.Log($"Receive buffer created. Size: [{length}], Capacity: [{length}], Offset: [{args.Offset}]"); + args.Completed += AsyncReceiveBodyCompleted; } @@ -588,8 +646,18 @@ private void SetupReceiveBody(SocketAsyncEventArgs args, int length) /// Updates the pointers on the buffer to continue a receive operation. /// /// The socket args to update. - private void UpdateBufferPointers(SocketAsyncEventArgs args) { - args.SetBuffer(args.Offset + args.BytesTransferred, args.Count - args.BytesTransferred); + private void UpdateBufferPointers(SocketAsyncEventArgs args) + { + MessageBuffer buffer = args.UserToken as MessageBuffer; + int newOffset = args.Offset + args.BytesTransferred; + args.SetBuffer(newOffset, buffer.Count - newOffset); + //Debug.Log($"Received bytes: [{args.BytesTransferred}], in buffer: [{newOffset}], remaining [{buffer.Count - newOffset}]"); + + // DEBUG: use byte[] as buffer rather then pooled MessageBuffer + // move the offset to bytes read + //int newOffset = args.Offset + args.BytesTransferred; + //args.SetBuffer(newOffset, args.Buffer.Length - newOffset); + //Debug.Log($"Received bytes: [{args.BytesTransferred}], in buffer: [{newOffset}], remaining [{args.Buffer.Length - newOffset}]"); } /// @@ -605,17 +673,15 @@ private void UdpReceiveCompleted(object sender, SocketAsyncEventArgs e) //If we received a Success then process it if (e.SocketError == SocketError.Success) { - using (MessageBuffer buffer = MessageBuffer.Create(e.BytesTransferred)) - { - Buffer.BlockCopy(e.Buffer, 0, buffer.Buffer, buffer.Offset, e.BytesTransferred); - buffer.Count = e.BytesTransferred; + using MessageBuffer buffer = MessageBuffer.Create(e.BytesTransferred); + Buffer.BlockCopy(e.Buffer, 0, buffer.Buffer, buffer.Offset, e.BytesTransferred); + buffer.Count = e.BytesTransferred; - completingAsync = udpSocket.ReceiveAsync(e); + completingAsync = udpSocket.ReceiveAsync(e); - //Length of 0 must be a hole punching packet - if (buffer.Count != 0) - HandleMessageReceived(buffer, SendMode.Unreliable); - } + //Length of 0 must be a hole punching packet + if (buffer.Count != 0) + HandleMessageReceived(buffer, SendMode.Unreliable); } //Ignore ConnectionReset (ICMP Port Unreachable) since NATs will return that when they get @@ -644,18 +710,48 @@ private void UdpReceiveCompleted(object sender, SocketAsyncEventArgs e) /// Called when a TCP send has completed. /// /// - /// - private void TcpSendCompleted(object sender, SocketAsyncEventArgs e) + /// + private void TcpSendCompleted(object sender, SocketAsyncEventArgs args) { - if (e.SocketError != SocketError.Success) - Disconnect(e.SocketError); + MessageBuffer messageBuffer = (MessageBuffer)args.UserToken; + SocketError socketError = args.SocketError; + + // Linux+Mono combination can complete without sending every byte on large packets + // this is not documented anythwere, call SendAsync again when that happens + // except in error case that is handled later on + int bytesTransferredTotal = args.Offset + args.BytesTransferred; + if (socketError == SocketError.Success && bytesTransferredTotal > 0 && bytesTransferredTotal < messageBuffer.Count) + { + args.SetBuffer(offset: bytesTransferredTotal, count: messageBuffer.Count - bytesTransferredTotal); + bool isCompletedAsync = tcpSocket.SendAsync(args); + if (isCompletedAsync) + return; - e.Completed -= TcpSendCompleted; + // otherwise it completed sync, just continue with execution as we're already in the complete callback + } - //Always dispose buffer when completed! - ((MessageBuffer)e.UserToken).Dispose(); + args.Completed -= TcpSendCompleted; - ObjectCache.ReturnSocketAsyncEventArgs(e); + // must save some info before we release the args into the pool and it gets reset + int bytesTotal = messageBuffer.Count + Message.HEADER_RESERVED_BYTES_COUNT; + int bufferSize = messageBuffer.Buffer.Length; + int bytesTransferred = args.BytesTransferred; + int sendSize = args.SendPacketsSendSize; + SocketFlags flags = args.SocketFlags; + + // socket disposed first to release ref to buffer as buffer might get reused immediatly + // if disposed with socket still holding the ref to it + ObjectCache.ReturnSocketAsyncEventArgs(args); + + // Always dispose buffer when completed! + messageBuffer.Dispose(); + + // during receive BytesTransferred == 0 means disconnect, maybe it could mean here as well, it's not documented + if (socketError != SocketError.Success || bytesTransferredTotal == 0) + { + Disconnect(socketError); + return; + } } /// @@ -665,15 +761,19 @@ private void TcpSendCompleted(object sender, SocketAsyncEventArgs e) /// private void UdpSendCompleted(object sender, SocketAsyncEventArgs e) { - if (e.SocketError != SocketError.Success) - Disconnect(e.SocketError); - e.Completed -= UdpSendCompleted; - //Always dispose buffer when completed! - ((MessageBuffer)e.UserToken).Dispose(); + MessageBuffer messageBuffer = (MessageBuffer)e.UserToken; + // socket disposed first to release ref to buffer as buffer might get reused immediatly + // if disposed with socket still holding the ref to it ObjectCache.ReturnSocketAsyncEventArgs(e); + + // Always dispose buffer when completed! + messageBuffer.Dispose(); + + if (e.SocketError != SocketError.Success) + Disconnect(e.SocketError); } /// @@ -684,8 +784,7 @@ private void Disconnect(SocketError error) { if (connectionState == ConnectionState.Connected) { - connectionState = ConnectionState.Disconnected; - + Disconnect(); HandleDisconnection(error); } } @@ -706,9 +805,6 @@ protected override void Dispose(bool disposing) if (disposing) { Disconnect(); - - tcpSocket.Close(); - udpSocket.Close(); } disposedValue = true; diff --git a/DarkRift.Client/DarkRift.Client.csproj b/DarkRift.Client/DarkRift.Client.csproj index 2e9b9c4..929273f 100644 --- a/DarkRift.Client/DarkRift.Client.csproj +++ b/DarkRift.Client/DarkRift.Client.csproj @@ -8,6 +8,7 @@ bin\$(Configuration)\$(TargetFramework)\DarkRift.Client.xml Debug;Free true + 8.0 diff --git a/DarkRift.Client/DarkRiftClient.cs b/DarkRift.Client/DarkRiftClient.cs index 69a186a..9c65060 100644 --- a/DarkRift.Client/DarkRiftClient.cs +++ b/DarkRift.Client/DarkRiftClient.cs @@ -232,8 +232,7 @@ public void Connect(NetworkClientConnection connection) { setupMutex.Reset(); - if (this.Connection != null) - this.Connection.Dispose(); + this.Connection?.Dispose(); this.Connection = connection; connection.MessageReceived = MessageReceivedHandler; @@ -371,26 +370,25 @@ public bool Disconnect() /// The SendMode used to send the data. private void MessageReceivedHandler(MessageBuffer buffer, SendMode sendMode) { - using (Message message = Message.Create(buffer, true)) + using Message message = Message.Create(buffer, true); + + //Record any ping acknowledgements + if (message.IsPingAcknowledgementMessage) { - //Record any ping acknowledgements - if (message.IsPingAcknowledgementMessage) + try { - try - { - RoundTripTime.RecordInboundPing(message.PingCode); - } - catch (KeyNotFoundException) - { - //Nothing we can really do about this - } + RoundTripTime.RecordInboundPing(message.PingCode); + } + catch (KeyNotFoundException) + { + //Nothing we can really do about this } - - if (message.IsCommandMessage) - HandleCommand(message); - else - HandleMessage(message, sendMode); } + + if (message.IsCommandMessage) + HandleCommand(message); + else + HandleMessage(message, sendMode); } /// @@ -399,16 +397,14 @@ private void MessageReceivedHandler(MessageBuffer buffer, SendMode sendMode) /// The message that was received. private void HandleCommand(Message message) { - using (DarkRiftReader reader = message.GetReader()) + using DarkRiftReader reader = message.GetReader(); + switch ((CommandCode)message.Tag) { - switch ((CommandCode)message.Tag) - { - case CommandCode.Configure: - ID = reader.ReadUInt16(); + case CommandCode.Configure: + ID = reader.ReadUInt16(); - setupMutex.Set(); - break; - } + setupMutex.Set(); + break; } } @@ -420,8 +416,8 @@ private void HandleCommand(Message message) private void HandleMessage(Message message, SendMode sendMode) { //Invoke for message received event - using (MessageReceivedEventArgs args = MessageReceivedEventArgs.Create(message, sendMode)) - MessageReceived?.Invoke(this, args); + using MessageReceivedEventArgs args = MessageReceivedEventArgs.Create(message, sendMode); + MessageReceived?.Invoke(this, args); } /// @@ -455,8 +451,7 @@ protected virtual void Dispose(bool disposing) { disposed = true; - if (Connection != null) - Connection.Dispose(); + Connection?.Dispose(); setupMutex.Close(); } diff --git a/DarkRift.Server/DarkRift.Server.csproj b/DarkRift.Server/DarkRift.Server.csproj index 644f32b..37cf741 100644 --- a/DarkRift.Server/DarkRift.Server.csproj +++ b/DarkRift.Server/DarkRift.Server.csproj @@ -8,6 +8,7 @@ bin\$(Configuration)\$(TargetFramework)\DarkRift.Server.xml Debug;Release true + 8.0 diff --git a/DarkRift/DarkRift.csproj b/DarkRift/DarkRift.csproj index 4678203..cae4c0d 100644 --- a/DarkRift/DarkRift.csproj +++ b/DarkRift/DarkRift.csproj @@ -9,6 +9,7 @@ Debug;Release true true + 8.0 diff --git a/DarkRift/DarkRiftWriter.cs b/DarkRift/DarkRiftWriter.cs index 3c27263..c6a7423 100644 --- a/DarkRift/DarkRiftWriter.cs +++ b/DarkRift/DarkRiftWriter.cs @@ -117,7 +117,18 @@ internal DarkRiftWriter() { serializeEventSingleton = new SerializeEvent(this); } - + + /// + /// Clears out the buffer, making it empty and reusable. + /// + /// Added by kova@freerangegames.com 2022-05-20 + public void Clear() + { + Position = 0; + buffer.Count = 0; + buffer.Offset = 0; + } + /// /// Writes a single byte to the writer. /// @@ -565,7 +576,7 @@ public void Write(T[] value) where T : IDarkRiftSerializable public void WriteRaw(byte[] bytes, int offset, int length) { buffer.EnsureLength(Position + length); - System.Buffer.BlockCopy(bytes, offset, buffer.Buffer, Position, length); + Buffer.BlockCopy(bytes, offset, buffer.Buffer, Position, length); Position += length; buffer.Count = Math.Max(Length, Position); diff --git a/DarkRift/Message.cs b/DarkRift/Message.cs index 44cc453..ddf1870 100644 --- a/DarkRift/Message.cs +++ b/DarkRift/Message.cs @@ -19,6 +19,11 @@ namespace DarkRift /// public sealed class Message : IDisposable { + /// + /// How many bytes is reserved for message header with value of rest of the message + /// + public const int HEADER_RESERVED_BYTES_COUNT = 4; + /// /// Bitmask for the command message flag. /// @@ -420,19 +425,23 @@ public void MakePingAcknowledgementMessage(Message acknowledging) //TODO DR3 Make this return an IMessageBuffer internal MessageBuffer ToBuffer() { - int headerLength = IsPingMessage || IsPingAcknowledgementMessage ? 5 : 3; + int headerLength = HEADER_RESERVED_BYTES_COUNT + (IsPingMessage || IsPingAcknowledgementMessage ? 5 : 3); int totalLength = headerLength + DataLength; MessageBuffer buffer = MessageBuffer.Create(totalLength); buffer.Count = totalLength; - buffer.Buffer[buffer.Offset] = flags; - BigEndianHelper.WriteBytes(buffer.Buffer, buffer.Offset + 1, tag); + // write length of the rest of the message + BigEndianHelper.WriteBytes(buffer.Buffer, 0, totalLength - HEADER_RESERVED_BYTES_COUNT); + + buffer.Buffer[HEADER_RESERVED_BYTES_COUNT] = flags; + BigEndianHelper.WriteBytes(buffer.Buffer, buffer.Offset + 1 + HEADER_RESERVED_BYTES_COUNT, tag); if (IsPingMessage || IsPingAcknowledgementMessage) - BigEndianHelper.WriteBytes(buffer.Buffer, buffer.Offset + 3, PingCode); + BigEndianHelper.WriteBytes(buffer.Buffer, buffer.Offset + 3 + HEADER_RESERVED_BYTES_COUNT, PingCode); - //Due to poor design, here's un unavoidable memory copy! Hooray! + // Due to poor design, here's un unavoidable memory copy! Hooray! + // Copy the content of the message into rest of the new buffer Buffer.BlockCopy(this.buffer.Buffer, this.buffer.Offset, buffer.Buffer, buffer.Offset + headerLength, this.buffer.Count); return buffer; diff --git a/DarkRift/MessageBuffer.cs b/DarkRift/MessageBuffer.cs index ed513ed..c26da15 100644 --- a/DarkRift/MessageBuffer.cs +++ b/DarkRift/MessageBuffer.cs @@ -114,6 +114,9 @@ internal void EnsureLength(int newLength) #region IDisposable Support public void Dispose() { + Count = 0; + Offset = 0; + //AutoRecyclingArray is reference counted, mark that we're no longer using it backingBuffer.DecrementReference(); diff --git a/DarkRift/ObjectCache.cs b/DarkRift/ObjectCache.cs index 96af8ec..1d42652 100644 --- a/DarkRift/ObjectCache.cs +++ b/DarkRift/ObjectCache.cs @@ -321,6 +321,16 @@ public static void ReturnSocketAsyncEventArgs(SocketAsyncEventArgs socketAsyncEv ObjectCacheTestHelper.SocketAsyncEventArgsWasReturned(); #endif + // added safety restore to default state before going ito the pool + socketAsyncEventArgs.SocketFlags = SocketFlags.None; + socketAsyncEventArgs.SocketError = SocketError.Success; + socketAsyncEventArgs.SendPacketsSendSize = 0; + socketAsyncEventArgs.SendPacketsFlags = TransmitFileOptions.UseDefaultWorkerThread; + socketAsyncEventArgs.SendPacketsElements = null; + socketAsyncEventArgs.BufferList = null; + socketAsyncEventArgs.UserToken = null; + socketAsyncEventArgs.SetBuffer(null, 0, 0); + if (!socketAsyncEventArgsPool.ReturnInstance(socketAsyncEventArgs)) socketAsyncEventArgs.Dispose(); }