IW4M-Admin/SharedLibrary/RCON.cs

163 lines
5.8 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Net.Sockets;
using SharedLibrary.Objects;
namespace SharedLibrary.Network
{
public static class RCON
{
enum QueryType
{
GET_STATUS,
GET_INFO,
DVAR,
COMMAND,
}
private static DateTime LastQuery;
static string[] SendQuery(QueryType Type, Server QueryServer, string Parameters = "")
{
if ((DateTime.Now - LastQuery).TotalMilliseconds < 300)
Task.Delay(300).Wait();
LastQuery = DateTime.Now;
var ServerOOBConnection = new UdpClient();
ServerOOBConnection.Client.SendTimeout = 1000;
ServerOOBConnection.Client.ReceiveTimeout = 1000;
var Endpoint = new IPEndPoint(IPAddress.Parse(QueryServer.GetIP()), QueryServer.GetPort());
string QueryString = String.Empty;
switch (Type)
{
case QueryType.DVAR:
case QueryType.COMMAND:
QueryString = $"ÿÿÿÿrcon {QueryServer.Password} {Parameters}";
break;
case QueryType.GET_STATUS:
QueryString = "ÿÿÿÿ getstatus";
break;
}
byte[] Payload = GetRequestBytes(QueryString);
int attempts = 0;
retry:
try
{
ServerOOBConnection.Connect(Endpoint);
ServerOOBConnection.Send(Payload, Payload.Length);
byte[] ReceiveBuffer = new byte[8192];
StringBuilder QueryResponseString = new StringBuilder();
do
{
ReceiveBuffer = ServerOOBConnection.Receive(ref Endpoint);
QueryResponseString.Append(Encoding.ASCII.GetString(ReceiveBuffer).TrimEnd('\0'));
2017-06-05 22:49:26 -04:00
} while (ServerOOBConnection.Available > 0 && ServerOOBConnection.Client.Connected);
ServerOOBConnection.Close();
if (QueryResponseString.ToString().Contains("Invalid password"))
throw new Exceptions.NetworkException("RCON password is invalid");
if (QueryResponseString.ToString().Contains("rcon_password"))
throw new Exceptions.NetworkException("RCON password has not been set");
int num = int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
string[] SplitResponse = QueryResponseString.ToString().Split(new char[] { (char)num }, StringSplitOptions.RemoveEmptyEntries);
return SplitResponse;
}
catch (Exceptions.NetworkException e)
{
throw e;
}
2017-11-13 16:58:23 -05:00
catch (Exception e)
{
attempts++;
2017-11-13 16:58:23 -05:00
if (attempts > 2)
{
2017-11-13 16:58:23 -05:00
var ne = new Exceptions.NetworkException("Could not communicate with the server");
ne.Data["internal_exception"] = e.Message;
ne.Data["server_address"] = ServerOOBConnection.Client.RemoteEndPoint.ToString();
ServerOOBConnection.Close();
2017-11-13 16:58:23 -05:00
throw ne;
}
Thread.Sleep(1000);
goto retry;
}
}
public static async Task<DVAR<T>> GetDvarAsync<T>(this Server server, string dvarName)
{
string[] LineSplit = await Task.FromResult(SendQuery(QueryType.DVAR, server, dvarName));
if (LineSplit.Length != 3)
{
var e = new Exceptions.DvarException($"DVAR \"{dvarName}\" does not exist");
e.Data["dvar_name"] = dvarName;
throw e;
}
string[] ValueSplit = LineSplit[1].Split(new char[] { '"' }, StringSplitOptions.RemoveEmptyEntries);
if (ValueSplit.Length != 5)
{
var e = new Exceptions.DvarException($"DVAR \"{dvarName}\" does not exist");
e.Data["dvar_name"] = dvarName;
throw e;
}
string DvarName = Regex.Replace(ValueSplit[0], @"\^[0-9]", "");
string DvarCurrentValue = Regex.Replace(ValueSplit[2], @"\^[0-9]", "");
string DvarDefaultValue = Regex.Replace(ValueSplit[4], @"\^[0-9]", "");
return new DVAR<T>(DvarName) { Value = (T)Convert.ChangeType(DvarCurrentValue, typeof(T)) };
}
public static async Task SetDvarAsync(this Server server, string dvarName, object dvarValue)
{
await Task.FromResult(SendQuery(QueryType.DVAR, server, $"set {dvarName} {dvarValue}"));
}
public static async Task<string[]> ExecuteCommandAsync(this Server server, string commandName)
{
return await Task.FromResult(SendQuery(QueryType.COMMAND, server, commandName).Skip(1).ToArray());
}
public static async Task<List<Player>> GetStatusAsync(this Server server)
{
#if DEBUG && DEBUG_PLAYERS
string[] response = await Task.Run(() => System.IO.File.ReadAllLines("players.txt"));
#else
string[] response = await Task.FromResult(SendQuery(QueryType.DVAR, server, "status"));
#endif
return Utilities.PlayersFromStatus(response);
}
static byte[] GetRequestBytes(string Request)
{
Byte[] initialRequestBytes = Encoding.Unicode.GetBytes(Request);
Byte[] fixedRequest = new Byte[initialRequestBytes.Length / 2];
for (int i = 0; i < initialRequestBytes.Length; i++)
if (initialRequestBytes[i] != 0)
fixedRequest[i / 2] = initialRequestBytes[i];
return fixedRequest;
}
}
}