diff --git a/Jupiter b/Jupiter index d8dd8de..a5f0625 160000 --- a/Jupiter +++ b/Jupiter @@ -1 +1 @@ -Subproject commit d8dd8dea5465e209083e423cbec8b7df1ad5cf59 +Subproject commit a5f06257535dcabecdc074af3f3591179e1bbfdc diff --git a/Jupiter Bot.sln b/Jupiter Bot.sln index 0eea142..bd777fa 100644 --- a/Jupiter Bot.sln +++ b/Jupiter Bot.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio 14 +VisualStudioVersion = 14.0.22823.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Bot", "Bot\Bot.vcxproj", "{C188871B-5F32-4946-B301-24CA2EBB275D}" EndProject @@ -151,6 +151,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RenX.HybridUUID", "RenX.Hyb {9103DF3D-8B4A-48E5-A6B3-CBE2554630E2} = {9103DF3D-8B4A-48E5-A6B3-CBE2554630E2} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RenX.Listen", "RenX.Listen\RenX.Listen.vcxproj", "{DA05D8B5-5E24-410E-A201-CC5905E327D3}" + ProjectSection(ProjectDependencies) = postProject + {C188871B-5F32-4946-B301-24CA2EBB275D} = {C188871B-5F32-4946-B301-24CA2EBB275D} + {9103DF3D-8B4A-48E5-A6B3-CBE2554630E2} = {9103DF3D-8B4A-48E5-A6B3-CBE2554630E2} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -261,6 +267,10 @@ Global {FF61361F-CB09-4C72-80E2-9CA2DA63910E}.Debug|Win32.Build.0 = Debug|Win32 {FF61361F-CB09-4C72-80E2-9CA2DA63910E}.Release|Win32.ActiveCfg = Release|Win32 {FF61361F-CB09-4C72-80E2-9CA2DA63910E}.Release|Win32.Build.0 = Release|Win32 + {DA05D8B5-5E24-410E-A201-CC5905E327D3}.Debug|Win32.ActiveCfg = Debug|Win32 + {DA05D8B5-5E24-410E-A201-CC5905E327D3}.Debug|Win32.Build.0 = Debug|Win32 + {DA05D8B5-5E24-410E-A201-CC5905E327D3}.Release|Win32.ActiveCfg = Release|Win32 + {DA05D8B5-5E24-410E-A201-CC5905E327D3}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Release/Bot.lib b/Release/Bot.lib index 5cf68bd..c955f56 100644 Binary files a/Release/Bot.lib and b/Release/Bot.lib differ diff --git a/Release/Plugins/RenX.Core.lib b/Release/Plugins/RenX.Core.lib index 427603b..1e31821 100644 Binary files a/Release/Plugins/RenX.Core.lib and b/Release/Plugins/RenX.Core.lib differ diff --git a/RenX.Core/RenX_Server.cpp b/RenX.Core/RenX_Server.cpp index 55b3e50..37a577b 100644 --- a/RenX.Core/RenX_Server.cpp +++ b/RenX.Core/RenX_Server.cpp @@ -31,12 +31,17 @@ int RenX::Server::think() { if (RenX::Server::connected == false) { - if (time(0) >= RenX::Server::lastAttempt + RenX::Server::delay) + if (RenX::Server::maxAttempts < 0 || RenX::Server::attempts < RenX::Server::maxAttempts) { - if (RenX::Server::connect()) - RenX::Server::sendLogChan(IRCCOLOR "03[RenX]" IRCCOLOR " Socket successfully reconnected to Renegade-X server."); - else RenX::Server::sendLogChan(IRCCOLOR "04[Error]" IRCCOLOR " Failed to reconnect to Renegade-X server."); + if (time(0) >= RenX::Server::lastAttempt + RenX::Server::delay) + { + if (RenX::Server::connect()) + RenX::Server::sendLogChan(IRCCOLOR "03[RenX]" IRCCOLOR " Socket successfully reconnected to Renegade-X server."); + else RenX::Server::sendLogChan(IRCCOLOR "04[Error]" IRCCOLOR " Failed to reconnect to Renegade-X server."); + } } + else + return 1; } else { @@ -61,11 +66,19 @@ int RenX::Server::think() else if (Jupiter::Socket::getLastError() != 10035) // This is a serious error { RenX::Server::wipeData(); - RenX::Server::sendLogChan(IRCCOLOR "07[Warning]" IRCCOLOR " Connection to Renegade-X server lost. Reconnection attempt in progress."); - if (RenX::Server::reconnect()) - RenX::Server::sendLogChan(IRCCOLOR "06[Progress]" IRCCOLOR " Connection to Renegade-X server reestablished. Initializing Renegade-X RCON protocol..."); + if (RenX::Server::maxAttempts != 0) + { + RenX::Server::sendLogChan(IRCCOLOR "07[Warning]" IRCCOLOR " Connection to Renegade-X server lost. Reconnection attempt in progress."); + if (RenX::Server::reconnect()) + RenX::Server::sendLogChan(IRCCOLOR "06[Progress]" IRCCOLOR " Connection to Renegade-X server reestablished. Initializing Renegade-X RCON protocol..."); + else + RenX::Server::sendLogChan(IRCCOLOR "04[Error]" IRCCOLOR " Connection to Renegade-X server lost. Reconnection attempt failed."); + } else - RenX::Server::sendLogChan(IRCCOLOR "04[Error]" IRCCOLOR " Connection to Renegade-X server lost. Reconnection attempt failed."); + { + RenX::Server::sendLogChan(IRCCOLOR "04[Error]" IRCCOLOR " Connection to Renegade-X server lost. No attempt will be made to reconnect."); + return 1; + } return 0; } if (RenX::Server::rconVersion >= 3 && std::chrono::steady_clock::now() > RenX::Server::lastClientListUpdate + RenX::Server::clientUpdateRate) @@ -503,6 +516,16 @@ unsigned short RenX::Server::getPort() const return RenX::Server::port; } +const Jupiter::ReadableString &RenX::Server::getSocketHostname() const +{ + return RenX::Server::sock.getHostname(); +} + +unsigned short RenX::Server::getSocketPort() const +{ + return RenX::Server::sock.getPort(); +} + time_t RenX::Server::getLastAttempt() const { return RenX::Server::lastAttempt; @@ -2200,6 +2223,7 @@ void RenX::Server::processLine(const Jupiter::ReadableString &line) if (this->rconVersion >= 3) { + RenX::Server::sock.send(STRING_LITERAL_AS_REFERENCE("s\n")); RenX::Server::send(STRING_LITERAL_AS_REFERENCE("map")); RenX::Server::fetchClientList(); @@ -2250,16 +2274,17 @@ void RenX::Server::disconnect() bool RenX::Server::connect() { RenX::Server::lastAttempt = time(0); - if (RenX::Server::sock.connectToHost(RenX::Server::hostname.c_str(), RenX::Server::port, RenX::Server::clientHostname.isEmpty() ? nullptr : RenX::Server::clientHostname.c_str())) + if (RenX::Server::sock.connect(RenX::Server::hostname.c_str(), RenX::Server::port, RenX::Server::clientHostname.isEmpty() ? nullptr : RenX::Server::clientHostname.c_str())) { RenX::Server::sock.setBlocking(false); RenX::Server::sock.send(Jupiter::StringS::Format("a%.*s\n", RenX::Server::pass.size(), RenX::Server::pass.ptr())); - RenX::Server::sock.send(STRING_LITERAL_AS_REFERENCE("s\n")); RenX::Server::connected = true; RenX::Server::silenceParts = false; + RenX::Server::attempts = 0; return true; } RenX::Server::connected = false; + ++RenX::Server::attempts; return false; } @@ -2292,6 +2317,14 @@ const Jupiter::ReadableString &RenX::Server::getRCONUsername() const return RenX::Server::rconUser; } +RenX::Server::Server(Jupiter::Socket &&socket, const Jupiter::ReadableString &configurationSection) : Server(configurationSection) +{ + RenX::Server::sock = std::move(socket); + RenX::Server::sock.send(Jupiter::StringS::Format("a%.*s\n", RenX::Server::pass.size(), RenX::Server::pass.ptr())); + RenX::Server::connected = true; + RenX::Server::silenceParts = false; +} + RenX::Server::Server(const Jupiter::ReadableString &configurationSection) { RenX::Server::configSection = configurationSection; @@ -2317,6 +2350,7 @@ void RenX::Server::init() RenX::Server::rules = Jupiter::IRC::Client::Config->get(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("Rules"), STRING_LITERAL_AS_REFERENCE("Anarchy!")); RenX::Server::delay = Jupiter::IRC::Client::Config->getInt(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("ReconnectDelay"), 10); + RenX::Server::maxAttempts = Jupiter::IRC::Client::Config->getInt(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("MaxReconnectAttempts"), -1); RenX::Server::rconBan = Jupiter::IRC::Client::Config->getBool(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("RCONBan"), false); RenX::Server::localSteamBan = Jupiter::IRC::Client::Config->getBool(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("LocalSteamBan"), true); RenX::Server::localIPBan = Jupiter::IRC::Client::Config->getBool(RenX::Server::configSection, STRING_LITERAL_AS_REFERENCE("LocalIPBan"), true); diff --git a/RenX.Core/RenX_Server.h b/RenX.Core/RenX_Server.h index 7e7e8ca..1635d11 100644 --- a/RenX.Core/RenX_Server.h +++ b/RenX.Core/RenX_Server.h @@ -519,6 +519,20 @@ namespace RenX */ unsigned short getPort() const; + /** + * @brief Fetches the hostname from the server socket. + * + * @return String containing the hostname of the server. + */ + const Jupiter::ReadableString &getSocketHostname() const; + + /** + * @brief Fetches the port from the server socket. + * + * @return Port of the server. + */ + unsigned short getSocketPort() const; + /** * @brief Fetches the time of the last connection attempt. * Note: This includes both successful and failed connection attempts. @@ -734,6 +748,14 @@ namespace RenX */ const Jupiter::ReadableString &getRCONUsername() const; + /** + * @brief Creates a server object using the provided socket, and loads settings from the specified configuration section. + * + * @param socket Initialized Socket to use for the connection + * @param configurationSection Configuration section to load from. + */ + Server(Jupiter::Socket &&socket, const Jupiter::ReadableString &configurationSection); + /** * @brief Creates the Server object, and loads settings from the specified configuration section. * @@ -762,6 +784,7 @@ namespace RenX bool firstAction = false; unsigned int rconVersion = 0; time_t lastAttempt = 0; + int attempts = 0; std::chrono::steady_clock::time_point lastClientListUpdate = std::chrono::steady_clock::now(); Jupiter::String lastLine; Jupiter::StringS commandListFormat; @@ -773,6 +796,7 @@ namespace RenX int logChanType; int adminLogChanType; time_t delay; + int maxAttempts; std::chrono::milliseconds clientUpdateRate; int steamFormat; /** 16 = hex, 10 = base 10, 8 = octal, -2 = SteamID 2, -3 = SteamID 3 */ bool rconBan; diff --git a/RenX.Listen/RenX.Listen.vcxproj b/RenX.Listen/RenX.Listen.vcxproj new file mode 100644 index 0000000..348d222 --- /dev/null +++ b/RenX.Listen/RenX.Listen.vcxproj @@ -0,0 +1,85 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {DA05D8B5-5E24-410E-A201-CC5905E327D3} + PluginExample + + + + Application + true + v140 + MultiByte + + + DynamicLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + $(SolutionDir)$(Configuration)\Plugins\ + AllRules.ruleset + + + + Level3 + Disabled + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + ../Bot;../Jupiter;../RenX.Core + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RenX.Listen/RenX.Listen.vcxproj.filters b/RenX.Listen/RenX.Listen.vcxproj.filters new file mode 100644 index 0000000..2c7667e --- /dev/null +++ b/RenX.Listen/RenX.Listen.vcxproj.filters @@ -0,0 +1,38 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Resource Files + + + Resource Files + + + Resource Files + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/RenX.Listen/RenX_Listen.cpp b/RenX.Listen/RenX_Listen.cpp new file mode 100644 index 0000000..7568955 --- /dev/null +++ b/RenX.Listen/RenX_Listen.cpp @@ -0,0 +1,78 @@ +/** + * Copyright (C) 2015 Justin James. + * + * This license must be preserved. + * Any applications, libraries, or code which make any use of any + * component of this program must not be commercial, unless explicit + * permission is granted from the original author. The use of this + * program for non-profit purposes is permitted. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * In the event that this license restricts you from making desired use of this program, contact the original author. + * Written by Justin James + */ + +#include "Jupiter/IRC_Client.h" +#include "Jupiter/INIFile.h" +#include "Jupiter/CString.h" +#include "RenX_Listen.h" +#include "RenX_Core.h" +#include "RenX_Server.h" + +RenX_ListenPlugin::~RenX_ListenPlugin() +{ + RenX_ListenPlugin::socket.closeSocket(); +} + +bool RenX_ListenPlugin::init() +{ + uint16_t port = Jupiter::IRC::Client::Config->getInt(this->getName(), STRING_LITERAL_AS_REFERENCE("Port"), 13372); + const Jupiter::ReadableString &address = Jupiter::IRC::Client::Config->get(this->getName(), STRING_LITERAL_AS_REFERENCE("Address"), STRING_LITERAL_AS_REFERENCE("0.0.0.0")); + RenX_ListenPlugin::serverSection = Jupiter::IRC::Client::Config->get(this->getName(), STRING_LITERAL_AS_REFERENCE("ServerSection"), this->getName()); + return RenX_ListenPlugin::socket.bind(Jupiter::CStringS(address).c_str(), port, true) && RenX_ListenPlugin::socket.setBlocking(false); +} + +int RenX_ListenPlugin::think() +{ + Jupiter::Socket *sock = socket.accept(); + if (sock != nullptr) + { + sock->setBlocking(false); + RenX::Server *server = new RenX::Server(std::move(*sock), RenX_ListenPlugin::serverSection); + printf("Incoming server connected from " IRCCOLOR "12%.*s:%u", server->getSocketHostname().size(), server->getSocketHostname().ptr(), server->getSocketPort()); + server->sendLogChan("Incoming server connected from " IRCCOLOR "12%.*s:%u", server->getSocketHostname().size(), server->getSocketHostname().ptr(), server->getSocketPort()); + RenX::getCore()->addServer(server); + delete sock; + } + return 0; +} + +int RenX_ListenPlugin::OnRehash() +{ + uint16_t port = Jupiter::IRC::Client::Config->getInt(this->getName(), STRING_LITERAL_AS_REFERENCE("Port"), 13372); + const Jupiter::ReadableString &address = Jupiter::IRC::Client::Config->get(this->getName(), STRING_LITERAL_AS_REFERENCE("Address"), STRING_LITERAL_AS_REFERENCE("0.0.0.0")); + RenX_ListenPlugin::serverSection = Jupiter::IRC::Client::Config->get(this->getName(), STRING_LITERAL_AS_REFERENCE("ServerSection"), this->getName()); + if (port != RenX_ListenPlugin::socket.getPort() || address.equals(RenX_ListenPlugin::socket.getHostname()) == false) + { + puts("Notice: The Renegade-X listening socket has been changed!"); + RenX_ListenPlugin::socket.closeSocket(); + return RenX_ListenPlugin::socket.bind(Jupiter::CStringS(address).c_str(), port, true) == false || RenX_ListenPlugin::socket.setBlocking(false) == false; + } + return 0; +} + +// Plugin instantiation and entry point. +RenX_ListenPlugin pluginInstance; + +extern "C" __declspec(dllexport) bool load() +{ + return pluginInstance.init(); +} + +extern "C" __declspec(dllexport) Jupiter::Plugin *getPlugin() +{ + return &pluginInstance; +} diff --git a/RenX.Listen/RenX_Listen.h b/RenX.Listen/RenX_Listen.h new file mode 100644 index 0000000..5cccae2 --- /dev/null +++ b/RenX.Listen/RenX_Listen.h @@ -0,0 +1,45 @@ +/** + * Copyright (C) 2015 Justin James. + * + * This license must be preserved. + * Any applications, libraries, or code which make any use of any + * component of this program must not be commercial, unless explicit + * permission is granted from the original author. The use of this + * program for non-profit purposes is permitted. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * In the event that this license restricts you from making desired use of this program, contact the original author. + * Written by Justin James + */ + +#if !defined _EXAMPLE_H_HEADER +#define _EXAMPLE_H_HEADER + +#include "Jupiter/Plugin.h" +#include "Jupiter/Reference_String.h" +#include "Jupiter/TCPSocket.h" +#include "RenX_Plugin.h" + +class RenX_ListenPlugin : public RenX::Plugin +{ +public: // RenX::Plugin + +public: // Jupiter::Plugin + const Jupiter::ReadableString &getName() override { return name; } + int think() override; + int OnRehash(); + +public: // RenX_ListenPlugin + bool init(); + ~RenX_ListenPlugin(); + +private: + STRING_LITERAL_AS_NAMED_REFERENCE(name, "RenX.Listen"); + Jupiter::TCPSocket socket; + Jupiter::StringS serverSection; +}; + +#endif // _EXAMPLE_H_HEADER \ No newline at end of file