diff options
author | Mattes D <github@xoft.cz> | 2015-01-24 13:31:42 +0100 |
---|---|---|
committer | Mattes D <github@xoft.cz> | 2015-01-27 14:53:27 +0100 |
commit | 9e61ad8c74191210b0c0151a4b5bdbd88956a74d (patch) | |
tree | bd5ff097449fcbfd6ae8aa4fcbe7fd639f32b62e /src/RCONServer.cpp | |
parent | Fixed a crash in RCON server. (diff) | |
download | cuberite-9e61ad8c74191210b0c0151a4b5bdbd88956a74d.tar cuberite-9e61ad8c74191210b0c0151a4b5bdbd88956a74d.tar.gz cuberite-9e61ad8c74191210b0c0151a4b5bdbd88956a74d.tar.bz2 cuberite-9e61ad8c74191210b0c0151a4b5bdbd88956a74d.tar.lz cuberite-9e61ad8c74191210b0c0151a4b5bdbd88956a74d.tar.xz cuberite-9e61ad8c74191210b0c0151a4b5bdbd88956a74d.tar.zst cuberite-9e61ad8c74191210b0c0151a4b5bdbd88956a74d.zip |
Diffstat (limited to 'src/RCONServer.cpp')
-rw-r--r-- | src/RCONServer.cpp | 155 |
1 files changed, 92 insertions, 63 deletions
diff --git a/src/RCONServer.cpp b/src/RCONServer.cpp index 49ca4fc61..2ec7f191f 100644 --- a/src/RCONServer.cpp +++ b/src/RCONServer.cpp @@ -39,6 +39,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: class cRCONCommandOutput : @@ -77,9 +114,7 @@ protected: // cRCONServer: cRCONServer::cRCONServer(cServer & a_Server) : - m_Server(a_Server), - m_ListenThread4(*this, cSocket::IPv4, "RCON"), - m_ListenThread6(*this, cSocket::IPv6, "RCON") + m_Server(a_Server) { } @@ -89,8 +124,10 @@ cRCONServer::cRCONServer(cServer & a_Server) : cRCONServer::~cRCONServer() { - m_ListenThread4.Stop(); - m_ListenThread6.Stop(); + for (auto srv: m_ListenServers) + { + srv->Close(); + } } @@ -112,24 +149,28 @@ void cRCONServer::Initialize(cIniFile & a_IniFile) return; } - // Read and initialize both IPv4 and IPv6 ports for RCON - bool HasAnyPorts = false; - AString Ports4 = a_IniFile.GetValueSet("RCON", "PortsIPv4", "25575"); - if (m_ListenThread4.Initialize(Ports4)) - { - HasAnyPorts = true; - m_ListenThread4.Start(); - } - AString Ports6 = a_IniFile.GetValueSet("RCON", "PortsIPv6", "25575"); - if (m_ListenThread6.Initialize(Ports6)) + // Read the listening ports for RCON from config: + AStringVector Ports = ReadUpgradeIniPorts(a_IniFile, "RCON", "Ports", "PortsIPv4", "PortsIPv6", "25575"); + + // Start listening on each specified port: + for (auto port: Ports) { - HasAnyPorts = true; - m_ListenThread6.Start(); + UInt16 PortNum = static_cast<UInt16>(atol(port.c_str())); + if (PortNum == 0) + { + LOGINFO("Invalid RCON port value: \"%s\". Ignoring.", port.c_str()); + continue; + } + auto Handle = cNetwork::Listen(PortNum, std::make_shared<cRCONListenCallbacks>(*this, PortNum)); + if (Handle->IsListening()) + { + m_ListenServers.push_back(Handle); + } } - if (!HasAnyPorts) + + if (m_ListenServers.empty()) { - LOGWARNING("RCON is requested, but no ports are specified. Specify at least one port in PortsIPv4 or PortsIPv6. RCON is now disabled."); - return; + LOGWARNING("RCON is enabled but no valid ports were found. RCON is not accessible."); } } @@ -137,40 +178,33 @@ void cRCONServer::Initialize(cIniFile & a_IniFile) -void cRCONServer::OnConnectionAccepted(cSocket & a_Socket) -{ - if (!a_Socket.IsValid()) - { - return; - } +//////////////////////////////////////////////////////////////////////////////// +// cRCONServer::cConnection: - LOG("RCON Client \"%s\" connected!", a_Socket.GetIPString().c_str()); - - // Create a new cConnection object, it will be deleted when the connection is closed - m_SocketThreads.AddClient(a_Socket, new cConnection(*this, a_Socket)); +cRCONServer::cConnection::cConnection(cRCONServer & a_RCONServer, const AString & a_IPAddress) : + m_IsAuthenticated(false), + m_RCONServer(a_RCONServer), + m_IPAddress(a_IPAddress) +{ } -//////////////////////////////////////////////////////////////////////////////// -// cRCONServer::cConnection: - -cRCONServer::cConnection::cConnection(cRCONServer & a_RCONServer, cSocket & a_Socket) : - m_IsAuthenticated(false), - m_RCONServer(a_RCONServer), - m_Socket(a_Socket), - m_IPAddress(a_Socket.GetIPString()) +void cRCONServer::cConnection::OnLinkCreated(cTCPLinkPtr a_Link) { + m_Link = a_Link; } -bool cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size) +void cRCONServer::cConnection::OnReceivedData(const char * a_Data, size_t a_Size) { + ASSERT(m_Link != nullptr); + // Append data to the buffer: 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.", Length, m_IPAddress.c_str() ); - m_RCONServer.m_SocketThreads.RemoveClient(this); - m_Socket.CloseSocket(); - delete this; - return false; + m_Link->Close(); + m_Link.reset(); + return; } - 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 - return false; + return; } int RequestID = IntFromBuffer(m_Buffer.data() + 4); int PacketType = IntFromBuffer(m_Buffer.data() + 8); if (!ProcessPacket(RequestID, PacketType, Length - 10, m_Buffer.data() + 12)) { - m_RCONServer.m_SocketThreads.RemoveClient(this); - m_Socket.CloseSocket(); - delete this; - return false; + m_Link->Close(); + m_Link.reset(); + return; } m_Buffer.erase(0, Length + 4); } // 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_Outgoing.clear(); + m_Link.reset(); } -void cRCONServer::cConnection::SocketClosed(void) +void cRCONServer::cConnection::OnError(int a_ErrorCode, const AString & a_ErrorMsg) { - m_RCONServer.m_SocketThreads.RemoveClient(this); - delete this; + LOGD("Error in RCON connection %s: %d (%s)", m_IPAddress.c_str(), a_ErrorCode, a_ErrorMsg.c_str()); + 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) { ASSERT((a_PayloadLength == 0) || (a_Payload != nullptr)); // Either zero data to send, or a valid payload ptr + ASSERT(m_Link != nullptr); char Buffer[4]; int Length = a_PayloadLength + 10; IntToBuffer(Length, Buffer); - m_Outgoing.append(Buffer, 4); + m_Link->Send(Buffer, 4); IntToBuffer(a_RequestID, Buffer); - m_Outgoing.append(Buffer, 4); + m_Link->Send(Buffer, 4); IntToBuffer(a_PacketType, Buffer); - m_Outgoing.append(Buffer, 4); + m_Link->Send(Buffer, 4); if (a_PayloadLength > 0) { - m_Outgoing.append(a_Payload, a_PayloadLength); + m_Link->Send(a_Payload, a_PayloadLength); } - m_Outgoing.push_back(0); - m_Outgoing.push_back(0); - m_RCONServer.m_SocketThreads.NotifyWrite(this); + m_Link->Send("\0", 2); // Send two zero chars as the padding } |