diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
commit | 6352e8e3196f78388b6c771073f9e03eaa612673 (patch) | |
tree | e23772f79a7fbc41bc9108951e9e136857484bf4 /source/server/StarServerRconClient.cpp | |
parent | 6741a057e5639280d85d0f88ba26f000baa58f61 (diff) |
everything everywhere
all at once
Diffstat (limited to 'source/server/StarServerRconClient.cpp')
-rw-r--r-- | source/server/StarServerRconClient.cpp | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/source/server/StarServerRconClient.cpp b/source/server/StarServerRconClient.cpp new file mode 100644 index 0000000..a42a8ea --- /dev/null +++ b/source/server/StarServerRconClient.cpp @@ -0,0 +1,145 @@ +#include "StarServerRconThread.hpp" +#include "StarServerRconClient.hpp" +#include "StarLogging.hpp" +#include "StarRoot.hpp" +#include "StarConfiguration.hpp" +#include "StarUniverseServer.hpp" +#include "StarLexicalCast.hpp" + +namespace Star { + +ServerRconClient::ServerRconClient(UniverseServer* universe, TcpSocketPtr socket) + : Thread("RconClient"), + m_universe(universe), + m_socket(socket), + m_packetBuffer(MaxPacketSize), + m_stop(true), + m_authed(false) { + auto& root = Root::singleton(); + auto cfg = root.configuration(); + + m_packetBuffer.setByteOrder(ByteOrder::LittleEndian); + m_packetBuffer.setNullTerminatedStrings(true); + + m_rconPassword = cfg->get("rconServerPassword").toString(); +} + +ServerRconClient::~ServerRconClient() { + stop(); + join(); +} + +String ServerRconClient::handleCommand(String commandLine) { + String command = commandLine.extract(); + + if (command == "echo") { + return commandLine; + } else if (command == "broadcast" || command == "say") { + m_universe->adminBroadcast(commandLine); + return strf("OK: said %s", commandLine); + } else if (command == "stop") { + m_universe->stop(); + return "OK: shutting down"; + } else { + return m_universe->adminCommand(strf("%s %s", command, commandLine)); + } +} + +void ServerRconClient::receive(size_t size) { + m_packetBuffer.reset(size); + auto ptr = m_packetBuffer.ptr(); + while (size > 0) { + size_t r = m_socket->receive(ptr, size); + if (r == 0) + throw NoMoreRequests(); + size -= r; + ptr += r; + } +} + +void ServerRconClient::send(uint32_t requestId, uint32_t cmd, String str) { + m_packetBuffer.clear(); + m_packetBuffer << (uint32_t)(str.utf8Size() + 10) << requestId << cmd << str << (uint8_t)0x00; + m_socket->send(m_packetBuffer.ptr(), m_packetBuffer.size()); +} + +void ServerRconClient::sendAuthFailure() { + send(SERVERDATA_AUTH_FAILURE, SERVERDATA_AUTH_RESPONSE, ""); +} + +void ServerRconClient::sendCmdResponse(uint32_t requestId, String response) { + size_t len = response.length(); + // Always send at least one packet even if the response was blank + do { + auto dataLen = (len >= MaxPacketSize) ? MaxPacketSize : len; + send(requestId, SERVERDATA_RESPONSE_VALUE, response.substr(0, dataLen)); + response = response.substr(dataLen); + len = response.length(); + } while (len > 0); +} + +void ServerRconClient::start() { + m_stop = false; + Thread::start(); +} + +void ServerRconClient::stop() { + m_stop = true; + m_socket->close(); +} + +void ServerRconClient::processRequest() { + receive(4); + uint32_t size = m_packetBuffer.read<uint32_t>(); + + receive(size); + uint32_t requestId; + m_packetBuffer >> requestId; + + uint32_t cmd; + m_packetBuffer >> cmd; + + switch (cmd) { + case SERVERDATA_AUTH: { + String password; + m_packetBuffer >> password; + if (!m_rconPassword.empty() && m_rconPassword.equals(password)) { + m_authed = true; + send(requestId, SERVERDATA_RESPONSE_VALUE); + send(requestId, SERVERDATA_AUTH_RESPONSE); + } else { + m_authed = false; + sendAuthFailure(); + } + break; + } + case SERVERDATA_EXECCOMMAND: + if (m_authed) { + String command; + m_packetBuffer >> command; + try { + Logger::info("RCON %s: %s", m_socket->remoteAddress(), command); + sendCmdResponse(requestId, handleCommand(command)); + } catch (std::exception const& e) { + sendCmdResponse(requestId, strf("RCON: Error executing: %s: %s", command, outputException(e, true))); + } + } else { + sendAuthFailure(); + } + break; + default: + sendCmdResponse(requestId, strf("Unknown request %06x", cmd)); + } +} + +void ServerRconClient::run() { + try { + while (!m_stop) + processRequest(); + } catch (NoMoreRequests const&) { + } catch (std::exception const& e) { + Logger::error("ServerRconClient exception caught: %s", outputException(e, false)); + } +} + +} |