diff --git a/Projects/Server/Network/NetState/NetState.cs b/Projects/Server/Network/NetState/NetState.cs index e3f360385..4f6067a03 100644 --- a/Projects/Server/Network/NetState/NetState.cs +++ b/Projects/Server/Network/NetState/NetState.cs @@ -185,11 +185,11 @@ namespace Server.Network public bool Seeded { get; set; } - public Pipe RecvPipe { get; private set; } + public Pipe RecvPipe { get; } - public Pipe SendPipe { get; private set; } + public Pipe SendPipe { get; } - public ISocket Connection { get; private set; } + public ISocket Connection { get; } public bool CompressionEnabled { get; set; } @@ -999,9 +999,14 @@ namespace Server.Network } catch (SocketException ex) { + // Socket disconnected by client + if (ex.ErrorCode != 54) + { #if DEBUG Console.WriteLine(ex); #endif + } + Disconnect(string.Empty); } catch (Exception ex) @@ -1062,8 +1067,8 @@ namespace Server.Network while (Disposed.TryDequeue(out var ns)) { - ns.Dispose(); TcpServer.Instances.Remove(ns); + ns.Dispose(); } return count; @@ -1139,17 +1144,12 @@ namespace Server.Network _disconnectReason = reason; - if (Connection == null) - { - return; - } - Disposed.Enqueue(this); } - public void TraceDisconnect() + public static void TraceDisconnect(string reason, string ip) { - if (_disconnectReason == string.Empty) + if (reason == string.Empty) { return; } @@ -1159,8 +1159,8 @@ namespace Server.Network using StreamWriter op = new StreamWriter("network-disconnects.log", true); op.WriteLine($"# {DateTime.UtcNow}"); - op.WriteLine($"NetState: {this}"); - op.WriteLine(_disconnectReason); + op.WriteLine($"NetState: {ip}"); + op.WriteLine(reason); op.WriteLine(); op.WriteLine(); @@ -1173,7 +1173,7 @@ namespace Server.Network private void Dispose() { - TraceDisconnect(); + TraceDisconnect(_disconnectReason, _toString); RecvPipe.Writer.Close(); SendPipe.Writer.Close(); diff --git a/Projects/Server/Network/NetworkState.cs b/Projects/Server/Network/NetworkState.cs deleted file mode 100644 index 8f86be4f4..000000000 --- a/Projects/Server/Network/NetworkState.cs +++ /dev/null @@ -1,38 +0,0 @@ -/************************************************************************* - * ModernUO * - * Copyright 2019-2020 - ModernUO Development Team * - * Email: hi@modernuo.com * - * File: NetworkState.cs * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - *************************************************************************/ - -using System.Runtime.CompilerServices; -using System.Threading; - -namespace Server.Network -{ - public class NetworkState - { - public static readonly NetworkState PauseState = new(true); - public static readonly NetworkState ResumeState = new(false); - - public bool Paused { get; } - - internal NetworkState(bool paused) => Paused = paused; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool Pause(ref NetworkState state) => - Interlocked.CompareExchange(ref state, PauseState, ResumeState) != PauseState; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool Resume(ref NetworkState state) => - Interlocked.CompareExchange(ref state, ResumeState, PauseState) != ResumeState; - } -} diff --git a/Projects/Server/Network/TcpServer.cs b/Projects/Server/Network/TcpServer.cs index 307605201..12ab2a709 100644 --- a/Projects/Server/Network/TcpServer.cs +++ b/Projects/Server/Network/TcpServer.cs @@ -26,9 +26,9 @@ namespace Server.Network { public static class TcpServer { - private static NetworkState _networkState = NetworkState.ResumeState; + private const int MaxConnectionsPerLoop = 250; - // Sanity. 256 * 1024 * 5000 = ~1.3GB of ram + // Sanity. 256 * 1024 * 4096 = ~1.3GB of ram public static int MaxConnections { get; set; } = 4096; private const long _listenerErrorMessageDelay = 10000; // 10 seconds @@ -122,50 +122,15 @@ namespace Server.Network return null; } - /** - * Pauses the TcpServer and stops accepting new sockets. - * This is thread-safe without using locks. - */ - public static void Pause() - { - NetworkState.Pause(ref _networkState); - } - - /** - * Resumes accepting sockets on the TcpServer. - * This is thread-safe using a lock on the listeners - */ - public static void Resume() - { - if (!NetworkState.Resume(ref _networkState)) - { - return; - } - - lock (Listeners) - { - foreach (var listener in Listeners) - { - listener.BeginAcceptingSockets(); - } - } - } - public static int Slice() { int count = 0; - var limit = _connectedQueue.Count; - while (_connectedQueue.Count > 0 && --limit >= 0) + while (++count <= MaxConnectionsPerLoop && _connectedQueue.TryDequeue(out var ns)) { - if (!_connectedQueue.TryDequeue(out var ns)) - { - break; - } - - count++; Instances.Add(ns); ns.WriteConsole("Connected. [{0} Online]", Instances.Count); + ns.Start(); } return count; @@ -175,55 +140,58 @@ namespace Server.Network { while (true) { - if (_networkState.Paused) - { - return; - } - - Socket socket = null; - try { - socket = await listener.AcceptSocketAsync().ConfigureAwait(false); + var socket = await listener.AcceptSocketAsync(); + var rejected = false; if (Instances.Count >= MaxConnections) { - socket.Send(_socketRejected, SocketFlags.None); - socket.Shutdown(SocketShutdown.Both); - socket.Close(); - throw new MaxConnectionsException(); + rejected = true; + + var ticks = Core.TickCount; + + if (_nextMaximumSocketsReachedMessage <= ticks) + { + if (socket.RemoteEndPoint is IPEndPoint ipep) + { + var ip = ipep.Address.ToString(); + Console.WriteLine("Listener {0}: Failed (Maximum connections reached)", ip); + NetState.TraceDisconnect("Maximum connections reached.", ip); + } + + _nextMaximumSocketsReachedMessage = ticks + _listenerErrorMessageDelay; + } } var args = new SocketConnectEventArgs(socket); EventSink.InvokeSocketConnect(args); if (!args.AllowConnection) + { + rejected = true; + if (socket.RemoteEndPoint is IPEndPoint ipep) + { + var ip = ipep.Address.ToString(); + NetState.TraceDisconnect("Rejected by socket event handler", ip); + } + } + + if (rejected) { socket.Send(_socketRejected, SocketFlags.None); socket.Shutdown(SocketShutdown.Both); socket.Close(); } - } - catch (MaxConnectionsException) - { - var ticks = Core.TickCount; - - if (_nextMaximumSocketsReachedMessage <= ticks) + else { - if (socket?.RemoteEndPoint is IPEndPoint ipep) - { - Console.WriteLine("Listener {0}:{1}: Failed (Maximum connections reached)", ipep.Address, ipep.Port); - } - _nextMaximumSocketsReachedMessage = ticks + _listenerErrorMessageDelay; + var ns = new NetState(new NetworkSocket(socket)); + _connectedQueue.Enqueue(ns); } } catch { // ignored } - - var ns = new NetState(new NetworkSocket(socket)); - _connectedQueue.Enqueue(ns); - ns.Start(); } } }