From 9c8644e64563e373917d222da4a464c5556cf005 Mon Sep 17 00:00:00 2001 From: Amos <48657826+Mauler125@users.noreply.github.com> Date: Sun, 13 Feb 2022 15:10:38 +0100 Subject: [PATCH] Implement stream serialization/deserialization in RCON server and client --- r5dev/engine/sv_rcon.cpp | 198 ++++++++++++++++++------- r5dev/engine/sv_rcon.h | 17 ++- r5dev/netconsole/netconsole.cpp | 246 ++++++++++++++++++++++++++------ r5dev/netconsole/netconsole.h | 16 ++- r5dev/protobuf.vcxproj | 4 + 5 files changed, 377 insertions(+), 104 deletions(-) diff --git a/r5dev/engine/sv_rcon.cpp b/r5dev/engine/sv_rcon.cpp index c1710c3e..49d50bd5 100644 --- a/r5dev/engine/sv_rcon.cpp +++ b/r5dev/engine/sv_rcon.cpp @@ -1,7 +1,7 @@ //===========================================================================// -// -// Purpose: Implementation of the rcon server -// +// +// Purpose: Implementation of the rcon server. +// //===========================================================================// #include "core/stdafx.h" @@ -12,6 +12,8 @@ #include "tier2/socketcreator.h" #include "engine/sys_utils.h" #include "engine/sv_rcon.h" +#include "protoc/sv_rcon.pb.h" +#include "protoc/cl_rcon.pb.h" #include "mathlib/sha256.h" #include "client/IVEngineClient.h" #include "common/igameserverdata.h" @@ -23,11 +25,10 @@ void CRConServer::Init(void) { if (std::strlen(rcon_password->GetString()) < 8) { - if (std::strlen(rcon_password->GetString()) != 0) + if (std::strlen(rcon_password->GetString()) > 0) { DevMsg(eDLL_T::SERVER, "Remote server access requires a password of at least 8 characters\n"); } - if (m_pSocket->IsListening()) { m_pSocket->CloseListenSocket(); @@ -69,7 +70,7 @@ void CRConServer::Think(void) } } - // Create a new listen socket if authenticated socket is closed. + // Create a new listen socket if authenticated connection is closed. if (nCount == 0) { if (!m_pSocket->IsListening()) @@ -93,10 +94,10 @@ void CRConServer::RunFrame(void) } //----------------------------------------------------------------------------- -// Purpose: process outgoing packet -// Input : *pszBuf - +// Purpose: send message +// Input : svMessage - //----------------------------------------------------------------------------- -void CRConServer::Send(const char* pszBuf) +void CRConServer::Send(const std::string& svMessage) const { int nCount = m_pSocket->GetAcceptedSocketCount(); @@ -106,41 +107,40 @@ void CRConServer::Send(const char* pszBuf) if (pData->m_bAuthorized) { - ::send(pData->m_hSocket, pszBuf, strlen(pszBuf), MSG_NOSIGNAL); + std::string svFinal = this->Serialize(svMessage, "", sv_rcon::response_t::SERVERDATA_RESPONSE_CONSOLE_LOG); + ::send(pData->m_hSocket, svFinal.c_str(), static_cast(svFinal.size()), MSG_NOSIGNAL); } } } //----------------------------------------------------------------------------- -// Purpose: process incoming packet +// Purpose: receive message //----------------------------------------------------------------------------- void CRConServer::Recv(void) { int nCount = m_pSocket->GetAcceptedSocketCount(); + static char szRecvBuf[MAX_NETCONSOLE_INPUT_LEN]{}; for (m_nConnIndex = nCount - 1; m_nConnIndex >= 0; m_nConnIndex--) { CConnectedNetConsoleData* pData = m_pSocket->GetAcceptedSocketData(m_nConnIndex); - {////////////////////////////////////////////// if (CheckForBan(pData)) { - ::send(pData->m_hSocket, s_pszBannedMessage, strlen(s_pszBannedMessage), MSG_NOSIGNAL); - CloseConnection(); + std::string svNoAuth = this->Serialize(s_pszBannedMessage, "", sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH); + ::send(pData->m_hSocket, svNoAuth.c_str(), static_cast(svNoAuth.size()), MSG_NOSIGNAL); + this->CloseConnection(); continue; } - char szRecvBuf{}; - int nPendingLen = ::recv(pData->m_hSocket, &szRecvBuf, sizeof(szRecvBuf), MSG_PEEK); - + int nPendingLen = ::recv(pData->m_hSocket, szRecvBuf, sizeof(szRecvBuf), MSG_PEEK); if (nPendingLen == SOCKET_ERROR && m_pSocket->IsSocketBlocking()) { continue; } - if (nPendingLen <= 0) // EOF or error. { - CloseConnection(); + this->CloseConnection(); continue; } }////////////////////////////////////////////// @@ -148,30 +148,75 @@ void CRConServer::Recv(void) u_long nReadLen; // Find out how much we have to read. ::ioctlsocket(pData->m_hSocket, FIONREAD, &nReadLen); - while (nReadLen > 0 && nReadLen < MAX_NETCONSOLE_INPUT_LEN -1) + while (nReadLen > 0) { - char szRecvBuf[MAX_NETCONSOLE_INPUT_LEN]{}; - int nRecvLen = ::recv(pData->m_hSocket, szRecvBuf, MIN(sizeof(szRecvBuf), nReadLen), 0); + memset(szRecvBuf, '\0', sizeof(szRecvBuf)); + int nRecvLen = ::recv(pData->m_hSocket, szRecvBuf, MIN(sizeof(szRecvBuf), nReadLen), MSG_NOSIGNAL); if (nRecvLen == 0) // Socket was closed. { - CloseConnection(); + this->CloseConnection(); break; } - if (nRecvLen < 0 && !m_pSocket->IsSocketBlocking()) { break; } - nReadLen -= nRecvLen; - - // Write what we've got into the command buffer. - HandleInputChars(szRecvBuf, nRecvLen, pData); + nReadLen -= nRecvLen; // Process what we've got. + this->ProcessBuffer(szRecvBuf, nRecvLen, pData); } } } +//----------------------------------------------------------------------------- +// Purpose: serializes input +// Input : svRspBuf - +// svRspVal - +// response_t - +// Output : serialized results as string +//----------------------------------------------------------------------------- +std::string CRConServer::Serialize(const std::string& svRspBuf, const std::string& svRspVal, sv_rcon::response_t response_t) const +{ + sv_rcon::response sv_response; + + sv_response.set_responseid(-1); // TODO + sv_response.set_responsetype(response_t); + + switch (response_t) + { + case sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH: + { + sv_response.set_responsebuf(svRspBuf); + break; + } + case sv_rcon::response_t::SERVERDATA_RESPONSE_CONSOLE_LOG: + { + sv_response.set_responsebuf(svRspBuf); + sv_response.set_responseval(""); + break; + } + default: + { + break; + } + } + return sv_response.SerializeAsString().append("\r"); +} + +//----------------------------------------------------------------------------- +// Purpose: de-serializes input +// Input : svBuf - +// Output : de-serialized object +//----------------------------------------------------------------------------- +cl_rcon::request CRConServer::Deserialize(const std::string& svBuf) const +{ + cl_rcon::request cl_request; + cl_request.ParseFromArray(svBuf.c_str(), static_cast(svBuf.size())); + + return cl_request; +} + //----------------------------------------------------------------------------- // Purpose: authenticate new connections // Input : *pData - @@ -179,16 +224,16 @@ void CRConServer::Recv(void) // password in plain text over the wire. create a cvar for this so user could // also opt out and use legacy authentication instead for older RCON clients //----------------------------------------------------------------------------- -void CRConServer::Auth(CConnectedNetConsoleData* pData) +void CRConServer::Authenticate(const cl_rcon::request& cl_request, CConnectedNetConsoleData* pData) { if (pData->m_bAuthorized) { return; } - else if (std::memcmp(pData->m_pszInputCommandBuffer, "PASS ", 5) == 0) + else if (strcmp(cl_request.requestbuf().c_str(), "PASS") == 0) { - if (std::strcmp(pData->m_pszInputCommandBuffer + 5, rcon_password->GetString()) == 0) - { // TODO: Hash and compare password with SHA256 instead! + if (strcmp(cl_request.requestval().c_str(), rcon_password->GetString()) == 0) + {// TODO: Hash and compare password with SHA256 instead! pData->m_bAuthorized = true; m_pSocket->CloseListenSocket(); this->CloseNonAuthConnection(); @@ -197,17 +242,14 @@ void CRConServer::Auth(CConnectedNetConsoleData* pData) { CNetAdr2 netAdr2 = m_pSocket->GetAcceptedSocketAddress(m_nConnIndex); DevMsg(eDLL_T::SERVER, "Bad RCON password attempt from '%s'\n", netAdr2.GetIPAndPort().c_str()); - ::send(pData->m_hSocket, s_pszWrongPwMessage, strlen(s_pszWrongPwMessage), MSG_NOSIGNAL); + + std::string svWrongPass = this->Serialize(s_pszBannedMessage, "", sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH); + ::send(pData->m_hSocket, svWrongPass.c_str(), static_cast(svWrongPass.size()), MSG_NOSIGNAL); pData->m_bAuthorized = false; pData->m_nFailedAttempts++; } } - else - { - ::send(pData->m_hSocket, s_pszNoAuthMessage, strlen(s_pszNoAuthMessage), MSG_NOSIGNAL); - pData->m_nIgnoredMessage++; - } } //----------------------------------------------------------------------------- @@ -216,25 +258,18 @@ void CRConServer::Auth(CConnectedNetConsoleData* pData) // nRecvLen - // *pData - //----------------------------------------------------------------------------- -void CRConServer::HandleInputChars(const char* pszIn, int nRecvLen, CConnectedNetConsoleData* pData) +void CRConServer::ProcessBuffer(const char* pszIn, int nRecvLen, CConnectedNetConsoleData* pData) { while (nRecvLen) { switch (*pszIn) { case '\r': - case '\n': { if (pData->m_nCharsInCommandBuffer) { - pData->m_pszInputCommandBuffer[pData->m_nCharsInCommandBuffer] = 0; - this->Auth(pData); - - // Only execute if auth was succesfull. - if (pData->m_bAuthorized) - { - this->Execute(pData); - } + cl_rcon::request cl_request = this->Deserialize(pData->m_pszInputCommandBuffer); + this->ProcessMessage(cl_request); } pData->m_nCharsInCommandBuffer = 0; break; @@ -254,12 +289,71 @@ void CRConServer::HandleInputChars(const char* pszIn, int nRecvLen, CConnectedNe } //----------------------------------------------------------------------------- -// Purpose: execute commands issued from net console -// Input : *pData - +// Purpose: processes received message +// Input : *cl_request - //----------------------------------------------------------------------------- -void CRConServer::Execute(CConnectedNetConsoleData* pData) +void CRConServer::ProcessMessage(const cl_rcon::request& cl_request) { - IVEngineClient_CommandExecute(NULL, pData->m_pszInputCommandBuffer); + CConnectedNetConsoleData* pData = m_pSocket->GetAcceptedSocketData(m_nConnIndex); + + if (!pData->m_bAuthorized + && cl_request.requesttype() != cl_rcon::request_t::SERVERDATA_REQUEST_AUTH) + { + // Notify net console that authentication is required. + std::string svMessage = this->Serialize(s_pszNoAuthMessage, "", sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH); + ::send(pData->m_hSocket, svMessage.c_str(), static_cast(svMessage.size()), MSG_NOSIGNAL); + + pData->m_nIgnoredMessage++; + return; + } + switch (cl_request.requesttype()) + { + case cl_rcon::request_t::SERVERDATA_REQUEST_AUTH: + { + this->Authenticate(cl_request, pData); + break; + } + case cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND: + case cl_rcon::request_t::SERVERDATA_REQUEST_SETVALUE: + { + // Only execute if auth was succesfull. + if (pData->m_bAuthorized) + { + this->Execute(cl_request); + } + break; + } + case cl_rcon::request_t::SERVERDATA_REQUEST_SEND_CONSOLE_LOG: + { + if (pData->m_bAuthorized) + { + // TODO: Send conlog to true. + } + break; + } + default: + { + break; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: execute commands issued from net console +// Input : *cl_request - +//----------------------------------------------------------------------------- +void CRConServer::Execute(const cl_rcon::request& cl_request) const +{ + ConVar* pConVar = g_pCVar->FindVar(cl_request.requestbuf().c_str()); + if (pConVar) + { + pConVar->SetValue(cl_request.requestval().c_str()); + } + else // Execute command with "". + { + std::string svExec = cl_request.requestbuf() + " \"" + cl_request.requestval() + "\""; + IVEngineClient_CommandExecute(NULL, svExec.c_str()); + } } //----------------------------------------------------------------------------- diff --git a/r5dev/engine/sv_rcon.h b/r5dev/engine/sv_rcon.h index 3da7064a..30db0303 100644 --- a/r5dev/engine/sv_rcon.h +++ b/r5dev/engine/sv_rcon.h @@ -1,7 +1,8 @@ #pragma once #include "tier1/NetAdr2.h" #include "tier2/socketcreator.h" -#include "common/igameserverdata.h" +#include "protoc/sv_rcon.pb.h" +#include "protoc/cl_rcon.pb.h" constexpr char s_pszNoAuthMessage[] = "This server is password protected for console access. Must send 'PASS ' command.\n\r"; constexpr char s_pszWrongPwMessage[] = "Password incorrect.\n\r"; @@ -15,14 +16,20 @@ public: void RunFrame(void); + void Send(const std::string& svMessage) const; void Recv(void); - void Send(const char* pszBuf); - void Auth(CConnectedNetConsoleData* pData); - void HandleInputChars(const char* pszIn, int nRecvLen, CConnectedNetConsoleData* pData); - void Execute(CConnectedNetConsoleData* pData); + std::string Serialize(const std::string& svRspBuf, const std::string& svRspVal, sv_rcon::response_t response_t) const; + cl_rcon::request Deserialize(const std::string& svBuf) const; + void Authenticate(const cl_rcon::request& cl_request, CConnectedNetConsoleData* pData); + + void ProcessBuffer(const char* pszIn, int nRecvLen, CConnectedNetConsoleData* pData); + void ProcessMessage(const cl_rcon::request& cl_request); + + void Execute(const cl_rcon::request& cl_request) const; bool CheckForBan(CConnectedNetConsoleData* pData); + void CloseConnection(void); void CloseNonAuthConnection(void); diff --git a/r5dev/netconsole/netconsole.cpp b/r5dev/netconsole/netconsole.cpp index 12cbb1ac..c6fc1d29 100644 --- a/r5dev/netconsole/netconsole.cpp +++ b/r5dev/netconsole/netconsole.cpp @@ -1,17 +1,19 @@ //=====================================================================================// -// +// // Purpose: Lightweight netconsole client. -// +// //=====================================================================================// #include "core/stdafx.h" #include "core/termutil.h" #include "tier1/NetAdr2.h" #include "tier2/socketcreator.h" +#include "protoc/sv_rcon.pb.h" +#include "protoc/cl_rcon.pb.h" #include "netconsole/netconsole.h" //----------------------------------------------------------------------------- -// purpose: WSA and NETCON systems init +// Purpose: WSA and NETCON systems init // Output : true on success, false otherwise //----------------------------------------------------------------------------- bool CNetCon::Init(void) @@ -34,7 +36,7 @@ bool CNetCon::Init(void) } //----------------------------------------------------------------------------- -// purpose: WSA and NETCON systems shutdown +// Purpose: WSA and NETCON systems shutdown // Output : true on success, false otherwise //----------------------------------------------------------------------------- bool CNetCon::Shutdown(void) @@ -52,7 +54,7 @@ bool CNetCon::Shutdown(void) } //----------------------------------------------------------------------------- -// purpose: terminal setup +// Purpose: terminal setup //----------------------------------------------------------------------------- void CNetCon::TermSetup(void) { @@ -90,7 +92,7 @@ void CNetCon::TermSetup(void) } //----------------------------------------------------------------------------- -// purpose: gets input IP and port for initialization +// Purpose: gets input IP and port for initialization //----------------------------------------------------------------------------- void CNetCon::UserInput(void) { @@ -103,15 +105,46 @@ void CNetCon::UserInput(void) m_bQuitApplication = true; return; } - if (m_abConnEstablished) { - this->Send(svInput); + if (strcmp(svInput.c_str(), "disconnect") == 0) + { + this->Disconnect(); + return; + } + size_t nPos = svInput.find(" "); + if (!svInput.empty() + && nPos > 0 + && nPos < svInput.size() + && nPos != svInput.size()) + { + std::string svReqVal = svInput.substr(nPos + 1); + std::string svReqBuf = svInput.erase(svInput.find(" ")); + + if (strcmp(svReqBuf.c_str(), "PASS") == 0) // Auth with RCON server. + { + std::string svSerialized = this->Serialize(svReqBuf, svReqVal, cl_rcon::request_t::SERVERDATA_REQUEST_AUTH); + this->Send(svSerialized); + } + else // This is a ConVar. + { + std::string svSerialized = this->Serialize(svReqBuf, svReqVal, cl_rcon::request_t::SERVERDATA_REQUEST_SETVALUE); + this->Send(svSerialized); + } + } + else // This is a ConCommand. + { + std::string svSerialized = this->Serialize(svInput, "", cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND); + this->Send(svSerialized); + } } else // Setup connection from input. { size_t nPos = svInput.find(" "); - if (!svInput.empty() && nPos > 0 && nPos < svInput.size()) + if (!svInput.empty() + && nPos > 0 + && nPos < svInput.size() + && nPos != svInput.size()) { std::string svInPort = svInput.substr(nPos + 1); std::string svInAdr = svInput.erase(svInput.find(" ")); @@ -135,7 +168,7 @@ void CNetCon::UserInput(void) } //----------------------------------------------------------------------------- -// purpose: client's main processing loop +// Purpose: client's main processing loop //----------------------------------------------------------------------------- void CNetCon::RunFrame(void) { @@ -143,7 +176,7 @@ void CNetCon::RunFrame(void) { if (m_abConnEstablished) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); this->Recv(); } else if (m_abPromptConnect) @@ -155,21 +188,21 @@ void CNetCon::RunFrame(void) } //----------------------------------------------------------------------------- -// purpose: checks if application should be terminated +// Purpose: checks if application should be terminated // Output : true for termination, false otherwise //----------------------------------------------------------------------------- -bool CNetCon::ShouldQuit(void) +bool CNetCon::ShouldQuit(void) const { return this->m_bQuitApplication; } //----------------------------------------------------------------------------- -// purpose: connect to specified address and port +// Purpose: connect to specified address and port // Input : svInAdr - // svInPort - // Output : true if connection succeeds, false otherwise //----------------------------------------------------------------------------- -bool CNetCon::Connect(std::string svInAdr, std::string svInPort) +bool CNetCon::Connect(const std::string& svInAdr, const std::string& svInPort) { if (svInAdr.size() > 0 && svInPort.size() > 0) { @@ -189,38 +222,45 @@ bool CNetCon::Connect(std::string svInAdr, std::string svInPort) } //----------------------------------------------------------------------------- -// purpose: send message +// Purpose: disconnect from current session //----------------------------------------------------------------------------- -void CNetCon::Send(std::string svMessage) +void CNetCon::Disconnect(void) { - svMessage.append("\n\r"); - int nSendResult = ::send(m_pSocket->GetAcceptedSocketData(0)->m_hSocket, svMessage.c_str(), svMessage.size(), MSG_NOSIGNAL); + ::closesocket(m_pSocket->GetAcceptedSocketHandle(0)); + m_abPromptConnect = true; + m_abConnEstablished = false; } //----------------------------------------------------------------------------- -// purpose: receive message +// Purpose: send message +// Input : svMessage - +//----------------------------------------------------------------------------- +void CNetCon::Send(const std::string& svMessage) const +{ + int nSendResult = ::send(m_pSocket->GetAcceptedSocketData(0)->m_hSocket, svMessage.c_str(), svMessage.size(), MSG_NOSIGNAL); + if (nSendResult == SOCKET_ERROR) + { + std::cout << "Failed to send message: SOCKET_ERROR." << std::endl; + } +} + +//----------------------------------------------------------------------------- +// Purpose: receive message //----------------------------------------------------------------------------- void CNetCon::Recv(void) { static char szRecvBuf[MAX_NETCONSOLE_INPUT_LEN]{}; - static std::regex rxAnsiExp("\\\033\\[.*?m"); - static std::string svOut; {////////////////////////////////////////////// - char szRecvBuf{}; - int nPendingLen = ::recv(m_pSocket->GetAcceptedSocketData(0)->m_hSocket, &szRecvBuf, sizeof(szRecvBuf), MSG_PEEK); - + int nPendingLen = ::recv(m_pSocket->GetAcceptedSocketData(0)->m_hSocket, szRecvBuf, sizeof(szRecvBuf), MSG_PEEK); if (nPendingLen == SOCKET_ERROR && m_pSocket->IsSocketBlocking()) { return; } - if (nPendingLen <= 0) // EOF or error. + if (nPendingLen <= 0 && m_abConnEstablished) // EOF or error. { - ::closesocket(m_pSocket->GetAcceptedSocketHandle(0)); + this->Disconnect(); std::cout << "Server closed connection." << std::endl; - - m_abPromptConnect = true; - m_abConnEstablished = false; return; } }////////////////////////////////////////////// @@ -228,26 +268,144 @@ void CNetCon::Recv(void) u_long nReadLen; // Find out how much we have to read. ::ioctlsocket(m_pSocket->GetAcceptedSocketData(0)->m_hSocket, FIONREAD, &nReadLen); - if (nReadLen > 0 && nReadLen < MAX_NETCONSOLE_INPUT_LEN - 1) + while (nReadLen > 0) { - int nRecvLen = ::recv(m_pSocket->GetAcceptedSocketData(0)->m_hSocket, szRecvBuf, sizeof(szRecvBuf), MSG_NOSIGNAL); - svOut = szRecvBuf; - - if (m_bNoColor) - { - svOut = std::regex_replace(svOut, rxAnsiExp, ""); - } - else - { - svOut.append(g_svReset.c_str()); - } - std::cout << svOut.c_str(); memset(szRecvBuf, '\0', sizeof(szRecvBuf)); + int nRecvLen = ::recv(m_pSocket->GetAcceptedSocketData(0)->m_hSocket, szRecvBuf, MIN(sizeof(szRecvBuf), nReadLen), MSG_NOSIGNAL); + + if (nRecvLen == 0 && m_abConnEstablished) // Socket was closed. + { + this->Disconnect(); + std::cout << "Server closed connection." << std::endl; + break; + } + if (nRecvLen < 0 && !m_pSocket->IsSocketBlocking()) + { + break; + } + + nReadLen -= nRecvLen; // Process what we've got. + this->ProcessBuffer(szRecvBuf, nRecvLen); } } //----------------------------------------------------------------------------- -// purpose: entrypoint +// Purpose: handles input response buffer +// Input : *pszIn - +// nRecvLen - +//----------------------------------------------------------------------------- +void CNetCon::ProcessBuffer(const char* pszIn, int nRecvLen) const +{ + int nCharsInRespondBuffer = 0; + char szInputRespondBuffer[MAX_NETCONSOLE_INPUT_LEN]{}; + + while (nRecvLen) + { + switch (*pszIn) + { + case '\r': + { + if (nCharsInRespondBuffer) + { + sv_rcon::response sv_response = this->Deserialize(szInputRespondBuffer); + this->ProcessMessage(sv_response); + } + nCharsInRespondBuffer = 0; + break; + } + + default: + if (nCharsInRespondBuffer < MAX_NETCONSOLE_INPUT_LEN - 1) + { + szInputRespondBuffer[nCharsInRespondBuffer++] = *pszIn; + } + break; + } + pszIn++; + nRecvLen--; + } +} + +//----------------------------------------------------------------------------- +// Purpose: processes received message +// Input : sv_response - +//----------------------------------------------------------------------------- +void CNetCon::ProcessMessage(const sv_rcon::response& sv_response) const +{ + static std::regex rxAnsiExp("\\\033\\[.*?m"); + switch (sv_response.responsetype()) + { + case sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH: + case sv_rcon::response_t::SERVERDATA_RESPONSE_CONSOLE_LOG: + { + std::string svOut = sv_response.responsebuf(); + if (m_bNoColor) + { + svOut = std::regex_replace(svOut, rxAnsiExp, ""); + } + else + { + svOut.append(g_svReset.c_str()); + } + std::cout << svOut.c_str(); + break; + } + default: + { + break; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: serializes input +// Input : svReqBuf - +// svReqVal - +// request_t - +// Output : serialized results as string +//----------------------------------------------------------------------------- +std::string CNetCon::Serialize(const std::string& svReqBuf, const std::string& svReqVal, cl_rcon::request_t request_t) const +{ + cl_rcon::request cl_request; + + cl_request.set_requestid(-1); + cl_request.set_requesttype(request_t); + + switch (request_t) + { + case cl_rcon::request_t::SERVERDATA_REQUEST_SETVALUE: + case cl_rcon::request_t::SERVERDATA_REQUEST_AUTH: + { + cl_request.set_requestbuf(svReqBuf); + cl_request.set_requestval(svReqVal); + break; + } + case cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND: + { + cl_request.set_requestbuf(svReqBuf); + break; + } + } + return cl_request.SerializeAsString().append("\r"); +} + +//----------------------------------------------------------------------------- +// Purpose: de-serializes input +// Input : pszBuf - +// Output : de-serialized object +//----------------------------------------------------------------------------- +sv_rcon::response CNetCon::Deserialize(std::string svBuf) const +{ + sv_rcon::response sv_response; + sv_response.ParseFromArray(svBuf.c_str(), static_cast(svBuf.size())); + + return sv_response; +} + +//----------------------------------------------------------------------------- +// Purpose: entrypoint +// Input : argc - +// *argv - //----------------------------------------------------------------------------- int main(int argc, char* argv[]) { diff --git a/r5dev/netconsole/netconsole.h b/r5dev/netconsole/netconsole.h index 1bd18583..e4a4f7f8 100644 --- a/r5dev/netconsole/netconsole.h +++ b/r5dev/netconsole/netconsole.h @@ -4,6 +4,8 @@ // //===========================================================================// #pragma once +#include "protoc/cl_rcon.pb.h" +#include "protoc/sv_rcon.pb.h" constexpr const char* NETCON_VERSION = "2.0.0.1"; @@ -17,12 +19,20 @@ public: void UserInput(void); void RunFrame(void); - bool ShouldQuit(void); + bool ShouldQuit(void) const; - bool Connect(std::string svInAdr, std::string svInPort); - void Send(std::string svMessage); + bool Connect(const std::string& svInAdr, const std::string& svInPort); + void Disconnect(void); + + void Send(const std::string& svMessage) const; void Recv(void); + void ProcessBuffer(const char* pszIn, int nRecvLen) const; + void ProcessMessage(const sv_rcon::response& sv_response) const; + + std::string Serialize(const std::string& svReqBuf, const std::string& svReqVal, cl_rcon::request_t request_t) const; + sv_rcon::response Deserialize(std::string svBuf) const; + private: CNetAdr2* m_pNetAdr2 = new CNetAdr2("localhost", "37015"); CSocketCreator* m_pSocket = new CSocketCreator(); diff --git a/r5dev/protobuf.vcxproj b/r5dev/protobuf.vcxproj index f5458989..ca5b17ab 100644 --- a/r5dev/protobuf.vcxproj +++ b/r5dev/protobuf.vcxproj @@ -105,6 +105,7 @@ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions) + stdcpp17 Console @@ -120,6 +121,7 @@ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions) + stdcpp17 Console @@ -135,6 +137,7 @@ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions) + stdcpp17 Console @@ -150,6 +153,7 @@ NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions) + stdcpp17 Console