From 6648b75255407ea79d56c6b7d487125c3b2e76dd Mon Sep 17 00:00:00 2001 From: RaidMax Date: Wed, 2 Dec 2020 14:29:49 -0600 Subject: [PATCH] update CoD4x parser tweak handling segmented status response actually support more than 18 clients LOL --- Application/Extensions/StartupExtensions.cs | 20 +++++---- Application/RCon/ConnectionState.cs | 2 +- Application/RCon/RConConnection.cs | 50 +++++++++++---------- Application/RconParsers/BaseRConParser.cs | 3 +- Plugins/ScriptPlugins/ParserCoD4x.js | 3 +- SharedLibraryCore/Server.cs | 2 +- 6 files changed, 44 insertions(+), 36 deletions(-) diff --git a/Application/Extensions/StartupExtensions.cs b/Application/Extensions/StartupExtensions.cs index 764414da7..b59a4b0be 100644 --- a/Application/Extensions/StartupExtensions.cs +++ b/Application/Extensions/StartupExtensions.cs @@ -5,12 +5,13 @@ using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Serilog; using Serilog.Events; using SharedLibraryCore; using SharedLibraryCore.Configuration; -using SharedLibraryCore.Database; using SharedLibraryCore.Database.MigrationContext; +using ILogger = Serilog.ILogger; namespace IW4MAdmin.Application.Extensions { @@ -45,6 +46,8 @@ namespace IW4MAdmin.Application.Extensions } services.AddLogging(builder => builder.AddSerilog(_defaultLogger, dispose: true)); + services.AddSingleton(new LoggerFactory() + .AddSerilog(_defaultLogger, true)); return services; } @@ -76,18 +79,19 @@ namespace IW4MAdmin.Application.Extensions case "mysql": var appendTimeout = !appConfig.ConnectionString.Contains("default command timeout", StringComparison.InvariantCultureIgnoreCase); - var mysqlBuilder = new DbContextOptionsBuilder() + services.AddSingleton(sp => (DbContextOptions) new DbContextOptionsBuilder() .UseMySql(appConfig.ConnectionString + (appendTimeout ? ";default command timeout=0" : ""), - mysqlOptions => mysqlOptions.EnableRetryOnFailure()); - services.AddSingleton((DbContextOptions) mysqlBuilder.Options); + mysqlOptions => mysqlOptions.EnableRetryOnFailure()) + .UseLoggerFactory(sp.GetRequiredService()).Options); return services; case "postgresql": appendTimeout = !appConfig.ConnectionString.Contains("Command Timeout", StringComparison.InvariantCultureIgnoreCase); - var postgresqlBuilder = new DbContextOptionsBuilder() - .UseNpgsql(appConfig.ConnectionString + (appendTimeout ? ";Command Timeout=0" : ""), - postgresqlOptions => postgresqlOptions.EnableRetryOnFailure()); - services.AddSingleton((DbContextOptions) postgresqlBuilder.Options); + services.AddSingleton(sp => + (DbContextOptions) new DbContextOptionsBuilder() + .UseNpgsql(appConfig.ConnectionString + (appendTimeout ? ";Command Timeout=0" : ""), + postgresqlOptions => postgresqlOptions.EnableRetryOnFailure()) + .UseLoggerFactory(sp.GetRequiredService()).Options); return services; default: throw new ArgumentException($"No context available for {appConfig.DatabaseProvider}"); diff --git a/Application/RCon/ConnectionState.cs b/Application/RCon/ConnectionState.cs index 00595be23..91307671d 100644 --- a/Application/RCon/ConnectionState.cs +++ b/Application/RCon/ConnectionState.cs @@ -18,7 +18,7 @@ namespace IW4MAdmin.Application.RCon } public int ConnectionAttempts { get; set; } - const int BufferSize = 4096; + const int BufferSize = 8192; public readonly byte[] ReceiveBuffer = new byte[BufferSize]; public readonly SemaphoreSlim OnComplete = new SemaphoreSlim(1, 1); public readonly ManualResetEventSlim OnSentData = new ManualResetEventSlim(false); diff --git a/Application/RCon/RConConnection.cs b/Application/RCon/RConConnection.cs index 6586cdef3..07ea354ec 100644 --- a/Application/RCon/RConConnection.cs +++ b/Application/RCon/RConConnection.cs @@ -407,37 +407,39 @@ namespace IW4MAdmin.Application.RCon return; } - if (sender is Socket sock) + if (!(sender is Socket sock)) { - var state = ActiveQueries[this.Endpoint]; - state.BytesReadPerSegment.Add(e.BytesTransferred); + return; + } + + var state = ActiveQueries[this.Endpoint]; + state.BytesReadPerSegment.Add(e.BytesTransferred); - try + try + { + var totalBytesTransferred = e.BytesTransferred; + // we still have available data so the payload was segmented + while (sock.Available > 0) { - // we still have available data so the payload was segmented - if (sock.Available > 0) + state.ReceiveEventArgs.SetBuffer(state.ReceiveBuffer, totalBytesTransferred, sock.Available); + + if (sock.ReceiveAsync(state.ReceiveEventArgs)) { - state.ReceiveEventArgs.SetBuffer(state.ReceiveBuffer, e.BytesTransferred, state.ReceiveBuffer.Length - e.BytesTransferred); - - if (!sock.ReceiveAsync(state.ReceiveEventArgs)) - { - _log.LogDebug("Read {bytesTransferred} synchronous bytes from {endpoint}", state.ReceiveEventArgs.BytesTransferred, e.RemoteEndPoint); - // we need to increment this here because the callback isn't executed if there's no pending IO - state.BytesReadPerSegment.Add(state.ReceiveEventArgs.BytesTransferred); - ActiveQueries[this.Endpoint].OnReceivedData.Set(); - } - } - - else - { - ActiveQueries[this.Endpoint].OnReceivedData.Set(); + continue; } + + _log.LogDebug("Read {bytesTransferred} synchronous bytes from {endpoint}", state.ReceiveEventArgs.BytesTransferred, e.RemoteEndPoint); + // we need to increment this here because the callback isn't executed if there's no pending IO + state.BytesReadPerSegment.Add(state.ReceiveEventArgs.BytesTransferred); + totalBytesTransferred += state.ReceiveEventArgs.BytesTransferred; } + + ActiveQueries[this.Endpoint].OnReceivedData.Set(); + } - catch (ObjectDisposedException) - { - ActiveQueries[this.Endpoint].OnReceivedData.Set(); - } + catch (ObjectDisposedException) + { + ActiveQueries[this.Endpoint].OnReceivedData.Set(); } } diff --git a/Application/RconParsers/BaseRConParser.cs b/Application/RconParsers/BaseRConParser.cs index 55ca97943..c77da2434 100644 --- a/Application/RconParsers/BaseRConParser.cs +++ b/Application/RconParsers/BaseRConParser.cs @@ -205,7 +205,8 @@ namespace IW4MAdmin.Application.RconParsers if (match.Success) { - if (match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConPing]] == "ZMBI") + if (match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConPing]] == "ZMBI" || + match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConPing]] == "CNCT") { _logger.LogDebug("Ignoring detected client {client} because they are zombie state", string.Join(",", match.Values)); continue; diff --git a/Plugins/ScriptPlugins/ParserCoD4x.js b/Plugins/ScriptPlugins/ParserCoD4x.js index d4fbf0747..ada571c6b 100644 --- a/Plugins/ScriptPlugins/ParserCoD4x.js +++ b/Plugins/ScriptPlugins/ParserCoD4x.js @@ -15,9 +15,10 @@ var plugin = { eventParser = manager.GenerateDynamicEventParser(this.name); rconParser.Configuration.StatusHeader.Pattern = 'num +score +ping +playerid +steamid +name +lastmsg +address +qport +rate *'; - rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +-?([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]{16,32})|bot[0-9]+) ([0-9]+) +(.{0,32}) +([0-9]+) +(\\d+\\.\\d+\\.\\d+.\\d+\\:-*\\d{1,5}|0+.0+:-*\\d{1,5}|loopback) +(-*[0-9]+) +([0-9]+) *$'; + rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +-?([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]{16,32})|0) +([[0-9]+|0]) +(.{0,32}) +([0-9]+) +(\\d+\\.\\d+\\.\\d+.\\d+\\:-*\\d{1,5}|0+.0+:-*\\d{1,5}|loopback|bot) +(-*[0-9]+) +([0-9]+) *$'; rconParser.Configuration.Status.AddMapping(104, 6); // RConName rconParser.Configuration.Status.AddMapping(105, 8); // RConIPAddress + rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xffprint\n'; rconParser.Configuration.Dvar.Pattern = '^"(.+)" is: "(.+)?" default: "(.+)?" info: "(.+)?"$'; rconParser.Configuration.Dvar.AddMapping(109, 2); // DVAR latched value diff --git a/SharedLibraryCore/Server.cs b/SharedLibraryCore/Server.cs index d129d289a..84f16916e 100644 --- a/SharedLibraryCore/Server.cs +++ b/SharedLibraryCore/Server.cs @@ -42,7 +42,7 @@ namespace SharedLibraryCore ServerConfig = config; RemoteConnection = rconConnectionFactory.CreateConnection(IP, Port, Password); EventProcessing = new SemaphoreSlim(1, 1); - Clients = new List(new EFClient[18]); + Clients = new List(new EFClient[64]); Reports = new List(); ClientHistory = new Queue(); ChatHistory = new List();