diff options
Diffstat (limited to 'NetConsole')
-rw-r--r-- | NetConsole/NetConsole.vcxproj | 122 | ||||
-rw-r--r-- | NetConsole/NetConsole.vcxproj.filters | 63 | ||||
-rw-r--r-- | NetConsole/cl_rcon.proto | 21 | ||||
-rw-r--r-- | NetConsole/netconsole.cpp | 420 | ||||
-rw-r--r-- | NetConsole/netconsole.h | 46 | ||||
-rw-r--r-- | NetConsole/pch.cpp | 5 | ||||
-rw-r--r-- | NetConsole/pch.h | 33 | ||||
-rw-r--r-- | NetConsole/sv_rcon.proto | 21 |
8 files changed, 731 insertions, 0 deletions
diff --git a/NetConsole/NetConsole.vcxproj b/NetConsole/NetConsole.vcxproj new file mode 100644 index 00000000..264973b4 --- /dev/null +++ b/NetConsole/NetConsole.vcxproj @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>16.0</VCProjectVersion> + <Keyword>Win32Proj</Keyword> + <ProjectGuid>{abb29780-5fea-4108-8793-fa50fb9cdafa}</ProjectGuid> + <RootNamespace>NetConsole</RootNamespace> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v143</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v143</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + <TargetName>netcon</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <TargetName>netcon</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(SolutionDir)NorthstarDedicatedTest\;$(SolutionDir)NorthstarDedicatedTest\Include\;$(SolutionDir)NorthstarDedicatedTest\Include\protobuf\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <LanguageStandard>stdcpp17</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>Ws2_32.lib;$(SolutionDir)$(Platform)\$(Configuration)\libprotobuf_x64.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(SolutionDir)NorthstarDedicatedTest\;$(SolutionDir)NorthstarDedicatedTest\Include\;$(SolutionDir)NorthstarDedicatedTest\Include\protobuf\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PrecompiledHeader>Use</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <LanguageStandard>stdcpp17</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>Ws2_32.lib;$(SolutionDir)$(Platform)\$(Configuration)\libprotobuf_x64.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="..\NorthstarDedicatedTest\cl_rcon.pb.h" /> + <ClInclude Include="..\NorthstarDedicatedTest\net.h" /> + <ClInclude Include="..\NorthstarDedicatedTest\NetAdr2.h" /> + <ClInclude Include="..\NorthstarDedicatedTest\socketcreator.h" /> + <ClInclude Include="..\NorthstarDedicatedTest\sv_rcon.pb.h" /> + <ClInclude Include="netconsole.h" /> + <ClInclude Include="pch.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\NorthstarDedicatedTest\cl_rcon.pb.cc"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> + </ClCompile> + <ClCompile Include="..\NorthstarDedicatedTest\net.cpp" /> + <ClCompile Include="..\NorthstarDedicatedTest\NetAdr2.cpp" /> + <ClCompile Include="..\NorthstarDedicatedTest\socketcreator.cpp" /> + <ClCompile Include="..\NorthstarDedicatedTest\sv_rcon.pb.cc"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> + </ClCompile> + <ClCompile Include="netconsole.cpp" /> + <ClCompile Include="pch.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> + </ClCompile> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/NetConsole/NetConsole.vcxproj.filters b/NetConsole/NetConsole.vcxproj.filters new file mode 100644 index 00000000..617ef8c7 --- /dev/null +++ b/NetConsole/NetConsole.vcxproj.filters @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="netconsole.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="pch.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\NorthstarDedicatedTest\cl_rcon.pb.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\NorthstarDedicatedTest\sv_rcon.pb.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\NorthstarDedicatedTest\socketcreator.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\NorthstarDedicatedTest\NetAdr2.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\NorthstarDedicatedTest\net.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="netconsole.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="pch.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\NorthstarDedicatedTest\cl_rcon.pb.cc"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\NorthstarDedicatedTest\sv_rcon.pb.cc"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\NorthstarDedicatedTest\socketcreator.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\NorthstarDedicatedTest\NetAdr2.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\NorthstarDedicatedTest\net.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/NetConsole/cl_rcon.proto b/NetConsole/cl_rcon.proto new file mode 100644 index 00000000..c8ba8dbf --- /dev/null +++ b/NetConsole/cl_rcon.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; +package cl_rcon; +option optimize_for = LITE_RUNTIME; + +enum request_t +{ + SERVERDATA_REQUEST_VALUE = 0; + SERVERDATA_REQUEST_SETVALUE = 1; + SERVERDATA_REQUEST_EXECCOMMAND = 2; + SERVERDATA_REQUEST_AUTH = 3; + SERVERDATA_REQUEST_SEND_CONSOLE_LOG = 4; + SERVERDATA_REQUEST_SEND_REMOTEBUG = 5; +} + +message request +{ + optional int32 requestID = 1; + optional request_t requestType = 2; + optional string requestBuf = 3; + optional string requestVal = 4; +} diff --git a/NetConsole/netconsole.cpp b/NetConsole/netconsole.cpp new file mode 100644 index 00000000..4df47647 --- /dev/null +++ b/NetConsole/netconsole.cpp @@ -0,0 +1,420 @@ +//=====================================================================================// +// +// Purpose: Lightweight netconsole client. +// +//=====================================================================================// + +#include "pch.h" +#include "NetAdr2.h" +#include "socketcreator.h" +#include "sv_rcon.pb.h" +#include "cl_rcon.pb.h" +#include "net.h" +#include "netconsole.h" + +//----------------------------------------------------------------------------- +// Purpose: destructor +//----------------------------------------------------------------------------- +CNetCon::~CNetCon() +{ + delete m_pNetAdr2; + delete m_pSocket; +} + +//----------------------------------------------------------------------------- +// Purpose: WSA and NETCON systems init +// Output : true on success, false otherwise +//----------------------------------------------------------------------------- +bool CNetCon::Init(void) +{ + WSAData wsaData{}; + int nError = ::WSAStartup(MAKEWORD(2, 2), &wsaData); + + if (nError != 0) + { + spdlog::error("Failed to start Winsock via WSAStartup: ({})", NET_ErrorString(WSAGetLastError())); + return false; + } + + this->TermSetup(); + + std::thread tFrame(&CNetCon::RunFrame, this); + tFrame.detach(); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: WSA and NETCON systems shutdown +// Output : true on success, false otherwise +//----------------------------------------------------------------------------- +bool CNetCon::Shutdown(void) +{ + m_pSocket->CloseAllAcceptedSockets(); + m_abConnEstablished = false; + + int nError = ::WSACleanup(); + if (nError != 0) + { + spdlog::error("Failed to stop winsock via WSACleanup: ({})", NET_ErrorString(WSAGetLastError())); + return false; + } + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: terminal setup +//----------------------------------------------------------------------------- +void CNetCon::TermSetup(void) +{ + DWORD dwMode = NULL; + HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE); + HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); + + CONSOLE_SCREEN_BUFFER_INFOEX sbInfoEx{}; + COLORREF storedBG = sbInfoEx.ColorTable[0]; + sbInfoEx.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); + + GetConsoleScreenBufferInfoEx(hOutput, &sbInfoEx); + sbInfoEx.ColorTable[0] = 0x0000; + SetConsoleScreenBufferInfoEx(hOutput, &sbInfoEx); +} + +//----------------------------------------------------------------------------- +// Purpose: gets input IP and port for initialization +//----------------------------------------------------------------------------- +void CNetCon::UserInput(void) +{ + std::string svInput; + + if (std::getline(std::cin, svInput)) + { + if (strcmp(svInput.c_str(), "nquit") == 0) + { + m_bQuitApplication = true; + return; + } + if (m_abConnEstablished) + { + 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 svSecondArg = svInput.substr(nPos + 1); + std::string svFirstArg = svInput; + svFirstArg = svFirstArg.erase(svFirstArg.find(" ")); + + if (strcmp(svFirstArg.c_str(), "PASS") == 0) // Auth with RCON server. + { + std::string svSerialized = this->Serialize(svSecondArg, "", cl_rcon::request_t::SERVERDATA_REQUEST_AUTH); + this->Send(svSerialized); + } + else if (strcmp(svFirstArg.c_str(), "SET") == 0) // Set value query. + { + std::string svSerialized = this->Serialize(svFirstArg, svSecondArg, cl_rcon::request_t::SERVERDATA_REQUEST_SETVALUE); + this->Send(svSerialized); + } + else // Execute command query. + { + std::string svSerialized = this->Serialize(svInput.c_str(), "", cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND); + this->Send(svSerialized); + } + } + else // Single arg command query. + { + std::string svSerialized = this->Serialize(svInput.c_str(), "", 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() && nPos != svInput.size()) + { + std::string svInPort = svInput.substr(nPos + 1); + std::string svInAdr = svInput.erase(svInput.find(" ")); + + if (!this->Connect(svInAdr, svInPort)) + { + m_abPromptConnect = true; + return; + } + } + else // Initialize as [127.0.0.1]:37015. + { + if (!this->Connect("", "")) + { + m_abPromptConnect = true; + return; + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: client's main processing loop +//----------------------------------------------------------------------------- +void CNetCon::RunFrame(void) +{ + for (;;) + { + if (m_abConnEstablished) + { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + this->Recv(); + } + else if (m_abPromptConnect) + { + std::cout << "Enter <IP> <PORT>: "; + m_abPromptConnect = false; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: checks if application should be terminated +// Output : true for termination, false otherwise +//----------------------------------------------------------------------------- +bool CNetCon::ShouldQuit(void) const { return this->m_bQuitApplication; } + +//----------------------------------------------------------------------------- +// Purpose: connect to specified address and port +// Input : *svInAdr - +// *svInPort - +// Output : true if connection succeeds, false otherwise +//----------------------------------------------------------------------------- +bool CNetCon::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) + { + spdlog::warn("Failed to connect. Error: (SOCKET_ERROR). Verify IP and PORT."); + return false; + } + spdlog::info("Connected to: {}", m_pNetAdr2->GetIPAndPort()); + + m_abConnEstablished = true; + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: disconnect from current session +//----------------------------------------------------------------------------- +void CNetCon::Disconnect(void) +{ + ::closesocket(m_pSocket->GetAcceptedSocketHandle(0)); + m_abPromptConnect = true; + m_abConnEstablished = false; +} + +//----------------------------------------------------------------------------- +// 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) + { + spdlog::warn("Failed to send message: (SOCKET_ERROR)"); + } +} + +//----------------------------------------------------------------------------- +// Purpose: receive message +//----------------------------------------------------------------------------- +void CNetCon::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_abConnEstablished) // EOF or error. + { + this->Disconnect(); + spdlog::info("Server closed connection"); + 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_abConnEstablished) // Socket was closed. + { + this->Disconnect(); + spdlog::info("Server closed connection"); + 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 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 +{ + 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(); + svOut.erase(std::remove(svOut.begin(), svOut.end(), '\n'), svOut.end()); + spdlog::info(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 : *svBuf - +// Output : de-serialized object +//----------------------------------------------------------------------------- +sv_rcon::response CNetCon::Deserialize(const std::string& svBuf) const +{ + sv_rcon::response sv_response; + sv_response.ParseFromArray(svBuf.c_str(), static_cast<int>(svBuf.size())); + + return sv_response; +} + +//----------------------------------------------------------------------------- +// Purpose: entrypoint +// Input : argc - +// *argv - +//----------------------------------------------------------------------------- +int main(int argc, char* argv[]) +{ + CNetCon* pNetCon = new CNetCon(); + std::cout << "Northstar TCP net console [Version " << NETCON_VERSION << "]" << std::endl; + spdlog::default_logger()->set_pattern("[%H:%M:%S] [%l] %v"); + + if (!pNetCon->Init()) + { + return EXIT_FAILURE; + } + + if (argc >= 3) // Get IP and Port from command line. + { + if (!pNetCon->Connect(argv[1], argv[2])) + { + return EXIT_FAILURE; + } + } + + while (!pNetCon->ShouldQuit()) + { + pNetCon->UserInput(); + } + + if (!pNetCon->Shutdown()) + { + return EXIT_FAILURE; + } + + return ERROR_SUCCESS; +}
\ No newline at end of file diff --git a/NetConsole/netconsole.h b/NetConsole/netconsole.h new file mode 100644 index 00000000..dbd6eb2c --- /dev/null +++ b/NetConsole/netconsole.h @@ -0,0 +1,46 @@ +//===========================================================================// +// +// Purpose: +// +//===========================================================================// +#pragma once +#include "cl_rcon.pb.h" +#include "sv_rcon.pb.h" + +constexpr const char* NETCON_VERSION = "2.0.0.1"; + +class CNetCon +{ + public: + ~CNetCon(); + + bool Init(void); + bool Shutdown(void); + + void TermSetup(void); + void UserInput(void); + + void RunFrame(void); + bool ShouldQuit(void) const; + + 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; + + private: + CNetAdr2* m_pNetAdr2 = new CNetAdr2("localhost", "37015"); + CSocketCreator* m_pSocket = new CSocketCreator(); + + bool m_bInitialized = false; + bool m_bQuitApplication = false; + std::atomic<bool> m_abPromptConnect{true}; + std::atomic<bool> m_abConnEstablished{false}; +};
\ No newline at end of file diff --git a/NetConsole/pch.cpp b/NetConsole/pch.cpp new file mode 100644 index 00000000..64b7eef6 --- /dev/null +++ b/NetConsole/pch.cpp @@ -0,0 +1,5 @@ +// pch.cpp: source file corresponding to the pre-compiled header + +#include "pch.h" + +// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. diff --git a/NetConsole/pch.h b/NetConsole/pch.h new file mode 100644 index 00000000..5e917f10 --- /dev/null +++ b/NetConsole/pch.h @@ -0,0 +1,33 @@ +#ifndef PCH_H +#define PCH_H + +#define WIN32_LEAN_AND_MEAN +#define _CRT_SECURE_NO_WARNINGS + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +// add headers that you want to pre-compile here + +#include <Windows.h> +#include <WinSock2.h> +#include <Ws2tcpip.h> +#include <Psapi.h> +#include <comdef.h> +#include <filesystem> +#include <iostream> +#include <fstream> +#include <sstream> +#include <cstring> +#include <regex> +#include <thread> +#include <set> +#include <chrono> + +#include "spdlog/spdlog.h" +#endif diff --git a/NetConsole/sv_rcon.proto b/NetConsole/sv_rcon.proto new file mode 100644 index 00000000..ce2e9e35 --- /dev/null +++ b/NetConsole/sv_rcon.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; +package sv_rcon; +option optimize_for = LITE_RUNTIME; + +enum response_t +{ + SERVERDATA_RESPONSE_VALUE = 0; + SERVERDATA_RESPONSE_UPDATE = 1; + SERVERDATA_RESPONSE_AUTH = 2; + SERVERDATA_RESPONSE_CONSOLE_LOG = 3; + SERVERDATA_RESPONSE_STRING = 4; + SERVERDATA_RESPONSE_REMOTEBUG = 5; +} + +message response +{ + optional int32 responseID = 1; + optional response_t responseType = 2; + optional string responseBuf = 3; + optional string responseVal = 4; +} |