Migrated RCON server to cNetwork API.
This commit is contained in:
parent
059af2efdc
commit
9e61ad8c74
@ -38,6 +38,43 @@ enum
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cRCONListenCallbacks:
|
||||||
|
|
||||||
|
class cRCONListenCallbacks:
|
||||||
|
public cNetwork::cListenCallbacks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cRCONListenCallbacks(cRCONServer & a_RCONServer, UInt16 a_Port):
|
||||||
|
m_RCONServer(a_RCONServer),
|
||||||
|
m_Port(a_Port)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** The RCON server instance that we're attached to. */
|
||||||
|
cRCONServer & m_RCONServer;
|
||||||
|
|
||||||
|
/** The port for which this instance is responsible. */
|
||||||
|
UInt16 m_Port;
|
||||||
|
|
||||||
|
// cNetwork::cListenCallbacks overrides:
|
||||||
|
virtual cTCPLink::cCallbacksPtr OnIncomingConnection(const AString & a_RemoteIPAddress, UInt16 a_RemotePort) override
|
||||||
|
{
|
||||||
|
LOG("RCON Client \"%s\" connected!", a_RemoteIPAddress.c_str());
|
||||||
|
return std::make_shared<cRCONServer::cConnection>(m_RCONServer, a_RemoteIPAddress);
|
||||||
|
}
|
||||||
|
virtual void OnAccepted(cTCPLink & a_Link) override {}
|
||||||
|
virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override
|
||||||
|
{
|
||||||
|
LOGWARNING("RCON server error on port %d: %d (%s)", m_Port, a_ErrorCode, a_ErrorMsg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cRCONCommandOutput:
|
// cRCONCommandOutput:
|
||||||
|
|
||||||
@ -77,9 +114,7 @@ protected:
|
|||||||
// cRCONServer:
|
// cRCONServer:
|
||||||
|
|
||||||
cRCONServer::cRCONServer(cServer & a_Server) :
|
cRCONServer::cRCONServer(cServer & a_Server) :
|
||||||
m_Server(a_Server),
|
m_Server(a_Server)
|
||||||
m_ListenThread4(*this, cSocket::IPv4, "RCON"),
|
|
||||||
m_ListenThread6(*this, cSocket::IPv6, "RCON")
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,8 +124,10 @@ cRCONServer::cRCONServer(cServer & a_Server) :
|
|||||||
|
|
||||||
cRCONServer::~cRCONServer()
|
cRCONServer::~cRCONServer()
|
||||||
{
|
{
|
||||||
m_ListenThread4.Stop();
|
for (auto srv: m_ListenServers)
|
||||||
m_ListenThread6.Stop();
|
{
|
||||||
|
srv->Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -112,42 +149,29 @@ void cRCONServer::Initialize(cIniFile & a_IniFile)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read and initialize both IPv4 and IPv6 ports for RCON
|
// Read the listening ports for RCON from config:
|
||||||
bool HasAnyPorts = false;
|
AStringVector Ports = ReadUpgradeIniPorts(a_IniFile, "RCON", "Ports", "PortsIPv4", "PortsIPv6", "25575");
|
||||||
AString Ports4 = a_IniFile.GetValueSet("RCON", "PortsIPv4", "25575");
|
|
||||||
if (m_ListenThread4.Initialize(Ports4))
|
// Start listening on each specified port:
|
||||||
|
for (auto port: Ports)
|
||||||
{
|
{
|
||||||
HasAnyPorts = true;
|
UInt16 PortNum = static_cast<UInt16>(atol(port.c_str()));
|
||||||
m_ListenThread4.Start();
|
if (PortNum == 0)
|
||||||
}
|
{
|
||||||
AString Ports6 = a_IniFile.GetValueSet("RCON", "PortsIPv6", "25575");
|
LOGINFO("Invalid RCON port value: \"%s\". Ignoring.", port.c_str());
|
||||||
if (m_ListenThread6.Initialize(Ports6))
|
continue;
|
||||||
{
|
}
|
||||||
HasAnyPorts = true;
|
auto Handle = cNetwork::Listen(PortNum, std::make_shared<cRCONListenCallbacks>(*this, PortNum));
|
||||||
m_ListenThread6.Start();
|
if (Handle->IsListening())
|
||||||
}
|
{
|
||||||
if (!HasAnyPorts)
|
m_ListenServers.push_back(Handle);
|
||||||
{
|
}
|
||||||
LOGWARNING("RCON is requested, but no ports are specified. Specify at least one port in PortsIPv4 or PortsIPv6. RCON is now disabled.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cRCONServer::OnConnectionAccepted(cSocket & a_Socket)
|
|
||||||
{
|
|
||||||
if (!a_Socket.IsValid())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("RCON Client \"%s\" connected!", a_Socket.GetIPString().c_str());
|
if (m_ListenServers.empty())
|
||||||
|
{
|
||||||
// Create a new cConnection object, it will be deleted when the connection is closed
|
LOGWARNING("RCON is enabled but no valid ports were found. RCON is not accessible.");
|
||||||
m_SocketThreads.AddClient(a_Socket, new cConnection(*this, a_Socket));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -157,11 +181,10 @@ void cRCONServer::OnConnectionAccepted(cSocket & a_Socket)
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cRCONServer::cConnection:
|
// cRCONServer::cConnection:
|
||||||
|
|
||||||
cRCONServer::cConnection::cConnection(cRCONServer & a_RCONServer, cSocket & a_Socket) :
|
cRCONServer::cConnection::cConnection(cRCONServer & a_RCONServer, const AString & a_IPAddress) :
|
||||||
m_IsAuthenticated(false),
|
m_IsAuthenticated(false),
|
||||||
m_RCONServer(a_RCONServer),
|
m_RCONServer(a_RCONServer),
|
||||||
m_Socket(a_Socket),
|
m_IPAddress(a_IPAddress)
|
||||||
m_IPAddress(a_Socket.GetIPString())
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,8 +192,19 @@ cRCONServer::cConnection::cConnection(cRCONServer & a_RCONServer, cSocket & a_So
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size)
|
void cRCONServer::cConnection::OnLinkCreated(cTCPLinkPtr a_Link)
|
||||||
{
|
{
|
||||||
|
m_Link = a_Link;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cRCONServer::cConnection::OnReceivedData(const char * a_Data, size_t a_Size)
|
||||||
|
{
|
||||||
|
ASSERT(m_Link != nullptr);
|
||||||
|
|
||||||
// Append data to the buffer:
|
// Append data to the buffer:
|
||||||
m_Buffer.append(a_Data, a_Size);
|
m_Buffer.append(a_Data, a_Size);
|
||||||
|
|
||||||
@ -184,49 +218,45 @@ bool cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size)
|
|||||||
LOGWARNING("Received an invalid RCON packet length (%d), dropping RCON connection to %s.",
|
LOGWARNING("Received an invalid RCON packet length (%d), dropping RCON connection to %s.",
|
||||||
Length, m_IPAddress.c_str()
|
Length, m_IPAddress.c_str()
|
||||||
);
|
);
|
||||||
m_RCONServer.m_SocketThreads.RemoveClient(this);
|
m_Link->Close();
|
||||||
m_Socket.CloseSocket();
|
m_Link.reset();
|
||||||
delete this;
|
return;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (Length > (int)(m_Buffer.size() + 4))
|
if (Length > static_cast<int>(m_Buffer.size() + 4))
|
||||||
{
|
{
|
||||||
// Incomplete packet yet, wait for more data to come
|
// Incomplete packet yet, wait for more data to come
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RequestID = IntFromBuffer(m_Buffer.data() + 4);
|
int RequestID = IntFromBuffer(m_Buffer.data() + 4);
|
||||||
int PacketType = IntFromBuffer(m_Buffer.data() + 8);
|
int PacketType = IntFromBuffer(m_Buffer.data() + 8);
|
||||||
if (!ProcessPacket(RequestID, PacketType, Length - 10, m_Buffer.data() + 12))
|
if (!ProcessPacket(RequestID, PacketType, Length - 10, m_Buffer.data() + 12))
|
||||||
{
|
{
|
||||||
m_RCONServer.m_SocketThreads.RemoveClient(this);
|
m_Link->Close();
|
||||||
m_Socket.CloseSocket();
|
m_Link.reset();
|
||||||
delete this;
|
return;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
m_Buffer.erase(0, Length + 4);
|
m_Buffer.erase(0, Length + 4);
|
||||||
} // while (m_Buffer.size() >= 14)
|
} // while (m_Buffer.size() >= 14)
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cRCONServer::cConnection::GetOutgoingData(AString & a_Data)
|
void cRCONServer::cConnection::OnRemoteClosed(void)
|
||||||
{
|
{
|
||||||
a_Data.assign(m_Outgoing);
|
m_Link.reset();
|
||||||
m_Outgoing.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cRCONServer::cConnection::SocketClosed(void)
|
void cRCONServer::cConnection::OnError(int a_ErrorCode, const AString & a_ErrorMsg)
|
||||||
{
|
{
|
||||||
m_RCONServer.m_SocketThreads.RemoveClient(this);
|
LOGD("Error in RCON connection %s: %d (%s)", m_IPAddress.c_str(), a_ErrorCode, a_ErrorMsg.c_str());
|
||||||
delete this;
|
m_Link.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -311,22 +341,21 @@ void cRCONServer::cConnection::IntToBuffer(int a_Value, char * a_Buffer)
|
|||||||
void cRCONServer::cConnection::SendResponse(int a_RequestID, int a_PacketType, int a_PayloadLength, const char * a_Payload)
|
void cRCONServer::cConnection::SendResponse(int a_RequestID, int a_PacketType, int a_PayloadLength, const char * a_Payload)
|
||||||
{
|
{
|
||||||
ASSERT((a_PayloadLength == 0) || (a_Payload != nullptr)); // Either zero data to send, or a valid payload ptr
|
ASSERT((a_PayloadLength == 0) || (a_Payload != nullptr)); // Either zero data to send, or a valid payload ptr
|
||||||
|
ASSERT(m_Link != nullptr);
|
||||||
|
|
||||||
char Buffer[4];
|
char Buffer[4];
|
||||||
int Length = a_PayloadLength + 10;
|
int Length = a_PayloadLength + 10;
|
||||||
IntToBuffer(Length, Buffer);
|
IntToBuffer(Length, Buffer);
|
||||||
m_Outgoing.append(Buffer, 4);
|
m_Link->Send(Buffer, 4);
|
||||||
IntToBuffer(a_RequestID, Buffer);
|
IntToBuffer(a_RequestID, Buffer);
|
||||||
m_Outgoing.append(Buffer, 4);
|
m_Link->Send(Buffer, 4);
|
||||||
IntToBuffer(a_PacketType, Buffer);
|
IntToBuffer(a_PacketType, Buffer);
|
||||||
m_Outgoing.append(Buffer, 4);
|
m_Link->Send(Buffer, 4);
|
||||||
if (a_PayloadLength > 0)
|
if (a_PayloadLength > 0)
|
||||||
{
|
{
|
||||||
m_Outgoing.append(a_Payload, a_PayloadLength);
|
m_Link->Send(a_Payload, a_PayloadLength);
|
||||||
}
|
}
|
||||||
m_Outgoing.push_back(0);
|
m_Link->Send("\0", 2); // Send two zero chars as the padding
|
||||||
m_Outgoing.push_back(0);
|
|
||||||
m_RCONServer.m_SocketThreads.NotifyWrite(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "OSSupport/SocketThreads.h"
|
#include "OSSupport/Network.h"
|
||||||
#include "OSSupport/ListenThread.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -24,8 +23,7 @@ class cIniFile;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cRCONServer :
|
class cRCONServer
|
||||||
public cListenThread::cCallback
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cRCONServer(cServer & a_Server);
|
cRCONServer(cServer & a_Server);
|
||||||
@ -35,72 +33,61 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class cRCONCommandOutput;
|
friend class cRCONCommandOutput;
|
||||||
|
friend class cRCONListenCallbacks;
|
||||||
|
|
||||||
class cConnection :
|
class cConnection :
|
||||||
public cSocketThreads::cCallback
|
public cTCPLink::cCallbacks
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cConnection(cRCONServer & a_RCONServer, cSocket & a_Socket);
|
cConnection(cRCONServer & a_RCONServer, const AString & a_IPAddress);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class cRCONCommandOutput;
|
friend class cRCONCommandOutput;
|
||||||
|
|
||||||
/// Set to true if the client has successfully authenticated
|
/** Set to true if the client has successfully authenticated */
|
||||||
bool m_IsAuthenticated;
|
bool m_IsAuthenticated;
|
||||||
|
|
||||||
/// Buffer for the incoming data
|
/** Buffer for the incoming data */
|
||||||
AString m_Buffer;
|
AString m_Buffer;
|
||||||
|
|
||||||
/// Buffer for the outgoing data
|
/** Server that owns this connection and processes requests */
|
||||||
AString m_Outgoing;
|
|
||||||
|
|
||||||
/// Server that owns this connection and processes requests
|
|
||||||
cRCONServer & m_RCONServer;
|
cRCONServer & m_RCONServer;
|
||||||
|
|
||||||
/// The socket belonging to the client
|
/** The TCP link to the client */
|
||||||
cSocket & m_Socket;
|
cTCPLinkPtr m_Link;
|
||||||
|
|
||||||
/// Address of the client
|
/** Address of the client */
|
||||||
AString m_IPAddress;
|
AString m_IPAddress;
|
||||||
|
|
||||||
|
|
||||||
// cSocketThreads::cCallback overrides:
|
// cTCPLink::cCallbacks overrides:
|
||||||
virtual bool DataReceived(const char * a_Data, size_t a_Size) override;
|
virtual void OnLinkCreated(cTCPLinkPtr a_Link);
|
||||||
virtual void GetOutgoingData(AString & a_Data) override;
|
virtual void OnReceivedData(const char * a_Data, size_t a_Length) override;
|
||||||
virtual void SocketClosed(void) override;
|
virtual void OnRemoteClosed(void) override;
|
||||||
|
virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override;
|
||||||
|
|
||||||
/// Processes the given packet and sends the response; returns true if successful, false if the connection is to be dropped
|
/** Processes the given packet and sends the response; returns true if successful, false if the connection is to be dropped */
|
||||||
bool ProcessPacket(int a_RequestID, int a_PacketType, int a_PayloadLength, const char * a_Payload);
|
bool ProcessPacket(int a_RequestID, int a_PacketType, int a_PayloadLength, const char * a_Payload);
|
||||||
|
|
||||||
/// Reads 4 bytes from a_Buffer and returns the int they represent
|
/** Reads 4 bytes from a_Buffer and returns the int they represent */
|
||||||
int IntFromBuffer(const char * a_Buffer);
|
int IntFromBuffer(const char * a_Buffer);
|
||||||
|
|
||||||
/// Puts 4 bytes representing the int into the buffer
|
/** Puts 4 bytes representing the int into the buffer */
|
||||||
void IntToBuffer(int a_Value, char * a_Buffer);
|
void IntToBuffer(int a_Value, char * a_Buffer);
|
||||||
|
|
||||||
/// Sends a RCON packet back to the client
|
/** Sends a RCON packet back to the client */
|
||||||
void SendResponse(int a_RequestID, int a_PacketType, int a_PayloadLength, const char * a_Payload);
|
void SendResponse(int a_RequestID, int a_PacketType, int a_PayloadLength, const char * a_Payload);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
/// The server object that will process the commands received
|
/** The server object that will process the commands received */
|
||||||
cServer & m_Server;
|
cServer & m_Server;
|
||||||
|
|
||||||
/// The thread(s) that take care of all the traffic on the RCON ports
|
/** The sockets for accepting RCON connections (one socket per port). */
|
||||||
cSocketThreads m_SocketThreads;
|
cServerHandlePtrs m_ListenServers;
|
||||||
|
|
||||||
/// The thread for accepting IPv4 RCON connections
|
/** Password for authentication */
|
||||||
cListenThread m_ListenThread4;
|
|
||||||
|
|
||||||
/// The thread for accepting IPv6 RCON connections
|
|
||||||
cListenThread m_ListenThread6;
|
|
||||||
|
|
||||||
/// Password for authentication
|
|
||||||
AString m_Password;
|
AString m_Password;
|
||||||
|
|
||||||
|
|
||||||
// cListenThread::cCallback overrides:
|
|
||||||
virtual void OnConnectionAccepted(cSocket & a_Socket) override;
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user