fix rcon issue
This commit is contained in:
parent
3ad4aa2196
commit
ff0d22c142
@ -456,7 +456,7 @@ namespace IW4MAdmin.Application.Misc
|
||||
|
||||
private void GetDvarAsync(Server server, string dvarName, Delegate onCompleted)
|
||||
{
|
||||
Task.Run<Task>(async () =>
|
||||
Task.Run(() =>
|
||||
{
|
||||
var tokenSource = new CancellationTokenSource();
|
||||
tokenSource.CancelAfter(TimeSpan.FromSeconds(5));
|
||||
@ -464,14 +464,14 @@ namespace IW4MAdmin.Application.Misc
|
||||
var success = true;
|
||||
try
|
||||
{
|
||||
result = (await server.GetDvarAsync<string>(dvarName, token: tokenSource.Token)).Value;
|
||||
result = server.GetDvarAsync<string>(dvarName, token: tokenSource.Token).GetAwaiter().GetResult().Value;
|
||||
}
|
||||
catch
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
|
||||
await _onProcessing.WaitAsync();
|
||||
_onProcessing.Wait();
|
||||
try
|
||||
{
|
||||
onCompleted.DynamicInvoke(JsValue.Undefined,
|
||||
@ -495,7 +495,7 @@ namespace IW4MAdmin.Application.Misc
|
||||
}
|
||||
private void SetDvarAsync(Server server, string dvarName, string dvarValue, Delegate onCompleted)
|
||||
{
|
||||
Task.Run<Task>(async () =>
|
||||
Task.Run(() =>
|
||||
{
|
||||
var tokenSource = new CancellationTokenSource();
|
||||
tokenSource.CancelAfter(TimeSpan.FromSeconds(5));
|
||||
@ -503,14 +503,14 @@ namespace IW4MAdmin.Application.Misc
|
||||
|
||||
try
|
||||
{
|
||||
await server.SetDvarAsync(dvarName, dvarValue, tokenSource.Token);
|
||||
server.SetDvarAsync(dvarName, dvarValue, tokenSource.Token).GetAwaiter().GetResult();
|
||||
}
|
||||
catch
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
|
||||
await _onProcessing.WaitAsync();
|
||||
_onProcessing.Wait();
|
||||
try
|
||||
{
|
||||
onCompleted.DynamicInvoke(JsValue.Undefined,
|
||||
|
@ -33,7 +33,8 @@ namespace Integrations.Cod
|
||||
private readonly Encoding _gameEncoding;
|
||||
private readonly int _retryAttempts;
|
||||
|
||||
public CodRConConnection(IPEndPoint ipEndpoint, string password, ILogger<CodRConConnection> log, Encoding gameEncoding, int retryAttempts)
|
||||
public CodRConConnection(IPEndPoint ipEndpoint, string password, ILogger<CodRConConnection> log,
|
||||
Encoding gameEncoding, int retryAttempts)
|
||||
{
|
||||
RConPassword = password;
|
||||
_gameEncoding = gameEncoding;
|
||||
@ -66,6 +67,11 @@ namespace Integrations.Cod
|
||||
}
|
||||
finally
|
||||
{
|
||||
using (LogContext.PushProperty("Server", Endpoint.ToString()))
|
||||
{
|
||||
_log.LogDebug("Releasing OnComplete {Count}", ActiveQueries[Endpoint].OnComplete.CurrentCount);
|
||||
}
|
||||
|
||||
if (ActiveQueries[Endpoint].OnComplete.CurrentCount == 0)
|
||||
{
|
||||
ActiveQueries[Endpoint].OnComplete.Release();
|
||||
@ -73,14 +79,19 @@ namespace Integrations.Cod
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string[]> SendQueryAsyncInternal(StaticHelpers.QueryType type, string parameters = "", CancellationToken token = default)
|
||||
private async Task<string[]> SendQueryAsyncInternal(StaticHelpers.QueryType type, string parameters = "",
|
||||
CancellationToken token = default)
|
||||
{
|
||||
if (!ActiveQueries.ContainsKey(Endpoint))
|
||||
{
|
||||
ActiveQueries.TryAdd(Endpoint, new ConnectionState());
|
||||
}
|
||||
|
||||
var connectionState = ActiveQueries[Endpoint];
|
||||
if (!ActiveQueries.TryGetValue(Endpoint, out var connectionState))
|
||||
{
|
||||
_log.LogError("Could not retrieve connection state");
|
||||
throw new InvalidOperationException("Could not get connection state");
|
||||
}
|
||||
|
||||
_log.LogDebug("Waiting for semaphore to be released [{Endpoint}]", Endpoint);
|
||||
|
||||
@ -91,6 +102,8 @@ namespace Integrations.Cod
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_log.LogDebug("OnComplete did not complete before timeout {Count}",
|
||||
connectionState.OnComplete.CurrentCount);
|
||||
throw new RConException("Timed out waiting for access to rcon socket");
|
||||
}
|
||||
|
||||
@ -100,16 +113,20 @@ namespace Integrations.Cod
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(_config.FloodProtectInterval - (int)timeSinceLastQuery, token);
|
||||
var delay = _config.FloodProtectInterval - (int)timeSinceLastQuery;
|
||||
_log.LogDebug("Delaying for {Delay}ms", delay);
|
||||
await Task.Delay(delay, token);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_log.LogDebug("Waiting for flood protect did not complete before timeout timeout {Count}",
|
||||
connectionState.OnComplete.CurrentCount);
|
||||
throw new RConException("Timed out waiting for flood protect to expire");
|
||||
}
|
||||
}
|
||||
|
||||
_log.LogDebug("Semaphore has been released [{Endpoint}]", Endpoint);
|
||||
_log.LogDebug("Query {@QueryInfo}", new { endpoint=Endpoint.ToString(), type, parameters });
|
||||
_log.LogDebug("Query {@QueryInfo}", new { endpoint = Endpoint.ToString(), type, parameters });
|
||||
|
||||
byte[] payload = null;
|
||||
var waitForResponse = _config.WaitForResponse;
|
||||
@ -163,7 +180,6 @@ namespace Integrations.Cod
|
||||
// e.g: emoji -> windows-1252
|
||||
catch (OverflowException ex)
|
||||
{
|
||||
|
||||
using (LogContext.PushProperty("Server", Endpoint.ToString()))
|
||||
{
|
||||
_log.LogError(ex, "Could not convert RCon data payload to desired encoding {Encoding} {Params}",
|
||||
@ -201,6 +217,7 @@ namespace Integrations.Cod
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_log.LogDebug("OnSent did not complete in time");
|
||||
throw new RConException("Timed out waiting for access to RCon send socket");
|
||||
}
|
||||
|
||||
@ -211,14 +228,13 @@ namespace Integrations.Cod
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw new RConException("Timed out waiting for access to RCon receive socket");
|
||||
}
|
||||
finally
|
||||
{
|
||||
_log.LogDebug("OnReceived did not complete in time");
|
||||
if (connectionState.OnSentData.CurrentCount == 0)
|
||||
{
|
||||
connectionState.OnSentData.Release();
|
||||
}
|
||||
|
||||
throw new RConException("Timed out waiting for access to RCon receive socket");
|
||||
}
|
||||
|
||||
connectionState.SendEventArgs.UserToken = new ConnectionUserToken
|
||||
@ -242,6 +258,7 @@ namespace Integrations.Cod
|
||||
|
||||
if ((response?.Length == 0 || response[0].Length == 0) && waitForResponse)
|
||||
{
|
||||
_log.LogDebug("0 bytes received from rcon request");
|
||||
throw new RConException("Expected response but got 0 bytes back");
|
||||
}
|
||||
|
||||
@ -252,6 +269,7 @@ namespace Integrations.Cod
|
||||
{
|
||||
// if we timed out due to the cancellation token,
|
||||
// we don't want to count that as an attempt
|
||||
_log.LogDebug("OperationCanceledException when waiting for payload send to complete");
|
||||
connectionState.ConnectionAttempts = 0;
|
||||
}
|
||||
catch
|
||||
@ -265,7 +283,8 @@ namespace Integrations.Cod
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return Array.Empty<string>();
|
||||
_log.LogDebug("OperationCancelled while waiting for retry");
|
||||
throw;
|
||||
}
|
||||
|
||||
goto retrySend;
|
||||
@ -311,11 +330,13 @@ namespace Integrations.Cod
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
var responseString = type == StaticHelpers.QueryType.COMMAND_STATUS ?
|
||||
ReassembleSegmentedStatus(response) : RecombineMessages(response);
|
||||
var responseString = type == StaticHelpers.QueryType.COMMAND_STATUS
|
||||
? ReassembleSegmentedStatus(response)
|
||||
: RecombineMessages(response);
|
||||
|
||||
// note: not all games respond if the password is wrong or not set
|
||||
if (responseString.Contains("Invalid password") || responseString.Contains("rconpassword"))
|
||||
if (responseString.Contains("Invalid password", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
responseString.Contains("rconpassword"))
|
||||
{
|
||||
throw new RConException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_RCON_INVALID"]);
|
||||
}
|
||||
@ -327,11 +348,14 @@ namespace Integrations.Cod
|
||||
|
||||
if (responseString.Contains(_config.ServerNotRunningResponse))
|
||||
{
|
||||
throw new ServerException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_NOT_RUNNING"].FormatExt(Endpoint.ToString()));
|
||||
throw new ServerException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_NOT_RUNNING"]
|
||||
.FormatExt(Endpoint.ToString()));
|
||||
}
|
||||
|
||||
var responseHeaderMatch = Regex.Match(responseString, _config.CommandPrefixes.RConResponse).Value;
|
||||
var headerSplit = responseString.Split(type == StaticHelpers.QueryType.GET_INFO ? _config.CommandPrefixes.RconGetInfoResponseHeader : responseHeaderMatch);
|
||||
var headerSplit = responseString.Split(type == StaticHelpers.QueryType.GET_INFO
|
||||
? _config.CommandPrefixes.RconGetInfoResponseHeader
|
||||
: responseHeaderMatch);
|
||||
|
||||
if (headerSplit.Length != 2)
|
||||
{
|
||||
@ -369,7 +393,8 @@ namespace Integrations.Cod
|
||||
|
||||
else
|
||||
{
|
||||
splitStatusStrings.Add(responseString.Replace(_config.CommandPrefixes.RConResponse, "").TrimEnd('\0'));
|
||||
splitStatusStrings.Add(responseString.Replace(_config.CommandPrefixes.RConResponse, "")
|
||||
.TrimEnd('\0'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -396,8 +421,10 @@ namespace Integrations.Cod
|
||||
{
|
||||
message = message.Replace(_config.CommandPrefixes.RConResponse, "");
|
||||
}
|
||||
|
||||
builder.Append(message);
|
||||
}
|
||||
|
||||
builder.Append('\n');
|
||||
return builder.ToString();
|
||||
}
|
||||
@ -410,6 +437,7 @@ namespace Integrations.Cod
|
||||
|
||||
if (rconSocket is null)
|
||||
{
|
||||
_log.LogDebug("Invalid state");
|
||||
throw new InvalidOperationException("State is not valid for socket operation");
|
||||
}
|
||||
|
||||
@ -419,6 +447,7 @@ namespace Integrations.Cod
|
||||
// setup the event handlers only once because we're reusing the event args
|
||||
connectionState.SendEventArgs.Completed += OnDataSent;
|
||||
connectionState.ReceiveEventArgs.Completed += OnDataReceived;
|
||||
connectionState.ReceiveEventArgs.UserToken = connectionState.SendEventArgs.UserToken;
|
||||
connectionState.SendEventArgs.RemoteEndPoint = Endpoint;
|
||||
connectionState.ReceiveEventArgs.RemoteEndPoint = Endpoint;
|
||||
connectionState.ReceiveEventArgs.DisconnectReuseSocket = true;
|
||||
@ -438,7 +467,7 @@ namespace Integrations.Cod
|
||||
|
||||
if (!complete)
|
||||
{
|
||||
using(LogContext.PushProperty("Server", Endpoint.ToString()))
|
||||
using (LogContext.PushProperty("Server", Endpoint.ToString()))
|
||||
{
|
||||
_log.LogWarning("Socket timed out while sending RCon data on attempt {Attempt}",
|
||||
connectionState.ConnectionAttempts);
|
||||
@ -461,7 +490,8 @@ namespace Integrations.Cod
|
||||
|
||||
if (receiveDataPending)
|
||||
{
|
||||
_log.LogDebug("Waiting to asynchronously receive data on attempt #{ConnectionAttempts}", connectionState.ConnectionAttempts);
|
||||
_log.LogDebug("Waiting to asynchronously receive data on attempt #{ConnectionAttempts}",
|
||||
connectionState.ConnectionAttempts);
|
||||
|
||||
var completed = false;
|
||||
|
||||
@ -493,6 +523,7 @@ namespace Integrations.Cod
|
||||
}
|
||||
|
||||
rconSocket.Close();
|
||||
_log.LogDebug("OnDataReceived did not complete in allocated time");
|
||||
throw new NetworkException("Timed out receiving RCon response", rconSocket);
|
||||
}
|
||||
}
|
||||
@ -521,7 +552,8 @@ namespace Integrations.Cod
|
||||
|
||||
private void OnDataReceived(object sender, SocketAsyncEventArgs e)
|
||||
{
|
||||
_log.LogDebug("Read {BytesTransferred} bytes from {Endpoint}", e.BytesTransferred, e.RemoteEndPoint?.ToString());
|
||||
_log.LogDebug("Read {BytesTransferred} bytes from {Endpoint}", e.BytesTransferred,
|
||||
e.RemoteEndPoint?.ToString());
|
||||
|
||||
// this occurs when we close the socket
|
||||
if (e.BytesTransferred == 0)
|
||||
@ -638,7 +670,8 @@ namespace Integrations.Cod
|
||||
|
||||
private void OnDataSent(object sender, SocketAsyncEventArgs e)
|
||||
{
|
||||
_log.LogDebug("Sent {ByteCount} bytes to {Endpoint}", e.Buffer?.Length, e.ConnectSocket?.RemoteEndPoint?.ToString());
|
||||
_log.LogDebug("Sent {ByteCount} bytes to {Endpoint}", e.Buffer?.Length,
|
||||
e.ConnectSocket?.RemoteEndPoint?.ToString());
|
||||
|
||||
var semaphore = ActiveQueries[Endpoint].OnSentData;
|
||||
try
|
||||
|
@ -20,7 +20,7 @@ namespace Integrations.Cod
|
||||
public int ConnectionAttempts { get; set; }
|
||||
private const int BufferSize = 16384;
|
||||
public readonly byte[] ReceiveBuffer = new byte[BufferSize];
|
||||
public readonly SemaphoreSlim OnComplete = new SemaphoreSlim(1, 1);
|
||||
public readonly SemaphoreSlim OnComplete = new(1, 1);
|
||||
public readonly SemaphoreSlim OnSentData = new(1, 1);
|
||||
public readonly SemaphoreSlim OnReceivedData = new (1, 1);
|
||||
|
||||
|
@ -482,7 +482,7 @@ const pollForEvents = server => {
|
||||
if (!state.waitingOnOutput) {
|
||||
if (state.queuedMessages.length === 0) {
|
||||
logger.WriteDebug('No messages in queue');
|
||||
return;``
|
||||
return;
|
||||
}
|
||||
|
||||
state.waitingOnOutput = true;
|
||||
|
Loading…
Reference in New Issue
Block a user