From 1e3f256d59fbf1bf1b0100a14df0cf7a89a5f55f Mon Sep 17 00:00:00 2001
From: dungeon2567 <31074903+dungeon2567@users.noreply.github.com>
Date: Wed, 15 Jul 2020 12:24:09 -0300
Subject: [PATCH 1/4] Update RuffleSocket.cs
---
Ruffles/Core/RuffleSocket.cs | 1585 +++++++++++++++++-----------------
1 file changed, 790 insertions(+), 795 deletions(-)
diff --git a/Ruffles/Core/RuffleSocket.cs b/Ruffles/Core/RuffleSocket.cs
index 0818370..c5437d8 100644
--- a/Ruffles/Core/RuffleSocket.cs
+++ b/Ruffles/Core/RuffleSocket.cs
@@ -1,28 +1,28 @@
using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using Ruffles.Channeling;
-using Ruffles.Collections;
-using Ruffles.Configuration;
-using Ruffles.Connections;
-using Ruffles.Hashing;
-using Ruffles.Memory;
-using Ruffles.Messaging;
-using Ruffles.Random;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using Ruffles.Channeling;
+using Ruffles.Collections;
+using Ruffles.Configuration;
+using Ruffles.Connections;
+using Ruffles.Hashing;
+using Ruffles.Memory;
+using Ruffles.Messaging;
+using Ruffles.Random;
using Ruffles.Simulation;
-using Ruffles.Time;
-using Ruffles.Utils;
-
-namespace Ruffles.Core
+using Ruffles.Time;
+using Ruffles.Utils;
+
+namespace Ruffles.Core
{
///
/// A dual IPv4 IPv6 socket using the Ruffles protocol.
- ///
- public sealed class RuffleSocket
- {
+ ///
+ public sealed class RuffleSocket
+ {
// Separate connections and pending to prevent something like a slorris attack
private readonly Dictionary _addressConnectionLookup = new Dictionary();
private Connection _headConnection;
@@ -31,24 +31,24 @@ public sealed class RuffleSocket
// Lock for adding or removing connections. This is done to allow for a quick ref to be gained on the user thread when connecting.
private readonly ReaderWriterLockSlim _connectionsLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
-
- private Socket _ipv4Socket;
+
+ private Socket _ipv4Socket;
private Socket _ipv6Socket;
private SlidingSet _challengeInitializationVectors;
private readonly object _challengeInitializationVectorsLock = new object();
internal MemoryManager MemoryManager { get; private set; }
- internal NetworkSimulator Simulator { get; private set; }
+ internal NetworkSimulator Simulator { get; private set; }
internal ChannelPool ChannelPool { get; private set; }
internal readonly SocketConfig Config;
- private readonly List _threads = new List();
+ private readonly List _threads = new List();
///
/// Gets a value indicating whether this is running.
///
- /// true if is running; otherwise, false.
+ /// true if is running; otherwise, false.
public bool IsRunning { get; private set; }
///
/// Gets a value indicating whether this is terminated.
@@ -66,11 +66,11 @@ public sealed class RuffleSocket
///
/// Whether or not the current OS supports IPv6
///
- public static readonly bool SupportsIPv6 = Socket.OSSupportsIPv6;
-
- // Events
-
- // Syncronized event
+ public static readonly bool SupportsIPv6 = Socket.OSSupportsIPv6;
+
+ // Events
+
+ // Syncronized event
private readonly AutoResetEvent _syncronizedEvent = new AutoResetEvent(false);
// Syncronized callbacks
private readonly ReaderWriterLockSlim _syncronizedCallbacksLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
@@ -79,8 +79,8 @@ public sealed class RuffleSocket
private ConcurrentCircularQueue _userEventQueue;
// Processing queue
- private ConcurrentCircularQueue> _processingQueue;
-
+ private ConcurrentCircularQueue> _processingQueue;
+
///
/// Gets a syncronization event that is set when a event is received.
///
@@ -97,46 +97,52 @@ public AutoResetEvent SyncronizationEvent
return _syncronizedEvent;
}
}
-
+
+ ///
+ /// Gets a syncronization event that needs to be sent when frame end.
+ ///
+ /// The syncronization event.
+ public AutoResetEvent FrameSyncronizationEvent { get; } = new AutoResetEvent(false);
+
///
/// Gets the local IPv4 listening endpoint.
///
/// The local IPv4 endpoint.
public EndPoint LocalIPv4EndPoint
- {
- get
+ {
+ get
{
- if (_ipv4Socket == null)
- {
- return new IPEndPoint(IPAddress.None, 0);
+ if (_ipv4Socket == null)
+ {
+ return new IPEndPoint(IPAddress.None, 0);
}
-
- return _ipv4Socket.LocalEndPoint;
- }
- }
+
+ return _ipv4Socket.LocalEndPoint;
+ }
+ }
///
/// Gets the local IPv6 listening endpoint.
///
- /// The local IPv6 endpoint.
- public EndPoint LocalIPv6EndPoint
+ /// The local IPv6 endpoint.
+ public EndPoint LocalIPv6EndPoint
{
get
{
- if (_ipv6Socket == null)
- {
- return new IPEndPoint(IPAddress.IPv6None, 0);
+ if (_ipv6Socket == null)
+ {
+ return new IPEndPoint(IPAddress.IPv6None, 0);
}
return _ipv6Socket.LocalEndPoint;
}
}
-
- public RuffleSocket(SocketConfig config)
+
+ public RuffleSocket(SocketConfig config)
{
this.Config = config;
- }
-
+ }
+
///
/// Register a syncronized callback that is ran on a specific thread when a message arrives.
///
@@ -234,10 +240,10 @@ internal void PublishEvent(NetworkEvent @event)
}
}
- private void Initialize()
- {
+ private void Initialize()
+ {
if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogInfo("Initializing socket");
-
+
if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Checking SocketConfig validity");
List configurationErrors = Config.GetInvalidConfiguration();
@@ -265,24 +271,24 @@ private void Initialize()
if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Allocating " + Config.EventQueueSize + " event slots");
_userEventQueue = new ConcurrentCircularQueue(Config.EventQueueSize);
- if (Config.ProcessingThreads > 0)
- {
+ if (Config.ProcessingThreads > 0)
+ {
if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Allocating " + Config.ProcessingQueueSize + " processing slots");
- _processingQueue = new ConcurrentCircularQueue>(Config.ProcessingQueueSize);
+ _processingQueue = new ConcurrentCircularQueue>(Config.ProcessingQueueSize);
}
else
- {
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Not allocating processingQueue beucase ProcessingThreads is set to 0");
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Not allocating processingQueue beucase ProcessingThreads is set to 0");
}
- if (Config.TimeBasedConnectionChallenge)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Allocating " + Config.ConnectionChallengeHistory + " challenge IV slots");
- _challengeInitializationVectors = new SlidingSet((int)Config.ConnectionChallengeHistory);
+ if (Config.TimeBasedConnectionChallenge)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Allocating " + Config.ConnectionChallengeHistory + " challenge IV slots");
+ _challengeInitializationVectors = new SlidingSet((int)Config.ConnectionChallengeHistory);
}
else
- {
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Not allocating challenge IV cache beucase TimeBasedConnectionChallenge is set to false");
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Not allocating challenge IV cache beucase TimeBasedConnectionChallenge is set to false");
}
if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Allocating memory manager");
@@ -299,233 +305,233 @@ private void Initialize()
// Reset the connectionId counter
_connectionIdCounter = 0;
// Reset the releasedConnectionIds collection
- _releasedConnectionIds.Clear();
-
- if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogInfo("Socket initialized");
+ _releasedConnectionIds.Clear();
+
+ if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogInfo("Socket initialized");
}
///
/// Starts the socket.
///
- public bool Start()
+ public bool Start()
{
- lock (_stateLock)
- {
- if (IsRunning)
- {
- throw new InvalidOperationException("Socket already started");
- }
-
- if (!IsInitialized)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Binding socket");
- bool bindSuccess = Bind(Config.IPv4ListenAddress, Config.IPv6ListenAddress, Config.DualListenPort, Config.UseIPv6Dual);
-
- if (!bindSuccess)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Failed to bind socket");
- return false;
- }
- else
- {
- if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogInfo("Socket was successfully bound");
- Initialize();
- IsInitialized = true;
- }
- }
-
- // Create logic threads
- for (int i = 0; i < Config.LogicThreads; i++)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Creating NetworkThread #" + i);
-
- _threads.Add(new Thread(StartNetworkLogic)
- {
- Name = "NetworkThread #" + i,
- IsBackground = true
- });
- }
-
- // Create socket threads
- for (int i = 0; i < Config.SocketThreads; i++)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Creating SocketThread #" + i);
-
- _threads.Add(new Thread(StartSocketLogic)
- {
- Name = "SocketThread #" + i,
- IsBackground = true
- });
- }
-
- for (int i = 0; i < Config.ProcessingThreads; i++)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Creating ProcessingThread #" + i);
-
- _threads.Add(new Thread(StartPacketProcessing)
- {
- Name = "ProcessingThread #" + i,
- IsBackground = true
- });
- }
-
- // Set running state to true
- IsRunning = true;
-
- // Start threads
- for (int i = 0; i < _threads.Count; i++)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Starting " + _threads[i].Name);
-
- _threads[i].Start();
- }
-
- if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogInfo("Started " + (Config.LogicThreads + Config.SocketThreads + Config.ProcessingThreads) + " threads");
-
- return true;
- }
+ lock (_stateLock)
+ {
+ if (IsRunning)
+ {
+ throw new InvalidOperationException("Socket already started");
+ }
+
+ if (!IsInitialized)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Binding socket");
+ bool bindSuccess = Bind(Config.IPv4ListenAddress, Config.IPv6ListenAddress, Config.DualListenPort, Config.UseIPv6Dual);
+
+ if (!bindSuccess)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Failed to bind socket");
+ return false;
+ }
+ else
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogInfo("Socket was successfully bound");
+ Initialize();
+ IsInitialized = true;
+ }
+ }
+
+ // Create logic threads
+ for (int i = 0; i < Config.LogicThreads; i++)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Creating NetworkThread #" + i);
+
+ _threads.Add(new Thread(StartNetworkLogic)
+ {
+ Name = "NetworkThread #" + i,
+ IsBackground = true
+ });
+ }
+
+ // Create socket threads
+ for (int i = 0; i < Config.SocketThreads; i++)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Creating SocketThread #" + i);
+
+ _threads.Add(new Thread(StartSocketLogic)
+ {
+ Name = "SocketThread #" + i,
+ IsBackground = true
+ });
+ }
+
+ for (int i = 0; i < Config.ProcessingThreads; i++)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Creating ProcessingThread #" + i);
+
+ _threads.Add(new Thread(StartPacketProcessing)
+ {
+ Name = "ProcessingThread #" + i,
+ IsBackground = true
+ });
+ }
+
+ // Set running state to true
+ IsRunning = true;
+
+ // Start threads
+ for (int i = 0; i < _threads.Count; i++)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Starting " + _threads[i].Name);
+
+ _threads[i].Start();
+ }
+
+ if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogInfo("Started " + (Config.LogicThreads + Config.SocketThreads + Config.ProcessingThreads) + " threads");
+
+ return true;
+ }
}
///
/// Stops the socket. This will flush all the events to the UserQueue allowing you to Poll them.
///
- public void Stop()
+ public void Stop()
{
- lock (_stateLock)
- {
- if (!IsRunning)
- {
- throw new InvalidOperationException("Cannot stop a non running socket");
+ lock (_stateLock)
+ {
+ if (!IsRunning)
+ {
+ throw new InvalidOperationException("Cannot stop a non running socket");
+ }
+
+ // Stop all the threads
+ IsRunning = false;
+
+ int threadCount = _threads.Count;
+
+ // Wait for all the threads to exit
+ for (int i = _threads.Count - 1; i >= 0; i--)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Joining " + _threads[i].Name);
+
+ _threads[i].Join();
+ _threads.RemoveAt(i);
}
- // Stop all the threads
- IsRunning = false;
-
- int threadCount = _threads.Count;
-
- // Wait for all the threads to exit
- for (int i = _threads.Count - 1; i >= 0; i--)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Joining " + _threads[i].Name);
-
- _threads[i].Join();
- _threads.RemoveAt(i);
- }
-
- if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogInfo("Joined " + threadCount + " threads");
+ if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogInfo("Joined " + threadCount + " threads");
// Empty the processing queue. This will consume all the unconsumed packets and they will be handled
// This has to be done before we call DisconnectInternal in order for all packets to be processed.
- if (_processingQueue != null)
- {
- EmptyPacketProcessingQueue();
+ if (_processingQueue != null)
+ {
+ EmptyPacketProcessingQueue();
}
-
- // Disconnect all clients. This will send all the finals
+
+ // Disconnect all clients. This will send all the finals
for (Connection connection = _headConnection; connection != null; connection = connection.NextConnection)
{
connection.DisconnectInternal(true, false);
- }
-
+ }
+
// Flush the simulator. Do this last to prevent any last packets sent by the connections to be dropped.
- if (Simulator != null)
- {
- Simulator.Flush();
- }
- }
+ if (Simulator != null)
+ {
+ Simulator.Flush();
+ }
+ }
}
///
/// Shuts the socket down. This will clear the UserQueue which means Poll will not return any elements.
/// If you want the final packets. Call Stop, then Poll, then Shutdown.
///
- public void Shutdown()
+ public void Shutdown()
{
- lock (_stateLock)
- {
- if (!IsInitialized)
- {
- throw new InvalidOperationException("Cannot shutdown a non initialized socket");
- }
-
- IsInitialized = false;
-
- if (IsRunning)
- {
- Stop();
- }
-
- // Release simulator
- Simulator = null;
-
- while (_userEventQueue != null && _userEventQueue.TryDequeue(out NetworkEvent networkEvent))
- {
- // Recycle all packets to prevent leak detection
- networkEvent.Recycle();
- }
-
- // Release user queue
- _userEventQueue = null;
-
- while (_processingQueue != null && _processingQueue.TryDequeue(out NetTuple packet))
- {
- // Dealloc all the pending memory to prevent leak detection
- MemoryManager.DeAlloc(packet.Item1);
- }
-
- // Release processing queue
- _processingQueue = null;
-
- // Release IV cache
- _challengeInitializationVectors = null;
-
- // Release channel pool
- ChannelPool = null;
-
- if (_ipv4Socket != null)
- {
- // Close socket
+ lock (_stateLock)
+ {
+ if (!IsInitialized)
+ {
+ throw new InvalidOperationException("Cannot shutdown a non initialized socket");
+ }
+
+ IsInitialized = false;
+
+ if (IsRunning)
+ {
+ Stop();
+ }
+
+ // Release simulator
+ Simulator = null;
+
+ while (_userEventQueue != null && _userEventQueue.TryDequeue(out NetworkEvent networkEvent))
+ {
+ // Recycle all packets to prevent leak detection
+ networkEvent.Recycle();
+ }
+
+ // Release user queue
+ _userEventQueue = null;
+
+ while (_processingQueue != null && _processingQueue.TryDequeue(out NetTuple packet))
+ {
+ // Dealloc all the pending memory to prevent leak detection
+ MemoryManager.DeAlloc(packet.Item1);
+ }
+
+ // Release processing queue
+ _processingQueue = null;
+
+ // Release IV cache
+ _challengeInitializationVectors = null;
+
+ // Release channel pool
+ ChannelPool = null;
+
+ if (_ipv4Socket != null)
+ {
+ // Close socket
_ipv4Socket.Close();
- _ipv4Socket = null;
+ _ipv4Socket = null;
}
- if (_ipv6Socket != null)
- {
- // Close socket
+ if (_ipv6Socket != null)
+ {
+ // Close socket
_ipv6Socket.Close();
- _ipv6Socket = null;
- }
-
- // Release ALL memory to GC safely. If this is not done the MemoryManager will see it as a leak
- MemoryManager.Release();
+ _ipv6Socket = null;
+ }
+
+ // Release ALL memory to GC safely. If this is not done the MemoryManager will see it as a leak
+ MemoryManager.Release();
}
}
-
+
private bool Bind(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool ipv6Dual)
{
// Create IPv4 UDP Socket
_ipv4Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// Setup IPv4 Socket and properly bind it to the OS
- if (!SetupAndBind(_ipv4Socket, new IPEndPoint(addressIPv4, port)))
+ if (!SetupAndBind(_ipv4Socket, new IPEndPoint(addressIPv4, port)))
{
- // Failed to bind socket
- return false;
- }
+ // Failed to bind socket
+ return false;
+ }
int ipv4LocalPort = ((IPEndPoint)_ipv4Socket.LocalEndPoint).Port;
- if (!ipv6Dual || !SupportsIPv6)
+ if (!ipv6Dual || !SupportsIPv6)
{
- // Dont use IPv6 dual mode
- return true;
- }
+ // Dont use IPv6 dual mode
+ return true;
+ }
// Create IPv6 UDP Socket
- _ipv6Socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
-
+ _ipv6Socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
+
// Setup IPv6 socket and bind it to the same port as the IPv4 socket was bound to.
- // Ignore if it fails
+ // Ignore if it fails
SetupAndBind(_ipv6Socket, new IPEndPoint(addressIPv6, ipv4LocalPort));
return true;
@@ -536,67 +542,67 @@ private bool SetupAndBind(Socket socket, IPEndPoint endpoint)
// Dont fragment and broadcasting is only supported on IPv4
if (socket.AddressFamily == AddressFamily.InterNetwork)
{
- try
- {
- socket.DontFragment = true;
+ try
+ {
+ socket.DontFragment = true;
}
catch (SocketException e)
{
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Failed to enable DontFragment: " + e);
- // This shouldnt happen when the OS supports it.
- // This is used for path MTU to do application level fragmentation
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Failed to enable DontFragment: " + e);
+ // This shouldnt happen when the OS supports it.
+ // This is used for path MTU to do application level fragmentation
}
- try
- {
- socket.EnableBroadcast = true;
+ try
+ {
+ socket.EnableBroadcast = true;
}
catch (SocketException e)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Failed to enable broadcasting: " + e);
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Failed to enable broadcasting: " + e);
}
}
- try
- {
- // Set the .NET buffer sizes. Defaults to 1 megabyte each
- socket.ReceiveBufferSize = Constants.RECEIVE_SOCKET_BUFFER_SIZE;
- socket.SendBufferSize = Constants.SEND_SOCKET_BUFFER_SIZE;
+ try
+ {
+ // Set the .NET buffer sizes. Defaults to 1 megabyte each
+ socket.ReceiveBufferSize = Constants.RECEIVE_SOCKET_BUFFER_SIZE;
+ socket.SendBufferSize = Constants.SEND_SOCKET_BUFFER_SIZE;
+ }
+ catch (Exception e)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Failed to set socket buffer size: " + e);
}
- catch (Exception e)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Failed to set socket buffer size: " + e);
- }
-
- try
- {
- const uint IOC_IN = 0x80000000;
- const uint IOC_VENDOR = 0x18000000;
+
+ try
+ {
+ const uint IOC_IN = 0x80000000;
+ const uint IOC_VENDOR = 0x18000000;
const uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
- unchecked
- {
- socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { 0 }, null);
- }
- }
- catch (Exception e)
- {
- // Ignore error when SIO_UDP_CONNRESET is not supported
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Failed to set SIO_UDP_CONNRESET: " + e);
- }
-
- try
- {
- socket.Ttl = (short)Constants.SOCKET_PACKET_TTL;
- }
- catch (Exception e)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Failed to set TTL: " + e);
+ unchecked
+ {
+ socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { 0 }, null);
+ }
+ }
+ catch (Exception e)
+ {
+ // Ignore error when SIO_UDP_CONNRESET is not supported
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Failed to set SIO_UDP_CONNRESET: " + e);
+ }
+
+ try
+ {
+ socket.Ttl = (short)Constants.SOCKET_PACKET_TTL;
+ }
+ catch (Exception e)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Failed to set TTL: " + e);
}
try
- {
- // Bind the socket to the OS
+ {
+ // Bind the socket to the OS
socket.Bind(endpoint);
}
catch (SocketException bindException)
@@ -605,36 +611,36 @@ private bool SetupAndBind(Socket socket, IPEndPoint endpoint)
{
// IPv6 bind fix
case SocketError.AddressAlreadyInUse:
- {
- if (socket.AddressFamily == AddressFamily.InterNetworkV6)
- {
- try
- {
- socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, true);
- socket.Bind(endpoint);
- }
- catch (SocketException e)
+ {
+ if (socket.AddressFamily == AddressFamily.InterNetworkV6)
+ {
+ try
+ {
+ socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, true);
+ socket.Bind(endpoint);
+ }
+ catch (SocketException e)
{
- if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Socket bind failed after setting dual mode with exception: " + e);
- return false;
+ if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Socket bind failed after setting dual mode with exception: " + e);
+ return false;
}
-
- return true;
- }
+
+ return true;
+ }
}
break;
// Fixes Unity exception for iOS (requires IPv6 but the runtime throws)
case SocketError.AddressFamilyNotSupported:
- {
- return true;
+ {
+ return true;
}
- }
-
+ }
+
if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Socket bind with exception: " + bindException);
return false;
}
- return true;
+ return true;
}
///
@@ -642,17 +648,17 @@ private bool SetupAndBind(Socket socket, IPEndPoint endpoint)
///
/// Payload.
/// Endpoint.
- public bool SendUnconnected(ArraySegment payload, IPEndPoint endpoint)
- {
+ public bool SendUnconnected(ArraySegment payload, IPEndPoint endpoint)
+ {
if (payload.Count > Config.MinimumMTU)
{
if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Tried to send unconnected message that was too large. [Size=" + payload.Count + "] [MaxMessageSize=" + Config.MaxFragments + "]");
return false;
- }
-
- // TODO: If payload has extra space. No need to realloc
-
- // Allocate the memory
+ }
+
+ // TODO: If payload has extra space. No need to realloc
+
+ // Allocate the memory
HeapMemory memory = MemoryManager.AllocHeapMemory((uint)payload.Count + 1);
// Write headers
@@ -661,15 +667,15 @@ public bool SendUnconnected(ArraySegment payload, IPEndPoint endpoint)
// Copy payload to borrowed memory
Buffer.BlockCopy(payload.Array, payload.Offset, memory.Buffer, 1, payload.Count);
- // Send the packet
+ // Send the packet
bool success = SendRaw(endpoint, new ArraySegment(memory.Buffer, (int)memory.VirtualOffset, (int)memory.VirtualCount));
// Release memory
MemoryManager.DeAlloc(memory);
- return success;
- }
-
+ return success;
+ }
+
///
/// Sends a broadcast packet to all local devices.
///
@@ -677,7 +683,7 @@ public bool SendUnconnected(ArraySegment payload, IPEndPoint endpoint)
/// The payload to send.
/// The port to send the broadcast to.
public bool SendBroadcast(ArraySegment payload, int port)
- {
+ {
if (payload.Count > Config.MinimumMTU)
{
if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Tried to send broadcast message that was too large. [Size=" + payload.Count + "] [MaxMessageSize=" + Config.MaxFragments + "]");
@@ -713,13 +719,13 @@ public bool SendBroadcast(ArraySegment payload, int port)
catch (Exception e)
{
if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Error when sending broadcast: " + e);
- }
-
- // Release memory
+ }
+
+ // Release memory
MemoryManager.DeAlloc(memory);
return broadcastSuccess || multicastSuccess;
- }
+ }
///
/// Starts a connection to a endpoint.
@@ -728,48 +734,48 @@ public bool SendBroadcast(ArraySegment payload, int port)
/// Note that this call will block the network thread and will cause slowdowns. Use ConnectLater for non blocking IO
///
/// The pending connection.
- /// The endpoint to connect to.
+ /// The endpoint to connect to.
public Connection Connect(EndPoint endpoint)
{
- if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogInfo("Attempting to connect (now) to " + endpoint);
+ if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogInfo("Attempting to connect (now) to " + endpoint);
ulong unixTimestamp = 0;
ulong iv = 0;
ulong counter = 0;
-
- if (Config.TimeBasedConnectionChallenge)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Using time based connection challenge. Calculating with difficulty " + Config.ChallengeDifficulty);
-
- // Current unix time
- unixTimestamp = (ulong)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
-
- // Generate IV
- iv = RandomProvider.GetRandomULong();
-
- // Find collision
- ulong hash;
- do
- {
- // Attempt to calculate a new hash collision
- hash = HashProvider.GetStableHash64(unixTimestamp, counter, iv);
-
- // Increment counter
- counter++;
- }
- while ((hash << (sizeof(ulong) * 8 - Config.ChallengeDifficulty)) >> (sizeof(ulong) * 8 - Config.ChallengeDifficulty) != 0);
-
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Found hash collision after " + counter + " attempts. [Counter=" + (counter - 1) + "] [IV=" + iv + "] [Time=" + unixTimestamp + "] [Hash=" + hash + "]");
-
- // Make counter 1 less
- counter--;
+
+ if (Config.TimeBasedConnectionChallenge)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Using time based connection challenge. Calculating with difficulty " + Config.ChallengeDifficulty);
+
+ // Current unix time
+ unixTimestamp = (ulong)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
+
+ // Generate IV
+ iv = RandomProvider.GetRandomULong();
+
+ // Find collision
+ ulong hash;
+ do
+ {
+ // Attempt to calculate a new hash collision
+ hash = HashProvider.GetStableHash64(unixTimestamp, counter, iv);
+
+ // Increment counter
+ counter++;
+ }
+ while ((hash << (sizeof(ulong) * 8 - Config.ChallengeDifficulty)) >> (sizeof(ulong) * 8 - Config.ChallengeDifficulty) != 0);
+
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Found hash collision after " + counter + " attempts. [Counter=" + (counter - 1) + "] [IV=" + iv + "] [Time=" + unixTimestamp + "] [Hash=" + hash + "]");
+
+ // Make counter 1 less
+ counter--;
}
return ConnectInternal(endpoint, unixTimestamp, counter, iv);
}
- private Connection ConnectInternal(EndPoint endpoint, ulong unixTimestamp, ulong counter, ulong iv)
- {
+ private Connection ConnectInternal(EndPoint endpoint, ulong unixTimestamp, ulong counter, ulong iv)
+ {
Connection connection = AddNewConnection(endpoint, ConnectionState.RequestingConnection);
if (connection != null)
@@ -801,18 +807,18 @@ private Connection ConnectInternal(EndPoint endpoint, ulong unixTimestamp, ulong
connection.PreConnectionChallengeTimestamp = unixTimestamp;
// Write the current unix time
- for (byte i = 0; i < sizeof(ulong); i++) memory.Buffer[1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + i] = ((byte)(unixTimestamp >> (i * 8)));
-
- // Save for resends
- connection.PreConnectionChallengeCounter = counter;
-
- // Write counter
+ for (byte i = 0; i < sizeof(ulong); i++) memory.Buffer[1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + i] = ((byte)(unixTimestamp >> (i * 8)));
+
+ // Save for resends
+ connection.PreConnectionChallengeCounter = counter;
+
+ // Write counter
for (byte i = 0; i < sizeof(ulong); i++) memory.Buffer[1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + i] = ((byte)(counter >> (i * 8)));
// Save for resends
- connection.PreConnectionChallengeIV = iv;
-
- // Write IV
+ connection.PreConnectionChallengeIV = iv;
+
+ // Write IV
for (byte i = 0; i < sizeof(ulong); i++) memory.Buffer[1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + i] = ((byte)(iv >> (i * 8)));
// Mark it as solved (for resending)
@@ -832,49 +838,38 @@ private Connection ConnectInternal(EndPoint endpoint, ulong unixTimestamp, ulong
if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Failed to allocate connection to " + endpoint);
}
- return connection;
+ return connection;
}
- private void StartNetworkLogic()
+ private void StartNetworkLogic()
{
- Stopwatch logicWatch = new Stopwatch();
- logicWatch.Start();
-
- while (IsRunning)
+ while (IsRunning)
{
- try
- {
- if (Simulator != null)
- {
- Simulator.RunLoop();
- }
-
- int elapsed = (int)logicWatch.ElapsedMilliseconds;
-
- for (Connection connection = _headConnection; connection != null; connection = connection.NextConnection)
- {
- connection.Update();
- }
-
- int sleepMs = (Config.LogicDelay - (((int)logicWatch.ElapsedMilliseconds) - elapsed));
-
- logicWatch.Reset();
- logicWatch.Start();
-
- if (sleepMs > 0)
- {
- Thread.Sleep(sleepMs);
+ try
+ {
+ FrameSyncronizationEvent.WaitOne();
+
+ if (Simulator != null)
+ {
+ Simulator.RunLoop();
+ }
+
+ int elapsed = (int)logicWatch.ElapsedMilliseconds;
+
+ for (Connection connection = _headConnection; connection != null; connection = connection.NextConnection)
+ {
+ connection.Update();
}
}
catch (Exception e)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Error when running internal loop: " + e);
- }
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Error when running internal loop: " + e);
+ }
}
- logicWatch.Stop();
- }
-
+ logicWatch.Stop();
+ }
+
private readonly EndPoint _fromIPv4Endpoint = new IPEndPoint(IPAddress.Any, 0);
private readonly EndPoint _fromIPv6Endpoint = new IPEndPoint(IPAddress.IPv6Any, 0);
@@ -907,51 +902,51 @@ private void StartSocketLogic()
try
{
// Get a endpoint reference
- EndPoint _endpoint = _selectSockets[i].AddressFamily == AddressFamily.InterNetwork ? _fromIPv4Endpoint : _selectSockets[i].AddressFamily == AddressFamily.InterNetworkV6 ? _fromIPv6Endpoint : null;
-
+ EndPoint _endpoint = _selectSockets[i].AddressFamily == AddressFamily.InterNetwork ? _fromIPv4Endpoint : _selectSockets[i].AddressFamily == AddressFamily.InterNetworkV6 ? _fromIPv6Endpoint : null;
+
byte[] receiveBuffer;
int receiveSize;
HeapMemory memory = null;
- if (Config.ProcessingThreads > 0)
- {
- // Alloc memory for the packet. Alloc max MTU
+ if (Config.ProcessingThreads > 0)
+ {
+ // Alloc memory for the packet. Alloc max MTU
memory = MemoryManager.AllocHeapMemory((uint)Config.MaximumMTU);
receiveSize = (int)memory.VirtualCount;
- receiveBuffer = memory.Buffer;
+ receiveBuffer = memory.Buffer;
}
- else
- {
+ else
+ {
receiveBuffer = _incomingBuffer;
- receiveSize = _incomingBuffer.Length;
+ receiveSize = _incomingBuffer.Length;
}
// Receive from socket
int size = _selectSockets[i].ReceiveFrom(receiveBuffer, 0, receiveSize, SocketFlags.None, ref _endpoint);
- if (Config.ProcessingThreads > 0)
+ if (Config.ProcessingThreads > 0)
{
// Set the size to prevent reading to end
memory.VirtualCount = (uint)size;
- // Process off thread
- _processingQueue.Enqueue(new NetTuple(memory, _endpoint));
+ // Process off thread
+ _processingQueue.Enqueue(new NetTuple(memory, _endpoint));
}
- else
+ else
{
- // Process on thread
- HandlePacket(new ArraySegment(receiveBuffer, 0, size), _endpoint, true);
+ // Process on thread
+ HandlePacket(new ArraySegment(receiveBuffer, 0, size), _endpoint, true);
}
}
- catch (SocketException e)
+ catch (SocketException e)
{
// TODO: Handle ConnectionReset and ConnectionRefused for Connect? More responsive?
// ConnectionReset and ConnectionRefused are triggered by local ICMP packets. Indicates remote is not present.
- // MessageSize is triggered by remote ICMP. Usually during path MTU
- if (e.SocketErrorCode != SocketError.ConnectionReset && e.SocketErrorCode != SocketError.ConnectionRefused && e.SocketErrorCode != SocketError.TimedOut && e.SocketErrorCode != SocketError.MessageSize)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Error when receiving from socket: " + e);
- }
+ // MessageSize is triggered by remote ICMP. Usually during path MTU
+ if (e.SocketErrorCode != SocketError.ConnectionReset && e.SocketErrorCode != SocketError.ConnectionRefused && e.SocketErrorCode != SocketError.TimedOut && e.SocketErrorCode != SocketError.MessageSize)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Error when receiving from socket: " + e);
+ }
}
catch (Exception e)
{
@@ -960,10 +955,10 @@ private void StartSocketLogic()
}
// If we have no logic thread. Run logic on receive thread
- if (Config.LogicThreads <= 0 && (NetTime.Now - _lastLogicRun).TotalMilliseconds > Config.LogicDelay)
- {
+ if (Config.LogicThreads <= 0 && (NetTime.Now - _lastLogicRun).TotalMilliseconds > Config.LogicDelay)
+ {
// Run logic
-
+
if (Simulator != null)
{
Simulator.RunLoop();
@@ -972,296 +967,296 @@ private void StartSocketLogic()
for (Connection connection = _headConnection; connection != null; connection = connection.NextConnection)
{
connection.Update();
- }
+ }
}
}
}
- private void StartPacketProcessing()
- {
- while (IsRunning)
- {
- EmptyPacketProcessingQueue();
- }
+ private void StartPacketProcessing()
+ {
+ while (IsRunning)
+ {
+ EmptyPacketProcessingQueue();
+ }
}
- private void EmptyPacketProcessingQueue()
- {
- try
- {
- while (_processingQueue.TryDequeue(out NetTuple packet))
- {
- // Process packet
- HandlePacket(new ArraySegment(packet.Item1.Buffer, (int)packet.Item1.VirtualOffset, (int)packet.Item1.VirtualCount), packet.Item2, true);
-
- // Dealloc the memory
- MemoryManager.DeAlloc(packet.Item1);
- }
- }
- catch (Exception e)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Error when processing packet: " + e);
- }
+ private void EmptyPacketProcessingQueue()
+ {
+ try
+ {
+ while (_processingQueue.TryDequeue(out NetTuple packet))
+ {
+ // Process packet
+ HandlePacket(new ArraySegment(packet.Item1.Buffer, (int)packet.Item1.VirtualOffset, (int)packet.Item1.VirtualCount), packet.Item2, true);
+
+ // Dealloc the memory
+ MemoryManager.DeAlloc(packet.Item1);
+ }
+ }
+ catch (Exception e)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Error when processing packet: " + e);
+ }
}
///
/// Polls the RuffleSocket for incoming events about connections.
///
/// The poll result.
- public NetworkEvent Poll()
- {
- if (_userEventQueue.TryDequeue(out NetworkEvent @event))
+ public NetworkEvent Poll()
+ {
+ if (_userEventQueue.TryDequeue(out NetworkEvent @event))
+ {
+ return @event;
+ }
+
+ return new NetworkEvent()
{
- return @event;
- }
-
- return new NetworkEvent()
- {
- Connection = null,
- Socket = this,
- Data = new ArraySegment(),
- AllowUserRecycle = false,
- InternalMemory = null,
+ Connection = null,
+ Socket = this,
+ Data = new ArraySegment(),
+ AllowUserRecycle = false,
+ InternalMemory = null,
Type = NetworkEventType.Nothing,
ChannelId = 0,
- SocketReceiveTime = NetTime.Now,
+ SocketReceiveTime = NetTime.Now,
MemoryManager = MemoryManager,
- EndPoint = null
- };
+ EndPoint = null
+ };
}
- internal bool SendRaw(EndPoint endpoint, ArraySegment payload)
+ internal bool SendRaw(EndPoint endpoint, ArraySegment payload)
{
- try
- {
- if (endpoint.AddressFamily == AddressFamily.InterNetwork)
- {
- return _ipv4Socket.SendTo(payload.Array, payload.Offset, payload.Count, SocketFlags.None, endpoint) > 0;
- }
- else if (endpoint.AddressFamily == AddressFamily.InterNetworkV6)
- {
- return _ipv6Socket.SendTo(payload.Array, payload.Offset, payload.Count, SocketFlags.None, endpoint) > 0;
- }
+ try
+ {
+ if (endpoint.AddressFamily == AddressFamily.InterNetwork)
+ {
+ return _ipv4Socket.SendTo(payload.Array, payload.Offset, payload.Count, SocketFlags.None, endpoint) > 0;
+ }
+ else if (endpoint.AddressFamily == AddressFamily.InterNetworkV6)
+ {
+ return _ipv6Socket.SendTo(payload.Array, payload.Offset, payload.Count, SocketFlags.None, endpoint) > 0;
+ }
}
- catch (SocketException e)
- {
- // MessageSize is ignored. This happens during path MTU
-
- if (e.SocketErrorCode != SocketError.MessageSize)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Error when sending through socket: " + e);
- }
+ catch (SocketException e)
+ {
+ // MessageSize is ignored. This happens during path MTU
+
+ if (e.SocketErrorCode != SocketError.MessageSize)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Error when sending through socket: " + e);
+ }
}
catch (Exception e)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Error when sending through socket: " + e);
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Error when sending through socket: " + e);
}
- return false;
+ return false;
}
- private readonly List> _mergeSegmentResults = new List>();
- internal void HandlePacket(ArraySegment payload, EndPoint endpoint, bool allowMergeUnpack)
- {
- if (payload.Count < 1)
- {
+ private readonly List> _mergeSegmentResults = new List>();
+ internal void HandlePacket(ArraySegment payload, EndPoint endpoint, bool allowMergeUnpack)
+ {
+ if (payload.Count < 1)
+ {
// Invalid size
- if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogError("Got packet of size " + payload.Count + " from " + endpoint + ". Packet is too small");
- return;
+ if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogError("Got packet of size " + payload.Count + " from " + endpoint + ". Packet is too small");
+ return;
}
-
+
// Unpack header, dont cast to MessageType enum for safety
- HeaderPacker.Unpack(payload.Array[payload.Offset], out MessageType messageType);
-
+ HeaderPacker.Unpack(payload.Array[payload.Offset], out MessageType messageType);
+
if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Unpacked packet. [MessageType=" + (MessageType)messageType + "]");
-
- switch (messageType)
+
+ switch (messageType)
{
case MessageType.Merge:
- {
- if (!Config.EnablePacketMerging)
- {
- // Big missmatch here.
- if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Packet was merged but packet merging was disabled. Skipping merge packet");
- return;
- }
-
- if (!allowMergeUnpack)
- {
- if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Packet was double merged. Skipping nested merge packet");
- return;
+ {
+ if (!Config.EnablePacketMerging)
+ {
+ // Big missmatch here.
+ if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Packet was merged but packet merging was disabled. Skipping merge packet");
+ return;
+ }
+
+ if (!allowMergeUnpack)
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Packet was double merged. Skipping nested merge packet");
+ return;
}
Connection connection = GetConnection(endpoint);
- if (connection != null)
+ if (connection != null)
{
- // Unpack the merged packet
+ // Unpack the merged packet
MessageMerger.Unpack(new ArraySegment(payload.Array, payload.Offset + 1, payload.Count - 1), _mergeSegmentResults);
- if (_mergeSegmentResults != null)
- {
- for (int i = 0; i < _mergeSegmentResults.Count; i++)
- {
- // Handle the segment
- HandlePacket(_mergeSegmentResults[i], endpoint, false);
- }
- }
- }
+ if (_mergeSegmentResults != null)
+ {
+ for (int i = 0; i < _mergeSegmentResults.Count; i++)
+ {
+ // Handle the segment
+ HandlePacket(_mergeSegmentResults[i], endpoint, false);
+ }
+ }
+ }
}
- break;
- case MessageType.ConnectionRequest:
+ break;
+ case MessageType.ConnectionRequest:
{
- if (payload.Count < Config.AmplificationPreventionHandshakePadding || payload.Count < 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length)
+ if (payload.Count < Config.AmplificationPreventionHandshakePadding || payload.Count < 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length)
{
- // This message is too small. They might be trying to use us for amplification.
- return;
+ // This message is too small. They might be trying to use us for amplification.
+ return;
}
- for (int i = 0; i < Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length; i++)
+ for (int i = 0; i < Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length; i++)
{
- if (payload.Array[payload.Offset + 1 + i] != Constants.RUFFLES_PROTOCOL_IDENTIFICATION[i])
- {
- // The identification number did not match
- if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Connection request packet was filtered away. Identification did not match");
- return;
+ if (payload.Array[payload.Offset + 1 + i] != Constants.RUFFLES_PROTOCOL_IDENTIFICATION[i])
+ {
+ // The identification number did not match
+ if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Connection request packet was filtered away. Identification did not match");
+ return;
}
}
- if (Config.TimeBasedConnectionChallenge)
+ if (Config.TimeBasedConnectionChallenge)
{
- // Get the current unix time seconds
- ulong currentUnixTime = (ulong)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
-
- // Read the time they used
- ulong challengeUnixTime = (((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length]) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + 1] << 8) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + 2] << 16) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + 3] << 24) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + 4] << 32) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + 5] << 40) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + 6] << 48) |
+ // Get the current unix time seconds
+ ulong currentUnixTime = (ulong)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
+
+ // Read the time they used
+ ulong challengeUnixTime = (((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length]) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + 1] << 8) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + 2] << 16) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + 3] << 24) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + 4] << 32) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + 5] << 40) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + 6] << 48) |
((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + 7] << 56));
- // The seconds diff
- long secondsDiff = (long)currentUnixTime - (long)challengeUnixTime;
-
- if (secondsDiff > (long)Config.ConnectionChallengeTimeWindow || secondsDiff < -(long)Config.ConnectionChallengeTimeWindow)
- {
+ // The seconds diff
+ long secondsDiff = (long)currentUnixTime - (long)challengeUnixTime;
+
+ if (secondsDiff > (long)Config.ConnectionChallengeTimeWindow || secondsDiff < -(long)Config.ConnectionChallengeTimeWindow)
+ {
// Outside the allowed window
- if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogWarning("Client " + endpoint + " failed the connection request. They were outside of their allowed window. The diff was " + Math.Abs(secondsDiff) + " seconds");
- return;
- }
-
- // Read the counter they used to collide the hash
- ulong counter = (((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong)]) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 1] << 8) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 2] << 16) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 3] << 24) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 4] << 32) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 5] << 40) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 6] << 48) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 7] << 56));
-
- // Read the initialization vector they used
- ulong userIv = (((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2)]) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 1] << 8) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 2] << 16) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 3] << 24) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 4] << 32) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 5] << 40) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 6] << 48) |
- ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 7] << 56));
-
- lock (_challengeInitializationVectorsLock)
- {
- // Ensure they dont reuse a IV
- if (!_challengeInitializationVectors.TrySet(userIv))
- {
- // This IV is being reused.
- if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogWarning("Client " + endpoint + " failed the connection request. They were trying to reuse an IV");
- return;
- }
- }
-
- // Calculate the hash the user claims have a collision
- ulong claimedHash = HashProvider.GetStableHash64(challengeUnixTime, counter, userIv);
-
- // Check if the hash collides
- bool isCollided = ((claimedHash << (sizeof(ulong) * 8 - Config.ChallengeDifficulty)) >> (sizeof(ulong) * 8 - Config.ChallengeDifficulty)) == 0;
-
- if (!isCollided)
- {
- // They failed the challenge
- if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogWarning("Client " + endpoint + " failed the connection request. They submitted an invalid answer. [ClaimedHash=" + claimedHash + "] [Counter=" + counter + "] [IV=" + userIv + "] [Time=" + challengeUnixTime + "]");
- return;
- }
- }
-
+ if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogWarning("Client " + endpoint + " failed the connection request. They were outside of their allowed window. The diff was " + Math.Abs(secondsDiff) + " seconds");
+ return;
+ }
+
+ // Read the counter they used to collide the hash
+ ulong counter = (((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong)]) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 1] << 8) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 2] << 16) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 3] << 24) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 4] << 32) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 5] << 40) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 6] << 48) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + 7] << 56));
+
+ // Read the initialization vector they used
+ ulong userIv = (((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2)]) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 1] << 8) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 2] << 16) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 3] << 24) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 4] << 32) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 5] << 40) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 6] << 48) |
+ ((ulong)payload.Array[payload.Offset + 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + 7] << 56));
+
+ lock (_challengeInitializationVectorsLock)
+ {
+ // Ensure they dont reuse a IV
+ if (!_challengeInitializationVectors.TrySet(userIv))
+ {
+ // This IV is being reused.
+ if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogWarning("Client " + endpoint + " failed the connection request. They were trying to reuse an IV");
+ return;
+ }
+ }
+
+ // Calculate the hash the user claims have a collision
+ ulong claimedHash = HashProvider.GetStableHash64(challengeUnixTime, counter, userIv);
+
+ // Check if the hash collides
+ bool isCollided = ((claimedHash << (sizeof(ulong) * 8 - Config.ChallengeDifficulty)) >> (sizeof(ulong) * 8 - Config.ChallengeDifficulty)) == 0;
+
+ if (!isCollided)
+ {
+ // They failed the challenge
+ if (Logging.CurrentLogLevel <= LogLevel.Info) Logging.LogWarning("Client " + endpoint + " failed the connection request. They submitted an invalid answer. [ClaimedHash=" + claimedHash + "] [Counter=" + counter + "] [IV=" + userIv + "] [Time=" + challengeUnixTime + "]");
+ return;
+ }
+ }
+
if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Client " + endpoint + " is being challenged");
Connection connection = AddNewConnection(endpoint, ConnectionState.RequestingChallenge);
- if (connection != null)
- {
+ if (connection != null)
+ {
// This connection was successfully added as pending
// Send connection request
- connection.SendChallengeRequest();
+ connection.SendChallengeRequest();
}
- else
- {
- if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Client " + endpoint + " could not be challenged. Allocation failed");
- }
- }
- break;
+ else
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Client " + endpoint + " could not be challenged. Allocation failed");
+ }
+ }
+ break;
case MessageType.ChallengeRequest:
- {
- if (payload.Count < 10)
- {
- // The message is not large enough to contain all the data neccecary. Wierd server?
- if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogWarning("Server " + endpoint + " sent us a payload that was too small. Disconnecting");
- return;
+ {
+ if (payload.Count < 10)
+ {
+ // The message is not large enough to contain all the data neccecary. Wierd server?
+ if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogWarning("Server " + endpoint + " sent us a payload that was too small. Disconnecting");
+ return;
}
- Connection connection = GetConnection(endpoint);
-
- if (connection != null)
- {
- ulong challenge = (((ulong)payload.Array[payload.Offset + 1 + 0]) |
- ((ulong)payload.Array[payload.Offset + 1 + 1] << 8) |
- ((ulong)payload.Array[payload.Offset + 1 + 2] << 16) |
- ((ulong)payload.Array[payload.Offset + 1 + 3] << 24) |
- ((ulong)payload.Array[payload.Offset + 1 + 4] << 32) |
- ((ulong)payload.Array[payload.Offset + 1 + 5] << 40) |
- ((ulong)payload.Array[payload.Offset + 1 + 6] << 48) |
+ Connection connection = GetConnection(endpoint);
+
+ if (connection != null)
+ {
+ ulong challenge = (((ulong)payload.Array[payload.Offset + 1 + 0]) |
+ ((ulong)payload.Array[payload.Offset + 1 + 1] << 8) |
+ ((ulong)payload.Array[payload.Offset + 1 + 2] << 16) |
+ ((ulong)payload.Array[payload.Offset + 1 + 3] << 24) |
+ ((ulong)payload.Array[payload.Offset + 1 + 4] << 32) |
+ ((ulong)payload.Array[payload.Offset + 1 + 5] << 40) |
+ ((ulong)payload.Array[payload.Offset + 1 + 6] << 48) |
((ulong)payload.Array[payload.Offset + 1 + 7] << 56));
byte difficulty = payload.Array[payload.Offset + 1 + sizeof(ulong)];
- connection.HandleChallengeRequest(challenge, difficulty);
- }
+ connection.HandleChallengeRequest(challenge, difficulty);
+ }
}
- break;
+ break;
case MessageType.ChallengeResponse:
- {
+ {
if (payload.Count < Config.AmplificationPreventionHandshakePadding)
{
// This message is too small. They might be trying to use us for amplification
if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogWarning("Client " + endpoint + " sent a challenge response that was smaller than the amplification padding");
return;
- }
-
- if (payload.Count < 9)
- {
+ }
+
+ if (payload.Count < 9)
+ {
// The message is not large enough to contain all the data neccecary. Wierd client?
- if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogWarning("Client " + endpoint + " sent a challenge response that was too small to contain all the data");
- return;
+ if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogWarning("Client " + endpoint + " sent a challenge response that was too small to contain all the data");
+ return;
}
-
+
Connection connection = GetConnection(endpoint);
- if (connection != null)
+ if (connection != null)
{
ulong challengeResponse = (((ulong)payload.Array[payload.Offset + 1 + 0]) |
((ulong)payload.Array[payload.Offset + 1 + 1] << 8) |
@@ -1270,149 +1265,149 @@ internal void HandlePacket(ArraySegment payload, EndPoint endpoint, bool a
((ulong)payload.Array[payload.Offset + 1 + 4] << 32) |
((ulong)payload.Array[payload.Offset + 1 + 5] << 40) |
((ulong)payload.Array[payload.Offset + 1 + 6] << 48) |
- ((ulong)payload.Array[payload.Offset + 1 + 7] << 56));
+ ((ulong)payload.Array[payload.Offset + 1 + 7] << 56));
- connection.HandleChallengeResponse(challengeResponse);
- }
+ connection.HandleChallengeResponse(challengeResponse);
+ }
}
- break;
+ break;
case MessageType.Hail:
{
Connection connection = GetConnection(endpoint);
if (connection != null)
{
- if (payload.Count < 2)
- {
- // Invalid size.
- if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogError("Client " + endpoint + " sent a payload that was too small");
- return;
- }
-
- // Read the amount of channels
+ if (payload.Count < 2)
+ {
+ // Invalid size.
+ if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogError("Client " + endpoint + " sent a payload that was too small");
+ return;
+ }
+
+ // Read the amount of channels
byte channelCount = payload.Array[payload.Offset + 1];
- if (channelCount > Constants.MAX_CHANNELS)
+ if (channelCount > Constants.MAX_CHANNELS)
{
- // Too many channels
+ // Too many channels
if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogError("Client " + endpoint + " more channels than allowed");
- return;
+ return;
}
- if (payload.Count < channelCount + 2)
- {
- // Invalid size.
- if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogError("Client " + endpoint + " sent a payload that was too small");
- return;
+ if (payload.Count < channelCount + 2)
+ {
+ // Invalid size.
+ if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogError("Client " + endpoint + " sent a payload that was too small");
+ return;
}
// Read the types and validate them (before alloc)
- for (byte i = 0; i < channelCount; i++)
+ for (byte i = 0; i < channelCount; i++)
{
byte channelType = payload.Array[payload.Offset + 2 + i];
- if (!ChannelTypeUtils.IsValidChannelType(channelType))
- {
- // Unknown channel type. Disconnect.
- if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogError("Client " + endpoint + " sent an invalid ChannelType");
- return;
+ if (!ChannelTypeUtils.IsValidChannelType(channelType))
+ {
+ // Unknown channel type. Disconnect.
+ if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogError("Client " + endpoint + " sent an invalid ChannelType");
+ return;
}
}
- connection.HandleHail(new ArraySegment(payload.Array, payload.Offset + 2, payload.Array[payload.Offset + 1]));
+ connection.HandleHail(new ArraySegment(payload.Array, payload.Offset + 2, payload.Array[payload.Offset + 1]));
}
}
- break;
+ break;
case MessageType.HailConfirmed:
- {
+ {
Connection connection = GetConnection(endpoint);
- if (connection != null)
+ if (connection != null)
{
- connection.HandleHailConfirmed();
- }
+ connection.HandleHailConfirmed();
+ }
}
- break;
+ break;
case MessageType.Heartbeat:
{
- if (!Config.EnableHeartbeats)
+ if (!Config.EnableHeartbeats)
{
// This is a missmatch.
- if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogWarning("Heartbeat received from " + endpoint + " but the we do not have heartbeats enabled. Configuration missmatch?");
- return;
+ if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogWarning("Heartbeat received from " + endpoint + " but the we do not have heartbeats enabled. Configuration missmatch?");
+ return;
}
-
+
Connection connection = GetConnection(endpoint);
- if (connection != null)
+ if (connection != null)
{
// Heartbeats are sequenced to not properly handle network congestion
- connection.HandleHeartbeat(new ArraySegment(payload.Array, payload.Offset + 1, payload.Count - 1));
- }
+ connection.HandleHeartbeat(new ArraySegment(payload.Array, payload.Offset + 1, payload.Count - 1));
+ }
}
- break;
+ break;
case MessageType.Data:
- {
+ {
Connection connection = GetConnection(endpoint);
- if (connection != null)
+ if (connection != null)
{
- connection.HandleChannelData(new ArraySegment(payload.Array, payload.Offset + 1, payload.Count - 1));
- }
+ connection.HandleChannelData(new ArraySegment(payload.Array, payload.Offset + 1, payload.Count - 1));
+ }
}
- break;
+ break;
case MessageType.Ack:
- {
+ {
Connection connection = GetConnection(endpoint);
if (connection != null)
- {
+ {
connection.HandleChannelAck(new ArraySegment(payload.Array, payload.Offset + 1, payload.Count - 1));
- }
+ }
}
- break;
+ break;
case MessageType.Disconnect:
- {
+ {
Connection connection = GetConnection(endpoint);
- if (connection != null)
- {
- connection.DisconnectInternal(false, false);
- }
+ if (connection != null)
+ {
+ connection.DisconnectInternal(false, false);
+ }
}
- break;
+ break;
case MessageType.MTURequest:
- {
- if (!Config.EnablePathMTU)
- {
+ {
+ if (!Config.EnablePathMTU)
+ {
if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogWarning("Got MTURequest message but SocketConfig.EnablePathMTU is disabled.");
- return;
- }
-
- Connection connection = GetConnection(endpoint);
-
- if (connection != null)
- {
- connection.HandleMTURequest((uint)payload.Count);
- }
+ return;
+ }
+
+ Connection connection = GetConnection(endpoint);
+
+ if (connection != null)
+ {
+ connection.HandleMTURequest((uint)payload.Count);
+ }
}
- break;
+ break;
case MessageType.MTUResponse:
- {
+ {
if (!Config.EnablePathMTU)
- {
+ {
if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogWarning("Got MTUResponse message but SocketConfig.EnablePathMTU is disabled.");
- return;
+ return;
}
-
- Connection connection = GetConnection(endpoint);
-
- if (connection != null)
+
+ Connection connection = GetConnection(endpoint);
+
+ if (connection != null)
{
- connection.HandleMTUResponse((uint)payload.Count);
- }
+ connection.HandleMTUResponse((uint)payload.Count);
+ }
}
- break;
+ break;
case MessageType.UnconnectedData:
{
if (!Config.AllowUnconnectedMessages)
@@ -1442,16 +1437,16 @@ internal void HandlePacket(ArraySegment payload, EndPoint endpoint, bool a
EndPoint = endpoint
});
}
- break;
+ break;
case MessageType.Broadcast:
- {
+ {
if (!Config.AllowBroadcasts)
{
if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogWarning("Got broadcast message but SocketConfig.AllowBroadcasts is false.");
return;
- }
-
- // Alloc memory that can be borrowed to userspace
+ }
+
+ // Alloc memory that can be borrowed to userspace
HeapMemory memory = MemoryManager.AllocHeapMemory((uint)payload.Count - 1);
// Copy payload to borrowed memory
@@ -1470,20 +1465,20 @@ internal void HandlePacket(ArraySegment payload, EndPoint endpoint, bool a
ChannelId = 0,
MemoryManager = MemoryManager,
EndPoint = endpoint
- });
+ });
}
break;
-
- }
- }
-
+
+ }
+ }
+
internal Connection GetConnection(EndPoint endpoint)
{
// Lock to prevent grabbing a half dead connection
_connectionsLock.EnterReadLock();
- try
- {
+ try
+ {
if (_addressConnectionLookup.ContainsKey(endpoint))
{
return _addressConnectionLookup[endpoint];
@@ -1491,43 +1486,43 @@ internal Connection GetConnection(EndPoint endpoint)
else
{
return null;
- }
+ }
}
- finally
- {
- _connectionsLock.ExitReadLock();
+ finally
+ {
+ _connectionsLock.ExitReadLock();
}
}
- internal void RemoveConnection(Connection connection)
- {
- // Lock when removing the connection to prevent another thread grabbing it before its fully dead.
+ internal void RemoveConnection(Connection connection)
+ {
+ // Lock when removing the connection to prevent another thread grabbing it before its fully dead.
_connectionsLock.EnterWriteLock();
- try
- {
- // Remove lookup
- if (_addressConnectionLookup.Remove(connection.EndPoint))
- {
- if (connection == _headConnection)
- {
- _headConnection = _headConnection.NextConnection;
+ try
+ {
+ // Remove lookup
+ if (_addressConnectionLookup.Remove(connection.EndPoint))
+ {
+ if (connection == _headConnection)
+ {
+ _headConnection = _headConnection.NextConnection;
}
- if (connection.PreviousConnection != null)
- {
- connection.PreviousConnection.NextConnection = connection.NextConnection;
+ if (connection.PreviousConnection != null)
+ {
+ connection.PreviousConnection.NextConnection = connection.NextConnection;
}
- if (connection.NextConnection != null)
- {
- connection.NextConnection.PreviousConnection = connection.PreviousConnection;
+ if (connection.NextConnection != null)
+ {
+ connection.NextConnection.PreviousConnection = connection.PreviousConnection;
}
connection.PreviousConnection = null;
- if (((ulong)_releasedConnectionIds.Count + 1) == _connectionIdCounter)
- {
+ if (((ulong)_releasedConnectionIds.Count + 1) == _connectionIdCounter)
+ {
// If the counter is equal to the amount of released + 1. This means all have been released and we can safely clear the queue and reset the counter.
// This is a meassure to save some memory.
// TODO: Improve: If 100 connections join, the last 99 leave. The queue will have 99 entries and the counter will be 100. It would be better if the counter was decreased to 1 and the 99 entries dropped.
@@ -1535,36 +1530,36 @@ internal void RemoveConnection(Connection connection)
_connectionIdCounter = 0;
_releasedConnectionIds.Clear();
}
- else if (_connectionIdCounter == connection.Id + 1)
- {
+ else if (_connectionIdCounter == connection.Id + 1)
+ {
// This was the last connection to be added. Instead of enqueueing, we can just decrease the counter
- _connectionIdCounter--;
+ _connectionIdCounter--;
+ }
+ else
+ {
+ // Add the released connectionId
+ _releasedConnectionIds.Enqueue(connection.Id);
}
- else
- {
- // Add the released connectionId
- _releasedConnectionIds.Enqueue(connection.Id);
- }
}
- else
- {
- if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Could not find endpoint to remove: " + connection.EndPoint);
- }
- }
- finally
- {
- _connectionsLock.ExitWriteLock();
- }
- }
-
- internal Connection AddNewConnection(EndPoint endpoint, ConnectionState state)
- {
+ else
+ {
+ if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Could not find endpoint to remove: " + connection.EndPoint);
+ }
+ }
+ finally
+ {
+ _connectionsLock.ExitWriteLock();
+ }
+ }
+
+ internal Connection AddNewConnection(EndPoint endpoint, ConnectionState state)
+ {
// Lock when adding connection to prevent grabbing a half alive connection.
_connectionsLock.EnterWriteLock();
- try
- {
- // Make sure they are not already connected to prevent an attack where a single person can fill all the slots.
+ try
+ {
+ // Make sure they are not already connected to prevent an attack where a single person can fill all the slots.
if (_addressConnectionLookup.ContainsKey(endpoint))
{
return null;
@@ -1572,36 +1567,36 @@ internal Connection AddNewConnection(EndPoint endpoint, ConnectionState state)
// Get a connectionId
ulong connectionId;
- if (_releasedConnectionIds.Count > 0)
- {
- connectionId = _releasedConnectionIds.Dequeue();
+ if (_releasedConnectionIds.Count > 0)
+ {
+ connectionId = _releasedConnectionIds.Dequeue();
}
- else
- {
- connectionId = _connectionIdCounter++;
- }
-
- // Alloc on the heap
- Connection connection = new Connection(connectionId, state, endpoint, this);
-
- // Add lookup
- _addressConnectionLookup.Add(endpoint, connection);
-
- if (_headConnection != null)
+ else
+ {
+ connectionId = _connectionIdCounter++;
+ }
+
+ // Alloc on the heap
+ Connection connection = new Connection(connectionId, state, endpoint, this);
+
+ // Add lookup
+ _addressConnectionLookup.Add(endpoint, connection);
+
+ if (_headConnection != null)
{
// We have a connection as head.
connection.NextConnection = _headConnection;
- _headConnection.PreviousConnection = connection;
+ _headConnection.PreviousConnection = connection;
}
_headConnection = connection;
- return connection;
+ return connection;
}
- finally
- {
- _connectionsLock.ExitWriteLock();
- }
- }
- }
-}
+ finally
+ {
+ _connectionsLock.ExitWriteLock();
+ }
+ }
+ }
+}
From d0e9d2443e5933048c4f1cd280a10fed054751c5 Mon Sep 17 00:00:00 2001
From: dungeon2567 <31074903+dungeon2567@users.noreply.github.com>
Date: Wed, 15 Jul 2020 12:25:57 -0300
Subject: [PATCH 2/4] Update RuffleSocket.cs
---
Ruffles/Core/RuffleSocket.cs | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Ruffles/Core/RuffleSocket.cs b/Ruffles/Core/RuffleSocket.cs
index c5437d8..12c2754 100644
--- a/Ruffles/Core/RuffleSocket.cs
+++ b/Ruffles/Core/RuffleSocket.cs
@@ -1551,6 +1551,10 @@ internal void RemoveConnection(Connection connection)
_connectionsLock.ExitWriteLock();
}
}
+
+ public void FlushMessages(){
+ FrameSyncronizationEvent.Set();
+ }
internal Connection AddNewConnection(EndPoint endpoint, ConnectionState state)
{
From 28ed3ef60c3c007d67893ef180fd15a92536b25f Mon Sep 17 00:00:00 2001
From: dungeon2567 <31074903+dungeon2567@users.noreply.github.com>
Date: Wed, 15 Jul 2020 12:30:31 -0300
Subject: [PATCH 3/4] Update RuffleSocket.cs
---
Ruffles/Core/RuffleSocket.cs | 4 ----
1 file changed, 4 deletions(-)
diff --git a/Ruffles/Core/RuffleSocket.cs b/Ruffles/Core/RuffleSocket.cs
index 12c2754..72df5be 100644
--- a/Ruffles/Core/RuffleSocket.cs
+++ b/Ruffles/Core/RuffleSocket.cs
@@ -854,8 +854,6 @@ private void StartNetworkLogic()
Simulator.RunLoop();
}
- int elapsed = (int)logicWatch.ElapsedMilliseconds;
-
for (Connection connection = _headConnection; connection != null; connection = connection.NextConnection)
{
connection.Update();
@@ -866,8 +864,6 @@ private void StartNetworkLogic()
if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Error when running internal loop: " + e);
}
}
-
- logicWatch.Stop();
}
private readonly EndPoint _fromIPv4Endpoint = new IPEndPoint(IPAddress.Any, 0);
From 901e215d7c032674062e9eca35eaed5ce57bf9e5 Mon Sep 17 00:00:00 2001
From: dungeon2567 <31074903+dungeon2567@users.noreply.github.com>
Date: Wed, 15 Jul 2020 22:39:26 -0300
Subject: [PATCH 4/4] Update RuffleSocket.cs
---
Ruffles/Core/RuffleSocket.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Ruffles/Core/RuffleSocket.cs b/Ruffles/Core/RuffleSocket.cs
index 72df5be..999e8a1 100644
--- a/Ruffles/Core/RuffleSocket.cs
+++ b/Ruffles/Core/RuffleSocket.cs
@@ -847,7 +847,7 @@ private void StartNetworkLogic()
{
try
{
- FrameSyncronizationEvent.WaitOne();
+ FrameSyncronizationEvent.WaitOne(TimeSpan.FromMilliseconds(Config.LogicDelay));
if (Simulator != null)
{