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) {