IW4M-Admin/SharedLibrary/RCON.cs
RaidMax 11d37d4cd6 Added high ping kick functionality to Welcome Plugin
Added response to RCON command if applicable
Added more maps into the map config
2017-06-07 17:08:29 -04:00

147 lines
5.1 KiB
C#

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;
namespace SharedLibrary.Network
{
public static class RCON
{
enum QueryType
{
GET_STATUS,
GET_INFO,
DVAR,
COMMAND,
}
static string[] SendQuery(QueryType Type, Server QueryServer, string Parameters = "")
{
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'));
} while (ServerOOBConnection.Available > 0 && ServerOOBConnection.Client.Connected);
ServerOOBConnection.Close();
if (QueryResponseString.ToString().Contains("Invalid password"))
throw new Exceptions.NetworkException("RCON password is invalid");
int num = int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
string[] SplitResponse = QueryResponseString.ToString().Split(new char[] { (char)num }, StringSplitOptions.RemoveEmptyEntries);
return SplitResponse;
}
catch (SocketException)
{
attempts++;
if (attempts > 5)
{
var e = new Exceptions.NetworkException("Cannot communicate with server");
e.Data["server_address"] = ServerOOBConnection.Client.RemoteEndPoint.ToString();
ServerOOBConnection.Close();
throw e;
}
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 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 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, $"{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)
{
string[] response = await Task.FromResult(SendQuery(QueryType.DVAR, server, "status"));
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;
}
}
}