diff --git a/r5dev/client/cdll_engine_int.cpp b/r5dev/client/cdll_engine_int.cpp index ad82fa21..33db3ec7 100644 --- a/r5dev/client/cdll_engine_int.cpp +++ b/r5dev/client/cdll_engine_int.cpp @@ -7,6 +7,7 @@ #include "client/client.h" #include "client/cdll_engine_int.h" #include "engine/net_chan.h" +#include "engine/cl_rcon.h" #include "public/include/bansystem.h" #include "vpc/keyvalues.h" #include "gameui/IConsole.h" @@ -31,15 +32,17 @@ void __fastcall HFrameStageNotify(CHLClient* rcx, ClientFrameStage_t frameStage) if (!g_pCmdLine->CheckParm("-devsdk")) { - IVEngineClient_CommandExecute(NULL, "exec autoexec_server.cfg"); - IVEngineClient_CommandExecute(NULL, "exec autoexec_client.cfg"); - IVEngineClient_CommandExecute(NULL, "exec autoexec.cfg"); + IVEngineClient_CommandExecute(NULL, "exec \"autoexec_server.cfg\""); + IVEngineClient_CommandExecute(NULL, "exec \"autoexec_client.cfg\""); + IVEngineClient_CommandExecute(NULL, "exec \"autoexec.cfg\""); + IVEngineClient_CommandExecute(NULL, "exec \"rcon_client.cfg\""); } else // Development configs. { - IVEngineClient_CommandExecute(NULL, "exec autoexec_server_dev.cfg"); - IVEngineClient_CommandExecute(NULL, "exec autoexec_client_dev.cfg"); - IVEngineClient_CommandExecute(NULL, "exec autoexec_dev.cfg"); + IVEngineClient_CommandExecute(NULL, "exec \"autoexec_server_dev.cfg\""); + IVEngineClient_CommandExecute(NULL, "exec \"autoexec_client_dev.cfg\""); + IVEngineClient_CommandExecute(NULL, "exec \"autoexec_dev.cfg\""); + IVEngineClient_CommandExecute(NULL, "exec \"rcon_client_dev.cfg\""); } *(bool*)m_bRestrictServerCommands = true; // Restrict commands. @@ -51,6 +54,7 @@ void __fastcall HFrameStageNotify(CHLClient* rcx, ClientFrameStage_t frameStage) HNET_GenerateKey(); } g_pCVar->FindVar("net_usesocketsforloopback")->SetValue(1); + g_pRConClient->Init(); bInitialized = true; } @@ -96,6 +100,7 @@ void __fastcall HFrameStageNotify(CHLClient* rcx, ClientFrameStage_t frameStage) } } g_pIConsole->Think(); + g_pRConClient->RunFrame(); CHLClient_FrameStageNotify(rcx, (int)frameStage); } diff --git a/r5dev/engine/cl_rcon.cpp b/r5dev/engine/cl_rcon.cpp index e670e473..fdc75d3b 100644 --- a/r5dev/engine/cl_rcon.cpp +++ b/r5dev/engine/cl_rcon.cpp @@ -1,14 +1,296 @@ //===========================================================================// -// -// Purpose: Implementation of the rcon client -// +// +// Purpose: Implementation of the rcon client. +// //===========================================================================// #include "core/stdafx.h" #include "tier0/IConVar.h" #include "tier0/cmd.h" #include "tier0/cvar.h" +#include "protoc/sv_rcon.pb.h" +#include "protoc/cl_rcon.pb.h" #include "engine/cl_rcon.h" +#include "engine/sys_utils.h" #include "common/igameserverdata.h" -// TODO.. \ No newline at end of file +//----------------------------------------------------------------------------- +// Purpose: NETCON systems init +//----------------------------------------------------------------------------- +void CRConClient::Init(void) +{ + if (std::strlen(rcon_password->GetString()) < 8) + { + if (std::strlen(rcon_password->GetString()) > 0) + { + DevMsg(eDLL_T::CLIENT, "Remote server access requires a password of at least 8 characters\n"); + } + m_bInitialized = false; + } + m_bInitialized = true; +} + +//----------------------------------------------------------------------------- +// Purpose: NETCON systems shutdown +//----------------------------------------------------------------------------- +void CRConClient::Shutdown(void) +{ + if (m_bConnEstablished) + { + this->Disconnect(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: client rcon main processing loop +//----------------------------------------------------------------------------- +void CRConClient::RunFrame(void) +{ + if (m_bInitialized && m_bConnEstablished) + { + this->Recv(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: connect to address and port stored in 'rcon_address' cvar +// Output : true if connection succeeds, false otherwise +//----------------------------------------------------------------------------- +bool CRConClient::Connect(void) +{ + if (strlen(rcon_address->GetString()) > 0) + { + // Default is [127.0.0.1]:37015 + m_pNetAdr2->SetIPAndPort(rcon_address->GetString()); + } + + if (m_pSocket->ConnectSocket(*m_pNetAdr2, true) == SOCKET_ERROR) + { + DevMsg(eDLL_T::CLIENT, "Connection to RCON server failed: (SOCKET_ERROR)\n"); + return false; + } + DevMsg(eDLL_T::CLIENT, "Connected to: %s\n", m_pNetAdr2->GetIPAndPort().c_str()); + + m_bConnEstablished = true; + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: connect to specified address and port +// Input : *svInAdr - +// *svInPort - +// Output : true if connection succeeds, false otherwise +//----------------------------------------------------------------------------- +bool CRConClient::Connect(const std::string& svInAdr, const std::string& svInPort) +{ + if (svInAdr.size() > 0 && svInPort.size() > 0) + { + // Default is [127.0.0.1]:37015 + m_pNetAdr2->SetIPAndPort(svInAdr, svInPort); + } + + if (m_pSocket->ConnectSocket(*m_pNetAdr2, true) == SOCKET_ERROR) + { + DevMsg(eDLL_T::CLIENT, "Connection to RCON server failed: (SOCKET_ERROR)\n"); + return false; + } + DevMsg(eDLL_T::CLIENT, "Connected to: %s\n", m_pNetAdr2->GetIPAndPort().c_str()); + + m_bConnEstablished = true; + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: disconnect from current session +//----------------------------------------------------------------------------- +void CRConClient::Disconnect(void) +{ + ::closesocket(m_pSocket->GetAcceptedSocketHandle(0)); + m_bConnEstablished = false; +} + +//----------------------------------------------------------------------------- +// Purpose: send message +// Input : *svMessage - +//----------------------------------------------------------------------------- +void CRConClient::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) + { + DevMsg(eDLL_T::CLIENT, "Failed to send RCON message: (SOCKET_ERROR)\n"); + } +} + +//----------------------------------------------------------------------------- +// Purpose: receive message +//----------------------------------------------------------------------------- +void CRConClient::Recv(void) +{ + static char szRecvBuf[MAX_NETCONSOLE_INPUT_LEN]{}; + + {////////////////////////////////////////////// + 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 && m_bConnEstablished) // EOF or error. + { + this->Disconnect(); + DevMsg(eDLL_T::CLIENT, "Server closed RCON connection\n"); + return; + } + }////////////////////////////////////////////// + + u_long nReadLen; // Find out how much we have to read. + ::ioctlsocket(m_pSocket->GetAcceptedSocketData(0)->m_hSocket, FIONREAD, &nReadLen); + + while (nReadLen > 0) + { + 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_bConnEstablished) // Socket was closed. + { + this->Disconnect(); + DevMsg(eDLL_T::CLIENT, "Server closed RCON connection\n"); + break; + } + if (nRecvLen < 0 && !m_pSocket->IsSocketBlocking()) + { + break; + } + + nReadLen -= nRecvLen; // Process what we've got. + this->ProcessBuffer(szRecvBuf, nRecvLen); + } +} + +//----------------------------------------------------------------------------- +// Purpose: handles input response buffer +// Input : *pszIn - +// nRecvLen - +//----------------------------------------------------------------------------- +void CRConClient::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 CRConClient::ProcessMessage(const sv_rcon::response& sv_response) const +{ + 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(); + + // TODO: Manipulate string.. + DevMsg(eDLL_T::NONE, "%s", svOut.c_str()); + break; + } + default: + { + break; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: serializes input +// Input : *svReqBuf - +// *svReqVal - +// request_t - +// Output : serialized results as string +//----------------------------------------------------------------------------- +std::string CRConClient::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 : *svBuf - +// Output : de-serialized object +//----------------------------------------------------------------------------- +sv_rcon::response CRConClient::Deserialize(const std::string& svBuf) const +{ + sv_rcon::response sv_response; + sv_response.ParseFromArray(svBuf.c_str(), static_cast(svBuf.size())); + + return sv_response; +} + +//----------------------------------------------------------------------------- +// Purpose: checks if client rcon is initialized +// Output : true if initialized, false otherwise +//----------------------------------------------------------------------------- +bool CRConClient::IsInitialized(void) const +{ + return this->m_bInitialized; +} + +//----------------------------------------------------------------------------- +// Purpose: checks if client rcon is connected +// Output : true if connected, false otherwise +//----------------------------------------------------------------------------- +bool CRConClient::IsConnected(void) const +{ + return this->m_bConnEstablished; +} + +CRConClient* g_pRConClient = new CRConClient(); \ No newline at end of file diff --git a/r5dev/engine/cl_rcon.h b/r5dev/engine/cl_rcon.h index ff77590b..ac317c14 100644 --- a/r5dev/engine/cl_rcon.h +++ b/r5dev/engine/cl_rcon.h @@ -1,10 +1,41 @@ #pragma once +#include "tier1/NetAdr2.h" +#include "tier2/SocketCreator.h" +#include "protoc/sv_rcon.pb.h" +#include "protoc/cl_rcon.pb.h" class CRConClient { +public: CRConClient(void){}; ~CRConClient(void){}; - void Authenticate(void){}; - void ProcessMessage(void){}; -}; \ No newline at end of file + void Init(void); + void Shutdown(void); + + void RunFrame(void); + + bool Connect(void); + 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(const std::string& svBuf) const; + + bool IsInitialized(void) const; + bool IsConnected(void) const; + +private: + CNetAdr2* m_pNetAdr2 = new CNetAdr2("localhost", "37015"); + CSocketCreator* m_pSocket = new CSocketCreator(); + + bool m_bInitialized = false; + bool m_bConnEstablished = false; +}; +extern CRConClient* g_pRConClient; \ No newline at end of file diff --git a/r5dev/engine/host_state.cpp b/r5dev/engine/host_state.cpp index 1643dfdf..a9bf438b 100644 --- a/r5dev/engine/host_state.cpp +++ b/r5dev/engine/host_state.cpp @@ -1,6 +1,6 @@ //=============================================================================// // -// Purpose: Runs the state machine for the host & server +// Purpose: Runs the state machine for the host & server. // //=============================================================================// @@ -19,6 +19,8 @@ #include "engine/sys_engine.h" #ifdef DEDICATED #include "engine/sv_rcon.h" +#else // +#include "engine/cl_rcon.h" #endif // DEDICATED //----------------------------------------------------------------------------- @@ -138,28 +140,30 @@ void HCHostState_FrameUpdate(void* rcx, void* rdx, float time) { if (!g_pCmdLine->CheckParm("-devsdk")) { - IVEngineClient_CommandExecute(NULL, "exec autoexec_server.cfg"); - IVEngineClient_CommandExecute(NULL, "exec rcon_server.cfg"); + IVEngineClient_CommandExecute(NULL, "exec \"autoexec_server.cfg\""); + IVEngineClient_CommandExecute(NULL, "exec \"rcon_server.cfg\""); #ifndef DEDICATED - IVEngineClient_CommandExecute(NULL, "exec autoexec_client.cfg"); - IVEngineClient_CommandExecute(NULL, "exec rcon_client.cfg"); + IVEngineClient_CommandExecute(NULL, "exec \"autoexec_client.cfg\""); + IVEngineClient_CommandExecute(NULL, "exec \"rcon_client.cfg\""); #endif // !DEDICATED - IVEngineClient_CommandExecute(NULL, "exec autoexec.cfg"); + IVEngineClient_CommandExecute(NULL, "exec \"autoexec.cfg\""); } else // Development configs. { - IVEngineClient_CommandExecute(NULL, "exec autoexec_server_dev.cfg"); - IVEngineClient_CommandExecute(NULL, "exec rcon_server_dev.cfg"); + IVEngineClient_CommandExecute(NULL, "exec \"autoexec_server_dev.cfg\""); + IVEngineClient_CommandExecute(NULL, "exec \"rcon_server_dev.cfg\""); #ifndef DEDICATED - IVEngineClient_CommandExecute(NULL, "exec autoexec_client_dev.cfg"); - IVEngineClient_CommandExecute(NULL, "exec rcon_client_dev.cfg"); + IVEngineClient_CommandExecute(NULL, "exec \"autoexec_client_dev.cfg\""); + IVEngineClient_CommandExecute(NULL, "exec \"rcon_client_dev.cfg\""); #endif // !DEDICATED - IVEngineClient_CommandExecute(NULL, "exec autoexec_dev.cfg"); + IVEngineClient_CommandExecute(NULL, "exec \"autoexec_dev.cfg\""); } g_pConVar->ClearHostNames(); #ifdef DEDICATED g_pRConServer->Init(); +#else // + g_pRConClient->Init(); #endif // DEDICATED *(bool*)m_bRestrictServerCommands = true; // Restrict commands. @@ -195,6 +199,8 @@ void HCHostState_FrameUpdate(void* rcx, void* rdx, float time) } #ifdef DEDICATED g_pRConServer->RunFrame(); +#else // + g_pRConClient->RunFrame(); #endif // DEDICATED HostStates_t oldState{}; diff --git a/r5dev/engine/sv_rcon.cpp b/r5dev/engine/sv_rcon.cpp index 0106c65c..e9130381 100644 --- a/r5dev/engine/sv_rcon.cpp +++ b/r5dev/engine/sv_rcon.cpp @@ -19,7 +19,7 @@ #include "common/igameserverdata.h" //----------------------------------------------------------------------------- -// Purpose: creates listen socket for RCON +// Purpose: NETCON systems init //----------------------------------------------------------------------------- void CRConServer::Init(void) { @@ -29,11 +29,7 @@ void CRConServer::Init(void) { DevMsg(eDLL_T::SERVER, "Remote server access requires a password of at least 8 characters\n"); } - if (m_pSocket->IsListening()) - { - m_pSocket->CloseListenSocket(); - } - m_bInitialized = false; + this->Shutdown(); return; } @@ -47,6 +43,18 @@ void CRConServer::Init(void) m_bInitialized = true; } +//----------------------------------------------------------------------------- +// Purpose: NETCON systems shutdown +//----------------------------------------------------------------------------- +void CRConServer::Shutdown(void) +{ + if (m_pSocket->IsListening()) + { + m_pSocket->CloseListenSocket(); + } + m_bInitialized = false; +} + //----------------------------------------------------------------------------- // Purpose: run tasks for the RCON server //----------------------------------------------------------------------------- @@ -65,7 +73,7 @@ void CRConServer::Think(void) CConnectedNetConsoleData* pData = m_pSocket->GetAcceptedSocketData(m_nConnIndex); if (!pData->m_bAuthorized) { - CloseConnection(); + this->CloseConnection(); } } } @@ -126,7 +134,7 @@ void CRConServer::Recv(void) { CConnectedNetConsoleData* pData = m_pSocket->GetAcceptedSocketData(m_nConnIndex); {////////////////////////////////////////////// - if (CheckForBan(pData)) + if (this->CheckForBan(pData)) { 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); diff --git a/r5dev/engine/sv_rcon.h b/r5dev/engine/sv_rcon.h index 97d711d7..22ed27e3 100644 --- a/r5dev/engine/sv_rcon.h +++ b/r5dev/engine/sv_rcon.h @@ -12,6 +12,7 @@ class CRConServer { public: void Init(void); + void Shutdown(void); void Think(void); void RunFrame(void); diff --git a/r5dev/netconsole/netconsole.cpp b/r5dev/netconsole/netconsole.cpp index ef185590..47472f7a 100644 --- a/r5dev/netconsole/netconsole.cpp +++ b/r5dev/netconsole/netconsole.cpp @@ -316,12 +316,14 @@ void CNetCon::ProcessBuffer(const char* pszIn, int nRecvLen) const } default: + { if (nCharsInRespondBuffer < MAX_NETCONSOLE_INPUT_LEN - 1) { szInputRespondBuffer[nCharsInRespondBuffer++] = *pszIn; } break; } + } pszIn++; nRecvLen--; } diff --git a/r5dev/tier0/cmd.cpp b/r5dev/tier0/cmd.cpp index 56b4c8a1..f2ba93c6 100644 --- a/r5dev/tier0/cmd.cpp +++ b/r5dev/tier0/cmd.cpp @@ -5,6 +5,71 @@ #include "client/client.h" #include "engine/sys_utils.h" +//----------------------------------------------------------------------------- +// Purpose: returns max command lenght +//----------------------------------------------------------------------------- +int CCommand::MaxCommandLength(void) +{ + return COMMAND_MAX_LENGTH - 1; +} + +//----------------------------------------------------------------------------- +// Purpose: returns argument count +//----------------------------------------------------------------------------- +std::int64_t CCommand::ArgC(void) const +{ + return m_nArgc; +} + +//----------------------------------------------------------------------------- +// Purpose: returns argument vector +//----------------------------------------------------------------------------- +const char** CCommand::ArgV(void) const +{ + return m_nArgc ? (const char**)m_ppArgv : NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: returns all args that occur after the 0th arg, in string form +//----------------------------------------------------------------------------- +const char* CCommand::ArgS(void) const +{ + return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : ""; +} + +//----------------------------------------------------------------------------- +// Purpose: returns the entire command in string form, including the 0th arg +//----------------------------------------------------------------------------- +const char* CCommand::GetCommandString(void) const +{ + return m_nArgc ? m_pArgSBuffer : ""; +} + +//----------------------------------------------------------------------------- +// Purpose: returns argument from index as string +// Input : nIndex - +//----------------------------------------------------------------------------- +const char* CCommand::Arg(int nIndex) const +{ + // FIXME: Many command handlers appear to not be particularly careful + // about checking for valid argc range. For now, we're going to + // do the extra check and return an empty string if it's out of range + if (nIndex < 0 || nIndex >= m_nArgc) + { + return ""; + } + return m_ppArgv[nIndex]; +} + +//----------------------------------------------------------------------------- +// Purpose: gets at arguments +// Input : nInput - +//----------------------------------------------------------------------------- +const char* CCommand::operator[](int nIndex) const +{ + return Arg(nIndex); +} + //----------------------------------------------------------------------------- // Purpose: construct/allocate //----------------------------------------------------------------------------- @@ -140,11 +205,11 @@ bool ConCommandBase::IsFlagSet(ConCommandBase* pCommandBase, int nFlags) return pCommandBase->HasFlags(nFlags) != 0; } +/////////////////////////////////////////////////////////////////////////////// void ConCommand_Attach() { DetourAttach((LPVOID*)&ConCommandBase_IsFlagSet, &ConCommandBase::IsFlagSet); } - void ConCommand_Detach() { DetourDetach((LPVOID*)&ConCommandBase_IsFlagSet, &ConCommandBase::IsFlagSet); diff --git a/r5dev/tier0/cmd.h b/r5dev/tier0/cmd.h index 59489823..2f8e8aec 100644 --- a/r5dev/tier0/cmd.h +++ b/r5dev/tier0/cmd.h @@ -1,5 +1,8 @@ #pragma once +//----------------------------------------------------------------------------- +// Purpose: Command tokenizer +//----------------------------------------------------------------------------- class CCommand { private: @@ -12,47 +15,13 @@ private: public: CCommand() = delete; - inline int MaxCommandLength() - { - return COMMAND_MAX_LENGTH - 1; - } - - inline std::int64_t ArgC() const - { - return m_nArgc; - } - - inline const char** ArgV() const - { - return m_nArgc ? (const char**)m_ppArgv : NULL; - } - - inline const char* ArgS() const - { - return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : ""; - } - - inline const char* GetCommandString() const - { - return m_nArgc ? m_pArgSBuffer : ""; - } - - inline const char* Arg(int nIndex) const - { - // FIXME: Many command handlers appear to not be particularly careful - // about checking for valid argc range. For now, we're going to - // do the extra check and return an empty string if it's out of range - if (nIndex < 0 || nIndex >= m_nArgc) - { - return ""; - } - return m_ppArgv[nIndex]; - } - - inline const char* operator[](int nIndex) const - { - return Arg(nIndex); - } + int MaxCommandLength(); + std::int64_t ArgC(void) const; + const char** ArgV(void) const; + const char* ArgS(void) const; + const char* GetCommandString(void) const; + const char* Arg(int nIndex) const; + const char* operator[](int nIndex) const; private: std::int64_t m_nArgc; @@ -62,6 +31,9 @@ private: const char* m_ppArgv[COMMAND_MAX_ARGC]; }; +//----------------------------------------------------------------------------- +// Purpose: The console invoked command +//----------------------------------------------------------------------------- class ConCommand { friend class CCVar; @@ -72,6 +44,9 @@ public: // TODO }; +//----------------------------------------------------------------------------- +// Purpose: The base console invoked command/cvar interface +//----------------------------------------------------------------------------- class ConCommandBase { public: diff --git a/r5dev/tier0/completion.cpp b/r5dev/tier0/completion.cpp index 757de7a7..b55919c5 100644 --- a/r5dev/tier0/completion.cpp +++ b/r5dev/tier0/completion.cpp @@ -1,6 +1,6 @@ //=============================================================================// // -// Purpose: Completion functions for ConCommand callbacks +// Purpose: Completion functions for ConCommand callbacks. // //=============================================================================// @@ -25,17 +25,32 @@ #include "mathlib/crc32.h" #ifndef DEDICATED +/* +===================== +_CGameConsole_f_CompletionFunc +===================== +*/ void _CGameConsole_f_CompletionFunc(const CCommand& cmd) { g_pIConsole->m_bActivate = !g_pIConsole->m_bActivate; } +/* +===================== +_CCompanion_f_CompletionFunc +===================== +*/ void _CCompanion_f_CompletionFunc(const CCommand& cmd) { g_pIBrowser->m_bActivate = !g_pIBrowser->m_bActivate; } #endif // !DEDICATED +/* +===================== +_Kick_f_CompletionFunc +===================== +*/ void _Kick_f_CompletionFunc(CCommand* cmd) { std::int32_t argSize = *(std::int32_t*)((std::uintptr_t)cmd + 0x4); @@ -77,6 +92,11 @@ void _Kick_f_CompletionFunc(CCommand* cmd) } } +/* +===================== +_KickID_f_CompletionFunc +===================== +*/ void _KickID_f_CompletionFunc(CCommand* cmd) { static auto HasOnlyDigits = [](const std::string& string) @@ -169,6 +189,11 @@ void _KickID_f_CompletionFunc(CCommand* cmd) } } +/* +===================== +_Ban_f_CompletionFunc +===================== +*/ void _Ban_f_CompletionFunc(CCommand* cmd) { std::int32_t argSize = *(std::int32_t*)((std::uintptr_t)cmd + 0x4); @@ -225,6 +250,11 @@ void _Ban_f_CompletionFunc(CCommand* cmd) } } +/* +===================== +_BanID_f_CompletionFunc +===================== +*/ void _BanID_f_CompletionFunc(CCommand* cmd) { static auto HasOnlyDigits = [](const std::string& string) @@ -321,6 +351,11 @@ void _BanID_f_CompletionFunc(CCommand* cmd) } } +/* +===================== +_Unban_f_CompletionFunc +===================== +*/ void _Unban_f_CompletionFunc(CCommand* cmd) { static auto HasOnlyDigits = [](const std::string& string) @@ -364,11 +399,21 @@ void _Unban_f_CompletionFunc(CCommand* cmd) } } +/* +===================== +_ReloadBanList_f_CompletionFunc +===================== +*/ void _ReloadBanList_f_CompletionFunc(CCommand* cmd) { g_pBanSystem->Load(); // Reload banlist. } +/* +===================== +_RTech_StringToGUID_f_CompletionFunc +===================== +*/ void _RTech_StringToGUID_f_CompletionFunc(CCommand* cmd) { std::int32_t argSize = *(std::int32_t*)((std::uintptr_t)cmd + 0x4); @@ -387,6 +432,11 @@ void _RTech_StringToGUID_f_CompletionFunc(CCommand* cmd) DevMsg(eDLL_T::RTECH, "] GUID: '0x%llX'\n", guid); } +/* +===================== +_RTech_AsyncLoad_f_CompletionFunc +===================== +*/ void _RTech_AsyncLoad_f_CompletionFunc(CCommand* cmd) { CCommand& args = *cmd; // Get reference. @@ -395,6 +445,14 @@ void _RTech_AsyncLoad_f_CompletionFunc(CCommand* cmd) HRtech_AsyncLoad(firstArg); } +/* +===================== +_RTech_Decompress_f_CompletionFunc + + Decompresses input RPak file and + dumps results to 'paks\Win32\*.rpak' +===================== +*/ void _RTech_Decompress_f_CompletionFunc(CCommand* cmd) { std::int32_t argSize = *(std::int32_t*)((std::uintptr_t)cmd + 0x4); @@ -519,6 +577,15 @@ void _RTech_Decompress_f_CompletionFunc(CCommand* cmd) outBlock.close(); } +/* +===================== +_NET_TraceNetChan_f_CompletionFunc + + Logs all data transmitted and received + over the UDP socket to a file on the disk. + File: ''. +===================== +*/ void _NET_TraceNetChan_f_CompletionFunc(CCommand* cmd) { static bool bTraceNetChannel = false; @@ -563,6 +630,14 @@ void _NET_TraceNetChan_f_CompletionFunc(CCommand* cmd) bTraceNetChannel = !bTraceNetChannel; } +/* +===================== +_VPK_Decompress_f_CompletionFunc + + Decompresses input VPK files and + dumps the output to '\vpk'. +===================== +*/ void _VPK_Decompress_f_CompletionFunc(CCommand* cmd) { std::int32_t argSize = *(std::int32_t*)((std::uintptr_t)cmd + 0x4); @@ -598,6 +673,13 @@ void _VPK_Decompress_f_CompletionFunc(CCommand* cmd) DevMsg(eDLL_T::FS, "--------------------------------------------------------------\n"); } +/* +===================== +_NET_SetKey_f_CompletionFunc + + Sets the input netchannel encryption key +===================== +*/ void _NET_SetKey_f_CompletionFunc(CCommand* cmd) { std::int32_t argSize = *(std::int32_t*)((std::uintptr_t)cmd + 0x4); @@ -613,13 +695,88 @@ void _NET_SetKey_f_CompletionFunc(CCommand* cmd) HNET_SetKey(firstArg); } +/* +===================== +_NET_GenerateKey_f_CompletionFunc + + Sets a random netchannel encryption key +===================== +*/ void _NET_GenerateKey_f_CompletionFunc(CCommand* cmd) { HNET_GenerateKey(); } +#ifndef DEDICATED +/* +===================== +_RCON_CmdQuery_f_CompletionFunc + Issues an RCON command to the + RCON server. +===================== +*/ void _RCON_CmdQuery_f_CompletionFunc(CCommand* cmd) { - // TODO: CRConClient.. - return; + std::int32_t argSize = *(std::int32_t*)((std::uintptr_t)cmd + 0x4); + + switch (argSize) + { + case 0: + case 1: + { + if (g_pRConClient->IsInitialized() + && !g_pRConClient->IsConnected() + && strlen(rcon_address->GetString()) > 0) + { + g_pRConClient->Connect(); + } + break; + } + case 2: + { + if (!g_pRConClient->IsInitialized()) + { + DevMsg(eDLL_T::CLIENT, "Failed to issue command to RCON server: uninitialized.\n"); + break; + } + + CCommand& args = *cmd; // Get reference. + if (!g_pRConClient->IsConnected()) + { + DevMsg(eDLL_T::CLIENT, "Failed to issue command to RCON server: unconnected.\n"); + break; + } + + std::string svCmdQuery = g_pRConClient->Serialize(args[1], "", cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND); + g_pRConClient->Send(svCmdQuery); + break; + } + case 3: + { + if (!g_pRConClient->IsInitialized()) + { + DevMsg(eDLL_T::CLIENT, "Failed to issue command to RCON server: uninitialized.\n"); + break; + } + + CCommand& args = *cmd; // Get reference. + if (!g_pRConClient->IsConnected()) + { + DevMsg(eDLL_T::CLIENT, "Failed to issue command to RCON server: unconnected.\n"); + break; + } + + if (strcmp(args[1], "PASS") == 0) + { + std::string svCmdQuery = g_pRConClient->Serialize(args[1], args[2], cl_rcon::request_t::SERVERDATA_REQUEST_AUTH); + g_pRConClient->Send(svCmdQuery); + break; + } + + std::string svCmdQuery = g_pRConClient->Serialize(args[1], args[2], cl_rcon::request_t::SERVERDATA_REQUEST_SETVALUE); + g_pRConClient->Send(svCmdQuery); + break; + } + } } +#endif // !DEDICATED diff --git a/r5dev/tier0/completion.h b/r5dev/tier0/completion.h index eb80f9d1..133e9a3b 100644 --- a/r5dev/tier0/completion.h +++ b/r5dev/tier0/completion.h @@ -33,7 +33,9 @@ void _VPK_Decompress_f_CompletionFunc(CCommand* cmd); void _NET_TraceNetChan_f_CompletionFunc(CCommand* cmd); void _NET_SetKey_f_CompletionFunc(CCommand* cmd); void _NET_GenerateKey_f_CompletionFunc(CCommand* cmd); +#ifndef DEDICATED void _RCON_CmdQuery_f_CompletionFunc(CCommand* cmd); +#endif // !DEDICATED /////////////////////////////////////////////////////////////////////////////// class HCompletion : public IDetour diff --git a/r5dev/tier1/NetAdr2.cpp b/r5dev/tier1/NetAdr2.cpp index 0ddc0ff5..035e056d 100644 --- a/r5dev/tier1/NetAdr2.cpp +++ b/r5dev/tier1/NetAdr2.cpp @@ -11,34 +11,12 @@ #endif // !NETCONSOLE //----------------------------------------------------------------------------- -// Purpose: constructor (use this when string contains <[IP]:PORT> or 'loopback'/'localhost'). +// Purpose: constructor (use this when string contains <[IP]:PORT>). // Input : svInAdr - //----------------------------------------------------------------------------- CNetAdr2::CNetAdr2(std::string svInAdr) { - SetType(netadrtype_t::NA_IP); - if (strcmp(svInAdr.c_str(), "loopback") == 0 || strcmp(svInAdr.c_str(), "::1") == 0) - { - SetType(netadrtype_t::NA_LOOPBACK); - svInAdr = "[127.0.0.1" + GetPort(svInAdr); - } - else if (strcmp(svInAdr.c_str(), "localhost")) - { - svInAdr = "[127.0.0.1" + GetPort(svInAdr); - } - - // [IP]:PORT - m_svip = GetBase(svInAdr); - SetVersion(); - - if (GetVersion() == netadrversion_t::NA_V4) - { - reinterpret_cast(&m_sadr)->sin_port = htons(stoi(GetPort())); - } - else if (GetVersion() == netadrversion_t::NA_V6) - { - reinterpret_cast(&m_sadr)->sin6_port = htons(stoi(GetPort())); - } + SetIPAndPort(svInAdr); } //----------------------------------------------------------------------------- @@ -102,15 +80,70 @@ void CNetAdr2::SetPort(const std::string& svInPort) m_svip += ":" + svInPort; } +//----------------------------------------------------------------------------- +// Purpose: sets the IP address and port. +// Input : *svInAdr - +//----------------------------------------------------------------------------- +void CNetAdr2::SetIPAndPort(std::string svInAdr) +{ + SetType(netadrtype_t::NA_IP); + if (strstr(svInAdr.c_str(), "loopback") || strstr(svInAdr.c_str(), "::1")) + { + SetType(netadrtype_t::NA_LOOPBACK); + svInAdr = "[127.0.0.1]:" + GetPort(svInAdr); + } + else if (strstr(svInAdr.c_str(), "localhost")) + { + svInAdr = "[127.0.0.1]:" + GetPort(svInAdr); + } + // [IP]:PORT + m_svip = svInAdr; + SetVersion(); + + if (GetVersion() == netadrversion_t::NA_V4) + { + reinterpret_cast(&m_sadr)->sin_port = htons(stoi(GetPort())); + } + else if (GetVersion() == netadrversion_t::NA_V6) + { + reinterpret_cast(&m_sadr)->sin6_port = htons(stoi(GetPort())); + } +} + //----------------------------------------------------------------------------- // Purpose: sets the IP address and port. // Input : *svInAdr - // *svInPort - //----------------------------------------------------------------------------- -void CNetAdr2::SetIPAndPort(const std::string& svInAdr, const std::string& svInPort) +void CNetAdr2::SetIPAndPort(std::string svInAdr, std::string svInPort) { + SetType(netadrtype_t::NA_IP); + + if (strcmp(svInAdr.c_str(), "loopback") == 0 || strcmp(svInAdr.c_str(), "::1") == 0) + { + SetType(netadrtype_t::NA_LOOPBACK); + } + else if (strcmp(svInAdr.c_str(), "localhost") == 0) + { + svInAdr = "127.0.0.1"; + } + + if (strstr(svInAdr.c_str(), "[")) + { + svInAdr = GetBase(svInAdr); + } + m_svip = "[" + svInAdr + "]:" + svInPort; SetVersion(); + + if (m_version == netadrversion_t::NA_V4) + { + reinterpret_cast(&m_sadr)->sin_port = htons(stoi(GetPort())); + } + else if (m_version == netadrversion_t::NA_V6) + { + reinterpret_cast(&m_sadr)->sin6_port = htons(stoi(GetPort())); + } } //----------------------------------------------------------------------------- diff --git a/r5dev/tier1/NetAdr2.h b/r5dev/tier1/NetAdr2.h index 02c576a2..54353a68 100644 --- a/r5dev/tier1/NetAdr2.h +++ b/r5dev/tier1/NetAdr2.h @@ -50,7 +50,8 @@ public: void SetIP(const std::string& svInAdr); void SetPort(const std::string& svInPort); - void SetIPAndPort(const std::string& svInAdr, const std::string& svInPort); + void SetIPAndPort(std::string svInAdr); + void SetIPAndPort(std::string svInAdr, std::string svInPort); void SetType(const netadrtype_t& type); void SetVersion(void); void SetFromSocket(const int& hSocket);