diff --git a/RT.Common/Types.cs b/RT.Common/Types.cs index c9320e5..e4d8450 100644 --- a/RT.Common/Types.cs +++ b/RT.Common/Types.cs @@ -443,6 +443,18 @@ public enum NetConnectionType : int NetConnectionTypeClientListenerTCP = 4 } + public enum SERVER_FORCE_DISCONNECT_REASON : byte + { + SERVER_FORCED_DISCONNECT_NONE = 0, + SERVER_FORCED_DISCONNECT_ERROR = 1, + SERVER_FORCED_DISCONNECT_SHUTDOWN = 2, + SERVER_FORCED_DISCONNECT_END_SESSION = 3, + SERVER_FORCED_DISCONNECT_END_GAME = 4, + SERVER_FORCED_DISCONNECT_TIME0UT = 5, + SERVER_FORCED_DISCONNECT_BAD_PERF = 6, + SERVER_FORCED_DISCONNECT_BANNED = 7 + } + public enum MGCL_EVENT_TYPE : int { MGCL_EVENT_CLIENT_DISCONNECT = 0, diff --git a/RT.Models/RT/RT_MSG_SERVER_FORCED_DISCONNECT.cs b/RT.Models/RT/RT_MSG_SERVER_FORCED_DISCONNECT.cs index f2a5d2d..f15d77d 100644 --- a/RT.Models/RT/RT_MSG_SERVER_FORCED_DISCONNECT.cs +++ b/RT.Models/RT/RT_MSG_SERVER_FORCED_DISCONNECT.cs @@ -1,4 +1,5 @@ using RT.Common; +using Server.Common; using System; using System.Collections.Generic; using System.IO; @@ -11,11 +12,11 @@ public class RT_MSG_SERVER_FORCED_DISCONNECT : BaseScertMessage { public override RT_MSG_TYPE Id => RT_MSG_TYPE.RT_MSG_SERVER_FORCED_DISCONNECT; - public byte Reason; + public SERVER_FORCE_DISCONNECT_REASON Reason; public override void Deserialize(BinaryReader reader) { - Reason = reader.ReadByte(); + Reason = reader.Read(); } protected override void Serialize(BinaryWriter writer) diff --git a/Server.Dme/Models/World.cs b/Server.Dme/Models/World.cs index f728f13..a901a0f 100644 --- a/Server.Dme/Models/World.cs +++ b/Server.Dme/Models/World.cs @@ -1,5 +1,6 @@ using DotNetty.Common.Internal.Logging; using Microsoft.Extensions.Logging; +using Microsoft.Scripting.Ast; using RT.Common; using RT.Models; using Server.Dme.PluginArgs; @@ -140,6 +141,8 @@ public async Task Tick() } } + + // Update last agg time if (isAggTick) _lastAggTimeUtc = DateTime.UtcNow; diff --git a/Server.Dme/TcpServer.cs b/Server.Dme/TcpServer.cs index 8c39801..d756920 100644 --- a/Server.Dme/TcpServer.cs +++ b/Server.Dme/TcpServer.cs @@ -39,6 +39,7 @@ public class TcpServer protected internal class ChannelData { public int ApplicationId { get; set; } = 0; + public bool Ignore { get; set; } = false; public ClientObject ClientObject { get; set; } = null; public ConcurrentQueue RecvQueue { get; } = new ConcurrentQueue(); public ConcurrentQueue SendQueue { get; } = new ConcurrentQueue(); @@ -86,7 +87,7 @@ public virtual async void Start() string key = channel.Id.AsLongText(); if (_channelDatas.TryGetValue(key, out var data)) { - if (data.ClientObject == null || !data.ClientObject.IsDestroyed) + if (!data.Ignore && (data.ClientObject == null || !data.ClientObject.IsDestroyed)) { data.RecvQueue.Enqueue(message); data.ClientObject?.OnEcho(true, DateTime.UtcNow); @@ -103,6 +104,7 @@ public virtual async void Start() .Group(_bossGroup, _workerGroup) .Channel() .Option(ChannelOption.SoBacklog, 100) + .Option(ChannelOption.SoTimeout, 30000) .Handler(new LoggingHandler(LogLevel.INFO)) .ChildHandler(new ActionChannelInitializer(channel => { @@ -163,7 +165,7 @@ private async Task Tick(IChannel clientChannel) // Disconnect on destroy if (data.ClientObject != null && data.ClientObject.IsDestroyed) { - await DisconnectClient(clientChannel); + data.Ignore = true; return; } @@ -177,6 +179,7 @@ private async Task Tick(IChannel clientChannel) catch (Exception e) { Logger.Error(e); + await ForceDisconnectClient(clientChannel); } } @@ -363,7 +366,7 @@ protected async Task ProcessMessage(BaseScertMessage message, IChannel clientCha case RT_MSG_CLIENT_DISCONNECT_WITH_REASON clientDisconnectWithReason: { - await DisconnectClient(clientChannel); + data.Ignore = true; break; } default: @@ -390,11 +393,20 @@ protected virtual void ProcessMediusMessage(BaseMediusMessage message, IChannel /// /// Closes the client channel. /// - protected async Task DisconnectClient(IChannel channel) + protected async Task ForceDisconnectClient(IChannel channel) { try { - //await channel.WriteAndFlushAsync(new RT_MSG_SERVER_FORCED_DISCONNECT()); + // Give it every reason just to make sure it disconnects + for (byte r = 0; r < 7; ++r) + { + await channel.WriteAsync(new RT_MSG_SERVER_FORCED_DISCONNECT() + { + Reason = (SERVER_FORCE_DISCONNECT_REASON)r + }); + } + + channel.Flush(); } catch (Exception) { diff --git a/Server.Dme/UdpServer.cs b/Server.Dme/UdpServer.cs index a793251..f5b44c0 100644 --- a/Server.Dme/UdpServer.cs +++ b/Server.Dme/UdpServer.cs @@ -246,29 +246,6 @@ protected virtual void ProcessMediusMessage(BaseMediusMessage message) #endregion - #region Channel - - /// - /// Closes the client channel. - /// - protected async Task DisconnectClient(IChannel channel) - { - try - { - //await channel.WriteAndFlushAsync(new RT_MSG_SERVER_FORCED_DISCONNECT()); - } - catch (Exception) - { - // Silence exception since the client probably just closed the socket before we could write to it - } - finally - { - await channel.CloseAsync(); - } - } - - #endregion - #region Send private void SendTo(BaseScertMessage message, EndPoint target) diff --git a/Server.Medius/Medius/BaseMediusComponent.cs b/Server.Medius/Medius/BaseMediusComponent.cs index 1ab7441..194d5cd 100644 --- a/Server.Medius/Medius/BaseMediusComponent.cs +++ b/Server.Medius/Medius/BaseMediusComponent.cs @@ -60,6 +60,10 @@ protected internal class ChannelData public bool? IsBanned { get; set; } = null; + /// + /// When true, all messages from this client will be ignored. + /// + public bool Ignore { get; set; } = false; public DateTime LastSentEcho { get; set; } = DateTime.UnixEpoch; } @@ -148,7 +152,7 @@ public virtual async void Start() if (_channelDatas.TryGetValue(key, out var data)) { // Don't queue message if client is ignored - if (data.ClientObject == null || !data.ClientObject.Ignore) + if (!data.Ignore) { // Don't queue if banned if (data.IsBanned == null || data.IsBanned == false) @@ -171,6 +175,7 @@ public virtual async void Start() .Group(_bossGroup, _workerGroup) .Channel() .Option(ChannelOption.SoBacklog, 100) + .Option(ChannelOption.SoTimeout, 30000) .Handler(new LoggingHandler(LogLevel.INFO)) .ChildHandler(new ActionChannelInitializer(channel => { @@ -228,7 +233,7 @@ protected virtual async Task Tick(IChannel clientChannel) if (_channelDatas.TryGetValue(key, out var data)) { // Ignore - if (data.ClientObject != null && data.ClientObject.Ignore) + if (data.Ignore) return; // Process all messages in queue @@ -252,6 +257,8 @@ protected virtual async Task Tick(IChannel clientChannel) catch (Exception e) { Logger.Error(e); + await ForceDisconnectClient(clientChannel); + data.Ignore = true; } } @@ -338,11 +345,20 @@ protected virtual void QueueBanMessage(ChannelData data, string msg = "You have #region Channel - protected async Task DisconnectClient(IChannel channel) + protected async Task ForceDisconnectClient(IChannel channel) { try { - //await channel.WriteAndFlushAsync(new RT_MSG_SERVER_FORCED_DISCONNECT()); + // Give it every reason just to make sure it disconnects + for (byte r = 0; r < 7; ++r) + { + await channel.WriteAsync(new RT_MSG_SERVER_FORCED_DISCONNECT() + { + Reason = (SERVER_FORCE_DISCONNECT_REASON)r + }); + } + + channel.Flush(); } catch (Exception) { @@ -350,7 +366,7 @@ protected async Task DisconnectClient(IChannel channel) } finally { - await channel.DisconnectAsync(); + } } diff --git a/Server.Medius/Medius/MLS.cs b/Server.Medius/Medius/MLS.cs index e466915..5baa179 100644 --- a/Server.Medius/Medius/MLS.cs +++ b/Server.Medius/Medius/MLS.cs @@ -74,7 +74,7 @@ protected override async Task ProcessMessage(BaseScertMessage message, IChannel data.ClientObject = Program.Manager.GetClientByAccessToken(clientConnectTcp.AccessToken); if (data.ClientObject == null) { - await DisconnectClient(clientChannel); + data.Ignore = true; } else { @@ -129,7 +129,7 @@ protected override async Task ProcessMessage(BaseScertMessage message, IChannel case RT_MSG_CLIENT_DISCONNECT_WITH_REASON clientDisconnectWithReason: { - await DisconnectClient(clientChannel); + data.Ignore = true; break; } default: @@ -2496,12 +2496,9 @@ private async Task ProcessChatMessage(IChannel clientChannel, ClientObject clien var targetPlayer = channel.Clients.FirstOrDefault(x => x.AccountId == chatMessage.TargetID); List chatResponses = new List(); - // ERROR -- Need to be logged in + // Need to be logged in if (!clientObject.IsLoggedIn) - { - await DisconnectClient(clientChannel); return; - } // Need to be in a channel if (channel == null) @@ -2557,10 +2554,7 @@ private async Task ProcessGenericChatMessage(IChannel clientChannel, ClientObjec // ERROR -- Need to be logged in if (!clientObject.IsLoggedIn) - { - await DisconnectClient(clientChannel); return; - } // Need to be in a channel if (channel == null) diff --git a/Server.Medius/Medius/MediusManager.cs b/Server.Medius/Medius/MediusManager.cs index e085292..a8e1738 100644 --- a/Server.Medius/Medius/MediusManager.cs +++ b/Server.Medius/Medius/MediusManager.cs @@ -394,9 +394,6 @@ private void TickClients() clientKeyPair.Value.Logout(); clientKeyPair.Value.EndSession(); - // Ignore all future messages - clientKeyPair.Value.Ignore = true; - clientsToRemove.Enqueue(clientKeyPair.Key); } } diff --git a/Server.Medius/Medius/Models/ClientObject.cs b/Server.Medius/Medius/Models/ClientObject.cs index 058da6b..677cd98 100644 --- a/Server.Medius/Medius/Models/ClientObject.cs +++ b/Server.Medius/Medius/Models/ClientObject.cs @@ -76,11 +76,6 @@ public class ClientObject /// public DateTime UtcLastEcho { get; protected set; } = DateTime.UtcNow; - /// - /// When true, all messages from this client will be ignored. - /// - public bool Ignore { get; set; } = false; - public virtual bool IsLoggedIn => !_logoutTime.HasValue && _loginTime.HasValue && IsConnected; public bool IsInGame => CurrentGame != null && CurrentChannel != null && CurrentChannel.Type == ChannelType.Game; diff --git a/Server.NAT/NAT.cs b/Server.NAT/NAT.cs index 93fc157..8231e8a 100644 --- a/Server.NAT/NAT.cs +++ b/Server.NAT/NAT.cs @@ -45,8 +45,8 @@ public async Task Start() // Queue all incoming messages _scertHandler.OnChannelMessage += (channel, message) => { - // Send ip and port back - if (message.Content.ReadableBytes == 4 && message.Content.GetByte(message.Content.ReaderIndex + 3) < 0x80) + // Send ip and port back if the last byte isn't 0xD4 + if (message.Content.ReadableBytes == 4 && message.Content.GetByte(message.Content.ReaderIndex + 3) != 0xD4) { var buffer = channel.Allocator.Buffer(6); buffer.WriteBytes((message.Sender as IPEndPoint).Address.MapToIPv4().GetAddressBytes());