Added rcon packet handling.
This commit is contained in:
parent
811f7ab1dc
commit
a465943eee
5 changed files with 270 additions and 6 deletions
|
|
@ -67,6 +67,9 @@ namespace TShockAPI
|
|||
|
||||
public int MaximumLoginAttempts = 3;
|
||||
|
||||
public string RconPassword = "";
|
||||
public int RconPort = 7778;
|
||||
|
||||
public static ConfigFile Read(string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
|
|
|
|||
253
TShockAPI/RconHandler.cs
Normal file
253
TShockAPI/RconHandler.cs
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
TShock, a server mod for Terraria
|
||||
Copyright (C) 2011 The TShock Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using Terraria;
|
||||
|
||||
namespace TShockAPI
|
||||
{
|
||||
class RconHandler
|
||||
{
|
||||
public static string Password = "";
|
||||
private static DateTime lastRequest;
|
||||
public static int ListenPort;
|
||||
public static bool ContinueServer = true;
|
||||
public static string Response = "";
|
||||
|
||||
public static void StartThread()
|
||||
{
|
||||
(new Thread(Start)).Start();
|
||||
}
|
||||
|
||||
public static void Start()
|
||||
{
|
||||
Log.Info("Starting RconHandler.");
|
||||
try
|
||||
{
|
||||
Console.WriteLine(string.Format("RconHandler is running at UDP port {0} and password is {1}",
|
||||
ListenPort.ToString(),
|
||||
Password));
|
||||
Thread listen = new Thread(new ThreadStart(Listener));
|
||||
listen.Start();
|
||||
while (true)
|
||||
{
|
||||
if (listen.ThreadState != ThreadState.Running)
|
||||
{
|
||||
listen.Abort();
|
||||
while (listen.ThreadState != ThreadState.Stopped)
|
||||
continue;
|
||||
listen.Start();
|
||||
}
|
||||
Thread.Sleep(3000);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static void Listener()
|
||||
{
|
||||
while (ContinueServer)
|
||||
{
|
||||
UdpClient listener = new UdpClient(ListenPort);
|
||||
try
|
||||
{
|
||||
var listenEP = new IPEndPoint(IPAddress.Any, ListenPort);
|
||||
lastRequest = DateTime.Now;
|
||||
byte[] bytes = listener.Receive(ref listenEP);
|
||||
Log.Info(string.Format("Recieved packet from {0}:{1}", listenEP.Address.ToString(), listenEP.Port.ToString()));
|
||||
var packet = parsePacket(bytes, listenEP);
|
||||
listener.Send(packet, packet.Length, listenEP);
|
||||
listener.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e.ToString());
|
||||
listener.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string sendPacket(byte[] bytes, string hostname, int port)
|
||||
{
|
||||
var response = Encoding.UTF8.GetString(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }) + "disconnect";
|
||||
try
|
||||
{
|
||||
var EP = new IPEndPoint(IPAddress.Any, port);
|
||||
UdpClient client = new UdpClient();
|
||||
client.Connect(hostname, port);
|
||||
client.Client.ReceiveTimeout = 500;
|
||||
client.Send(bytes, bytes.Length);
|
||||
response = Encoding.UTF8.GetString(client.Receive(ref EP));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e.ToString());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private static byte[] parsePacket(byte[] bytes, IPEndPoint EP)
|
||||
{
|
||||
string response = "";
|
||||
var packetstring = Encoding.UTF8.GetString(padPacket(bytes));
|
||||
var redirect = false;
|
||||
var print = true;
|
||||
if ((DateTime.Now - lastRequest).Milliseconds >= 100)
|
||||
{
|
||||
if (packetstring.StartsWith("rcon") || packetstring.Substring(4).StartsWith("rcon") || packetstring.Substring(5).StartsWith("rcon"))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Password))
|
||||
{
|
||||
var args = packetstring.Split(' ');
|
||||
if (args.Length >= 3)
|
||||
{
|
||||
if (args[1] == Password)
|
||||
{
|
||||
string command = "";
|
||||
for (int i = 2; i < args.Length; i++)
|
||||
command += args[i] + " ";
|
||||
command = command.TrimEnd(' ').TrimEnd('\0');
|
||||
response = executeCommand(command);
|
||||
if (response == "" && Response != "")
|
||||
{
|
||||
response = Response;
|
||||
Response = "";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
response = "Invalid password.";
|
||||
Log.ConsoleInfo("Bad rcon password from " + EP.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
response = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
response = "The server must set a password for clients to use rcon.";
|
||||
Log.Info("No password for rcon set");
|
||||
}
|
||||
}
|
||||
else
|
||||
redirect = true;
|
||||
}
|
||||
if (!redirect)
|
||||
return (constructPacket(response, print));
|
||||
else
|
||||
return (constructPacket("", false));
|
||||
}
|
||||
|
||||
private static string executeCommand(string text)
|
||||
{
|
||||
if (Main.rand == null)
|
||||
Main.rand = new Random();
|
||||
if (WorldGen.genRand == null)
|
||||
WorldGen.genRand = new Random();
|
||||
if (text.StartsWith("exit"))
|
||||
{
|
||||
Tools.ForceKickAll("Server shutting down!");
|
||||
return "Server shutting down.";
|
||||
}
|
||||
else if (text.StartsWith("playing") || text.StartsWith("/playing"))
|
||||
{
|
||||
int count = 0;
|
||||
foreach (TSPlayer player in TShock.Players)
|
||||
{
|
||||
if (player != null && player.Active)
|
||||
{
|
||||
count++;
|
||||
TSPlayer.Server.SendMessage(string.Format("{0} ({1}) [{2}]", player.Name, player.IP, player.Group.Name));
|
||||
}
|
||||
}
|
||||
TSPlayer.Server.SendMessage(string.Format("{0} players connected.", count));
|
||||
}
|
||||
else if (text.StartsWith("status"))
|
||||
{
|
||||
Response += "map: " + Main.worldName + "\n";
|
||||
Response += "num score ping name\tlastmsg address\tqport rate\n";
|
||||
int count = 0;
|
||||
foreach (TSPlayer player in TShock.Players)
|
||||
{
|
||||
if (player != null && player.Active)
|
||||
{
|
||||
count++;
|
||||
Response += (string.Format("{0} 0 0 {1}({2})\t{3} {4}\t0 0", count, player.Name, player.Group.Name, Netplay.serverSock[player.Index].tcpClient.Client.RemoteEndPoint.ToString())) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (text.StartsWith("say "))
|
||||
{
|
||||
Log.Info(string.Format("Server said: {0}", text.Remove(0, 4)));
|
||||
return string.Format("Server said: {0}", text.Remove(0, 4));
|
||||
}
|
||||
else if (text == "autosave")
|
||||
{
|
||||
Main.autoSave = TShock.Config.AutoSave = !TShock.Config.AutoSave;
|
||||
Log.ConsoleInfo("AutoSave " + (TShock.Config.AutoSave ? "Enabled" : "Disabled"));
|
||||
return "AutoSave " + (TShock.Config.AutoSave ? "Enabled" : "Disabled");
|
||||
}
|
||||
else
|
||||
if (!Commands.HandleCommand(TSPlayer.Server, text))
|
||||
return "Invalid command.";
|
||||
return "";
|
||||
}
|
||||
|
||||
private static byte[] constructPacket(string response, bool print)
|
||||
{
|
||||
var oob = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
MemoryStream stream = new MemoryStream();
|
||||
BinaryWriter writer = new BinaryWriter(stream);
|
||||
writer.Write(oob);
|
||||
if (print)
|
||||
writer.Write(Encoding.UTF8.GetBytes(string.Format("print\n{0}", response)));
|
||||
else
|
||||
writer.Write(Encoding.UTF8.GetBytes("disconnect\n"));
|
||||
var packet = Encoding.UTF8.GetBytes(
|
||||
(Encoding.UTF8.GetString(stream.GetBuffer())
|
||||
.Substring(0, (int)stream.Length)));
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static byte[] padPacket(byte[] packet)
|
||||
{
|
||||
var returnpacket = new byte[(4 + packet.Length)];
|
||||
int h = 0;
|
||||
if (packet[0] != 0xFF)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
returnpacket[i] = 0xFF;
|
||||
for (int i = 4; i < returnpacket.Length; i++)
|
||||
returnpacket[i] = packet[h++];
|
||||
}
|
||||
else
|
||||
returnpacket = packet;
|
||||
return returnpacket;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -370,6 +370,7 @@ namespace TShockAPI
|
|||
public override void SendMessage(string msg, byte red, byte green, byte blue)
|
||||
{
|
||||
Console.WriteLine(msg);
|
||||
RconHandler.Response += msg + "\n";
|
||||
}
|
||||
|
||||
public void SetBloodMoon(bool bloodMoon)
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ namespace TShockAPI
|
|||
RegionManager.ReadAllSettings();
|
||||
WarpsManager.ReadAllSettings();
|
||||
ItemManager.LoadBans();
|
||||
RconHandler.StartThread();
|
||||
|
||||
Log.ConsoleInfo("AutoSave " + (TShock.Config.AutoSave ? "Enabled" : "Disabled"));
|
||||
Log.ConsoleInfo("Backups " + (Backups.Interval > 0 ? "Enabled" : "Disabled"));
|
||||
|
|
@ -373,6 +374,8 @@ namespace TShockAPI
|
|||
if (text.StartsWith("exit"))
|
||||
{
|
||||
Tools.ForceKickAll("Server shutting down!");
|
||||
WorldGen.saveWorld(false);
|
||||
Netplay.disconnect = true;
|
||||
}
|
||||
else if (text.StartsWith("playing") || text.StartsWith("/playing"))
|
||||
{
|
||||
|
|
@ -595,6 +598,9 @@ namespace TShockAPI
|
|||
Netplay.serverPort = file.ServerPort;
|
||||
|
||||
Netplay.spamCheck = file.SpamChecks;
|
||||
|
||||
RconHandler.Password = file.RconPassword;
|
||||
RconHandler.ListenPort = file.RconPort;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@
|
|||
<Compile Include="Log.cs" />
|
||||
<Compile Include="Net\NetTile.cs" />
|
||||
<Compile Include="Net\WorldInfoMsg.cs" />
|
||||
<Compile Include="RconHandler.cs" />
|
||||
<Compile Include="RegionManager.cs" />
|
||||
<Compile Include="RememberPosManager.cs" />
|
||||
<Compile Include="Resources.Designer.cs">
|
||||
|
|
@ -149,11 +150,11 @@
|
|||
<UserProperties BuildVersion_IncrementBeforeBuild="False" BuildVersion_StartDate="2011/6/17" BuildVersion_BuildVersioningStyle="None.None.None.MonthAndDayStamp" BuildVersion_BuildAction="Both" BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
Loading…
Add table
Add a link
Reference in a new issue