update CoD4x parser

tweak handling segmented status response
actually support more than 18 clients LOL
This commit is contained in:
RaidMax 2020-12-02 14:29:49 -06:00
parent bd3f0caf60
commit 6648b75255
6 changed files with 44 additions and 36 deletions

View File

@ -5,12 +5,13 @@ using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog; using Serilog;
using Serilog.Events; using Serilog.Events;
using SharedLibraryCore; using SharedLibraryCore;
using SharedLibraryCore.Configuration; using SharedLibraryCore.Configuration;
using SharedLibraryCore.Database;
using SharedLibraryCore.Database.MigrationContext; using SharedLibraryCore.Database.MigrationContext;
using ILogger = Serilog.ILogger;
namespace IW4MAdmin.Application.Extensions namespace IW4MAdmin.Application.Extensions
{ {
@ -45,6 +46,8 @@ namespace IW4MAdmin.Application.Extensions
} }
services.AddLogging(builder => builder.AddSerilog(_defaultLogger, dispose: true)); services.AddLogging(builder => builder.AddSerilog(_defaultLogger, dispose: true));
services.AddSingleton(new LoggerFactory()
.AddSerilog(_defaultLogger, true));
return services; return services;
} }
@ -76,18 +79,19 @@ namespace IW4MAdmin.Application.Extensions
case "mysql": case "mysql":
var appendTimeout = !appConfig.ConnectionString.Contains("default command timeout", var appendTimeout = !appConfig.ConnectionString.Contains("default command timeout",
StringComparison.InvariantCultureIgnoreCase); StringComparison.InvariantCultureIgnoreCase);
var mysqlBuilder = new DbContextOptionsBuilder<MySqlDatabaseContext>() services.AddSingleton(sp => (DbContextOptions) new DbContextOptionsBuilder<MySqlDatabaseContext>()
.UseMySql(appConfig.ConnectionString + (appendTimeout ? ";default command timeout=0" : ""), .UseMySql(appConfig.ConnectionString + (appendTimeout ? ";default command timeout=0" : ""),
mysqlOptions => mysqlOptions.EnableRetryOnFailure()); mysqlOptions => mysqlOptions.EnableRetryOnFailure())
services.AddSingleton((DbContextOptions) mysqlBuilder.Options); .UseLoggerFactory(sp.GetRequiredService<ILoggerFactory>()).Options);
return services; return services;
case "postgresql": case "postgresql":
appendTimeout = !appConfig.ConnectionString.Contains("Command Timeout", appendTimeout = !appConfig.ConnectionString.Contains("Command Timeout",
StringComparison.InvariantCultureIgnoreCase); StringComparison.InvariantCultureIgnoreCase);
var postgresqlBuilder = new DbContextOptionsBuilder<PostgresqlDatabaseContext>() services.AddSingleton(sp =>
.UseNpgsql(appConfig.ConnectionString + (appendTimeout ? ";Command Timeout=0" : ""), (DbContextOptions) new DbContextOptionsBuilder<PostgresqlDatabaseContext>()
postgresqlOptions => postgresqlOptions.EnableRetryOnFailure()); .UseNpgsql(appConfig.ConnectionString + (appendTimeout ? ";Command Timeout=0" : ""),
services.AddSingleton((DbContextOptions) postgresqlBuilder.Options); postgresqlOptions => postgresqlOptions.EnableRetryOnFailure())
.UseLoggerFactory(sp.GetRequiredService<ILoggerFactory>()).Options);
return services; return services;
default: default:
throw new ArgumentException($"No context available for {appConfig.DatabaseProvider}"); throw new ArgumentException($"No context available for {appConfig.DatabaseProvider}");

View File

@ -18,7 +18,7 @@ namespace IW4MAdmin.Application.RCon
} }
public int ConnectionAttempts { get; set; } public int ConnectionAttempts { get; set; }
const int BufferSize = 4096; const int BufferSize = 8192;
public readonly byte[] ReceiveBuffer = new byte[BufferSize]; public readonly byte[] ReceiveBuffer = new byte[BufferSize];
public readonly SemaphoreSlim OnComplete = new SemaphoreSlim(1, 1); public readonly SemaphoreSlim OnComplete = new SemaphoreSlim(1, 1);
public readonly ManualResetEventSlim OnSentData = new ManualResetEventSlim(false); public readonly ManualResetEventSlim OnSentData = new ManualResetEventSlim(false);

View File

@ -407,37 +407,39 @@ namespace IW4MAdmin.Application.RCon
return; return;
} }
if (sender is Socket sock) if (!(sender is Socket sock))
{ {
var state = ActiveQueries[this.Endpoint]; return;
state.BytesReadPerSegment.Add(e.BytesTransferred); }
try var state = ActiveQueries[this.Endpoint];
state.BytesReadPerSegment.Add(e.BytesTransferred);
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 state.ReceiveEventArgs.SetBuffer(state.ReceiveBuffer, totalBytesTransferred, sock.Available);
if (sock.Available > 0)
{
state.ReceiveEventArgs.SetBuffer(state.ReceiveBuffer, e.BytesTransferred, state.ReceiveBuffer.Length - e.BytesTransferred);
if (!sock.ReceiveAsync(state.ReceiveEventArgs)) if (sock.ReceiveAsync(state.ReceiveEventArgs))
{ {
_log.LogDebug("Read {bytesTransferred} synchronous bytes from {endpoint}", state.ReceiveEventArgs.BytesTransferred, e.RemoteEndPoint); continue;
// 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 _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
ActiveQueries[this.Endpoint].OnReceivedData.Set(); state.BytesReadPerSegment.Add(state.ReceiveEventArgs.BytesTransferred);
} totalBytesTransferred += state.ReceiveEventArgs.BytesTransferred;
} }
catch (ObjectDisposedException) ActiveQueries[this.Endpoint].OnReceivedData.Set();
{ }
ActiveQueries[this.Endpoint].OnReceivedData.Set();
} catch (ObjectDisposedException)
{
ActiveQueries[this.Endpoint].OnReceivedData.Set();
} }
} }

View File

@ -205,7 +205,8 @@ namespace IW4MAdmin.Application.RconParsers
if (match.Success) 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)); _logger.LogDebug("Ignoring detected client {client} because they are zombie state", string.Join(",", match.Values));
continue; continue;

View File

@ -15,9 +15,10 @@ var plugin = {
eventParser = manager.GenerateDynamicEventParser(this.name); eventParser = manager.GenerateDynamicEventParser(this.name);
rconParser.Configuration.StatusHeader.Pattern = 'num +score +ping +playerid +steamid +name +lastmsg +address +qport +rate *'; 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(104, 6); // RConName
rconParser.Configuration.Status.AddMapping(105, 8); // RConIPAddress 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.Pattern = '^"(.+)" is: "(.+)?" default: "(.+)?" info: "(.+)?"$';
rconParser.Configuration.Dvar.AddMapping(109, 2); // DVAR latched value rconParser.Configuration.Dvar.AddMapping(109, 2); // DVAR latched value

View File

@ -42,7 +42,7 @@ namespace SharedLibraryCore
ServerConfig = config; ServerConfig = config;
RemoteConnection = rconConnectionFactory.CreateConnection(IP, Port, Password); RemoteConnection = rconConnectionFactory.CreateConnection(IP, Port, Password);
EventProcessing = new SemaphoreSlim(1, 1); EventProcessing = new SemaphoreSlim(1, 1);
Clients = new List<EFClient>(new EFClient[18]); Clients = new List<EFClient>(new EFClient[64]);
Reports = new List<Report>(); Reports = new List<Report>();
ClientHistory = new Queue<PlayerHistory>(); ClientHistory = new Queue<PlayerHistory>();
ChatHistory = new List<ChatInfo>(); ChatHistory = new List<ChatInfo>();