summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xCIbuild.sh5
-rw-r--r--src/OSSupport/NetworkSingleton.cpp53
-rw-r--r--src/OSSupport/NetworkSingleton.h11
-rw-r--r--src/Root.cpp291
-rw-r--r--src/Root.h10
-rw-r--r--src/main.cpp65
-rw-r--r--tests/Network/Google.cpp1
7 files changed, 239 insertions, 197 deletions
diff --git a/CIbuild.sh b/CIbuild.sh
index 100a64b0c..f1a583c79 100755
--- a/CIbuild.sh
+++ b/CIbuild.sh
@@ -22,6 +22,7 @@ echo "Building..."
make -j 2;
make -j 2 test ARGS="-V";
cd MCServer/;
-if [ "$TRAVIS_MCSERVER_BUILD_TYPE" != "COVERAGE" ]
- then echo stop | $MCSERVER_PATH;
+if [ "$TRAVIS_MCSERVER_BUILD_TYPE" != "COVERAGE" ]; then
+ echo restart | $MCSERVER_PATH;
+ echo stop | $MCSERVER_PATH;
fi
diff --git a/src/OSSupport/NetworkSingleton.cpp b/src/OSSupport/NetworkSingleton.cpp
index 417fab01e..c16f92c5a 100644
--- a/src/OSSupport/NetworkSingleton.cpp
+++ b/src/OSSupport/NetworkSingleton.cpp
@@ -18,8 +18,36 @@
-cNetworkSingleton::cNetworkSingleton(void):
- m_HasTerminated(false)
+cNetworkSingleton::cNetworkSingleton() :
+ m_HasTerminated(true)
+{
+}
+
+
+
+
+
+cNetworkSingleton::~cNetworkSingleton()
+{
+ // Check that Terminate has been called already:
+ ASSERT(m_HasTerminated);
+}
+
+
+
+
+
+cNetworkSingleton & cNetworkSingleton::Get(void)
+{
+ static cNetworkSingleton Instance;
+ return Instance;
+}
+
+
+
+
+
+void cNetworkSingleton::Initialise(void)
{
// Windows: initialize networking:
#ifdef _WIN32
@@ -64,26 +92,7 @@ cNetworkSingleton::cNetworkSingleton(void):
// Create the event loop thread:
m_EventLoopThread = std::thread(RunEventLoop, this);
-}
-
-
-
-
-
-cNetworkSingleton::~cNetworkSingleton()
-{
- // Check that Terminate has been called already:
- ASSERT(m_HasTerminated);
-}
-
-
-
-
-
-cNetworkSingleton & cNetworkSingleton::Get(void)
-{
- static cNetworkSingleton Instance;
- return Instance;
+ m_HasTerminated = false;
}
diff --git a/src/OSSupport/NetworkSingleton.h b/src/OSSupport/NetworkSingleton.h
index 0536a1c82..c72df38ec 100644
--- a/src/OSSupport/NetworkSingleton.h
+++ b/src/OSSupport/NetworkSingleton.h
@@ -44,13 +44,18 @@ typedef std::vector<cIPLookupPtr> cIPLookupPtrs;
class cNetworkSingleton
{
public:
+ cNetworkSingleton();
~cNetworkSingleton();
/** Returns the singleton instance of this class */
static cNetworkSingleton & Get(void);
+ /** Initialises all network-related threads.
+ To be called on first run or after app restart. */
+ void Initialise(void);
+
/** Terminates all network-related threads.
- To be used only on app shutdown.
+ To be used only on app shutdown or restart.
MSVC runtime requires that the LibEvent networking be shut down before the main() function is exitted; this is the way to do it. */
void Terminate(void);
@@ -122,10 +127,6 @@ protected:
/** The thread in which the main LibEvent loop runs. */
std::thread m_EventLoopThread;
-
- /** Initializes the LibEvent internals. */
- cNetworkSingleton(void);
-
/** Converts LibEvent-generated log events into log messages in MCS log. */
static void LogCallback(int a_Severity, const char * a_Msg);
diff --git a/src/Root.cpp b/src/Root.cpp
index 624e95e18..222c799b2 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -26,10 +26,10 @@
#include <iostream>
#ifdef _WIN32
- #include <conio.h>
#include <psapi.h>
#elif defined(__linux__)
#include <fstream>
+ #include <signal.h>
#elif defined(__APPLE__)
#include <mach/mach.h>
#endif
@@ -39,7 +39,6 @@
cRoot * cRoot::s_Root = nullptr;
-bool cRoot::m_ShouldStop = false;
@@ -53,10 +52,10 @@ cRoot::cRoot(void) :
m_FurnaceRecipe(nullptr),
m_WebAdmin(nullptr),
m_PluginManager(nullptr),
- m_MojangAPI(nullptr),
- m_bRestart(false)
+ m_MojangAPI(nullptr)
{
s_Root = this;
+ m_InputThreadRunFlag.clear();
}
@@ -76,24 +75,22 @@ void cRoot::InputThread(cRoot & a_Params)
{
cLogCommandOutputCallback Output;
- while (!cRoot::m_ShouldStop && !a_Params.m_bRestart && !m_TerminateEventRaised && std::cin.good())
+ while (a_Params.m_InputThreadRunFlag.test_and_set() && std::cin.good())
{
AString Command;
std::getline(std::cin, Command);
if (!Command.empty())
{
+ // Execute and clear command string when submitted
a_Params.ExecuteConsoleCommand(TrimString(Command), Output);
}
}
- if (m_TerminateEventRaised || !std::cin.good())
+ // We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running
+ if (!std::cin.good())
{
- // We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running
// Stop the server:
- if (!m_RunAsService) // Dont kill if running as a service
- {
- a_Params.m_ShouldStop = true;
- }
+ a_Params.QueueExecuteConsoleCommand("stop");
}
}
@@ -101,12 +98,12 @@ void cRoot::InputThread(cRoot & a_Params)
-void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo)
+void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> a_OverridesRepo)
{
#ifdef _WIN32
- HWND hwnd = GetConsoleWindow();
- HMENU hmenu = GetSystemMenu(hwnd, FALSE);
- EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED); // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling
+ HWND hwnd = GetConsoleWindow();
+ HMENU hmenu = GetSystemMenu(hwnd, FALSE);
+ EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED); // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling
#endif
cLogger::cListener * consoleLogListener = MakeConsoleListener(m_RunAsService);
@@ -127,156 +124,197 @@ void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo)
#endif
cDeadlockDetect dd;
+ auto BeginTime = std::chrono::steady_clock::now();
- m_ShouldStop = false;
- while (!m_ShouldStop)
- {
- auto BeginTime = std::chrono::steady_clock::now();
- m_bRestart = false;
-
- LoadGlobalSettings();
+ LoadGlobalSettings();
- LOG("Creating new server instance...");
- m_Server = new cServer();
+ LOG("Creating new server instance...");
+ m_Server = new cServer();
- LOG("Reading server config...");
+ LOG("Reading server config...");
- auto IniFile = cpp14::make_unique<cIniFile>();
- if (!IniFile->ReadFile("settings.ini"))
- {
- LOGWARN("Regenerating settings.ini, all settings will be reset");
- IniFile->AddHeaderComment(" This is the main server configuration");
- IniFile->AddHeaderComment(" Most of the settings here can be configured using the webadmin interface, if enabled in webadmin.ini");
- IniFile->AddHeaderComment(" See: http://wiki.mc-server.org/doku.php?id=configure:settings.ini for further configuration help");
- }
- auto settingsRepo = cpp14::make_unique<cOverridesSettingsRepository>(std::move(IniFile), std::move(overridesRepo));
+ auto IniFile = cpp14::make_unique<cIniFile>();
+ if (!IniFile->ReadFile("settings.ini"))
+ {
+ LOGWARN("Regenerating settings.ini, all settings will be reset");
+ IniFile->AddHeaderComment(" This is the main server configuration");
+ IniFile->AddHeaderComment(" Most of the settings here can be configured using the webadmin interface, if enabled in webadmin.ini");
+ IniFile->AddHeaderComment(" See: http://wiki.mc-server.org/doku.php?id=configure:settings.ini for further configuration help");
+ }
+ auto settingsRepo = cpp14::make_unique<cOverridesSettingsRepository>(std::move(IniFile), std::move(a_OverridesRepo));
- LOG("Starting server...");
- m_MojangAPI = new cMojangAPI;
- bool ShouldAuthenticate = settingsRepo->GetValueSetB("Authentication", "Authenticate", true);
- m_MojangAPI->Start(*settingsRepo, ShouldAuthenticate); // Mojang API needs to be started before plugins, so that plugins may use it for DB upgrades on server init
- if (!m_Server->InitServer(*settingsRepo, ShouldAuthenticate))
- {
- settingsRepo->Flush();
- LOGERROR("Failure starting server, aborting...");
- return;
- }
+ LOG("Starting server...");
+ m_MojangAPI = new cMojangAPI;
+ bool ShouldAuthenticate = settingsRepo->GetValueSetB("Authentication", "Authenticate", true);
+ m_MojangAPI->Start(*settingsRepo, ShouldAuthenticate); // Mojang API needs to be started before plugins, so that plugins may use it for DB upgrades on server init
+ if (!m_Server->InitServer(*settingsRepo, ShouldAuthenticate))
+ {
+ settingsRepo->Flush();
+ LOGERROR("Failure starting server, aborting...");
+ return;
+ }
- m_WebAdmin = new cWebAdmin();
- m_WebAdmin->Init();
+ m_WebAdmin = new cWebAdmin();
+ m_WebAdmin->Init();
- LOGD("Loading settings...");
- m_RankManager.reset(new cRankManager());
- m_RankManager->Initialize(*m_MojangAPI);
- m_CraftingRecipes = new cCraftingRecipes;
- m_FurnaceRecipe = new cFurnaceRecipe();
+ LOGD("Loading settings...");
+ m_RankManager.reset(new cRankManager());
+ m_RankManager->Initialize(*m_MojangAPI);
+ m_CraftingRecipes = new cCraftingRecipes();
+ m_FurnaceRecipe = new cFurnaceRecipe();
- LOGD("Loading worlds...");
- LoadWorlds(*settingsRepo);
+ LOGD("Loading worlds...");
+ LoadWorlds(*settingsRepo);
- LOGD("Loading plugin manager...");
- m_PluginManager = new cPluginManager();
- m_PluginManager->ReloadPluginsNow(*settingsRepo);
+ LOGD("Loading plugin manager...");
+ m_PluginManager = new cPluginManager();
+ m_PluginManager->ReloadPluginsNow(*settingsRepo);
- LOGD("Loading MonsterConfig...");
- m_MonsterConfig = new cMonsterConfig;
+ LOGD("Loading MonsterConfig...");
+ m_MonsterConfig = new cMonsterConfig;
- // This sets stuff in motion
- LOGD("Starting Authenticator...");
- m_Authenticator.Start(*settingsRepo);
+ // This sets stuff in motion
+ LOGD("Starting Authenticator...");
+ m_Authenticator.Start(*settingsRepo);
- LOGD("Starting worlds...");
- StartWorlds();
+ LOGD("Starting worlds...");
+ StartWorlds();
- if (settingsRepo->GetValueSetB("DeadlockDetect", "Enabled", true))
- {
- LOGD("Starting deadlock detector...");
- dd.Start(settingsRepo->GetValueSetI("DeadlockDetect", "IntervalSec", 20));
- }
+ if (settingsRepo->GetValueSetB("DeadlockDetect", "Enabled", true))
+ {
+ LOGD("Starting deadlock detector...");
+ dd.Start(settingsRepo->GetValueSetI("DeadlockDetect", "IntervalSec", 20));
+ }
- settingsRepo->Flush();
+ settingsRepo->Flush();
- LOGD("Finalising startup...");
- if (m_Server->Start())
- {
- m_WebAdmin->Start();
+ LOGD("Finalising startup...");
+ if (m_Server->Start())
+ {
+ m_WebAdmin->Start();
- #if !defined(ANDROID_NDK)
+ #if !defined(ANDROID_NDK)
LOGD("Starting InputThread...");
try
{
+ m_InputThreadRunFlag.test_and_set();
m_InputThread = std::thread(InputThread, std::ref(*this));
- m_InputThread.detach();
}
catch (std::system_error & a_Exception)
{
LOGERROR("cRoot::Start (std::thread) error %i: could not construct input thread; %s", a_Exception.code().value(), a_Exception.what());
}
- #endif
+ #endif
- LOG("Startup complete, took %ldms!", static_cast<long int>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - BeginTime).count()));
+ LOG("Startup complete, took %ldms!", static_cast<long int>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - BeginTime).count()));
- // Save the current time
- m_StartTime = std::chrono::steady_clock::now();
+ // Save the current time
+ m_StartTime = std::chrono::steady_clock::now();
- #ifdef _WIN32
+ #ifdef _WIN32
EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button
- #endif
+ #endif
+
+ for (;;)
+ {
+ m_StopEvent.Wait();
- while (!m_ShouldStop && !m_bRestart && !m_TerminateEventRaised) // These are modified by external threads
+ if (m_TerminateEventRaised && m_RunAsService)
{
- std::this_thread::sleep_for(std::chrono::seconds(1));
+ // Dont kill if running as a service
+ m_TerminateEventRaised = false;
}
-
- if (m_TerminateEventRaised)
+ else
{
- m_ShouldStop = true;
+ break;
}
+ }
- // Stop the server:
- m_WebAdmin->Stop();
+ // Stop the server:
+ m_WebAdmin->Stop();
- LOG("Shutting down server...");
- m_Server->Shutdown();
- } // if (m_Server->Start())
- else
- {
- m_ShouldStop = true;
- }
+ LOG("Shutting down server...");
+ m_Server->Shutdown();
+ } // if (m_Server->Start()
- delete m_MojangAPI; m_MojangAPI = nullptr;
+ delete m_MojangAPI; m_MojangAPI = nullptr;
- LOGD("Shutting down deadlock detector...");
- dd.Stop();
+ LOGD("Shutting down deadlock detector...");
+ dd.Stop();
- LOGD("Stopping world threads...");
- StopWorlds();
+ LOGD("Stopping world threads...");
+ StopWorlds();
- LOGD("Stopping authenticator...");
- m_Authenticator.Stop();
+ LOGD("Stopping authenticator...");
+ m_Authenticator.Stop();
- LOGD("Freeing MonsterConfig...");
- delete m_MonsterConfig; m_MonsterConfig = nullptr;
- delete m_WebAdmin; m_WebAdmin = nullptr;
+ LOGD("Freeing MonsterConfig...");
+ delete m_MonsterConfig; m_MonsterConfig = nullptr;
+ delete m_WebAdmin; m_WebAdmin = nullptr;
- LOGD("Unloading recipes...");
- delete m_FurnaceRecipe; m_FurnaceRecipe = nullptr;
- delete m_CraftingRecipes; m_CraftingRecipes = nullptr;
+ LOGD("Unloading recipes...");
+ delete m_FurnaceRecipe; m_FurnaceRecipe = nullptr;
+ delete m_CraftingRecipes; m_CraftingRecipes = nullptr;
- LOG("Unloading worlds...");
- UnloadWorlds();
+ LOG("Unloading worlds...");
+ UnloadWorlds();
- LOGD("Stopping plugin manager...");
- delete m_PluginManager; m_PluginManager = nullptr;
+ LOGD("Stopping plugin manager...");
+ delete m_PluginManager; m_PluginManager = nullptr;
- cItemHandler::Deinit();
+ cItemHandler::Deinit();
- LOG("Cleaning up...");
- delete m_Server; m_Server = nullptr;
+ LOG("Cleaning up...");
+ delete m_Server; m_Server = nullptr;
+ m_InputThreadRunFlag.clear();
+ #ifdef _WIN32
+ DWORD Length;
+ INPUT_RECORD Record
+ {
+ static_cast<WORD>(KEY_EVENT),
+ {
+ {
+ TRUE,
+ 1,
+ VK_RETURN,
+ MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC),
+ { { VK_RETURN } },
+ 0
+ }
+ }
+ };
+
+ // Can't kill the input thread since it breaks cin (getline doesn't block / receive input on restart)
+ // Apparently no way to unblock getline
+ // Only thing I can think of for now
+ if (WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &Record, 1, &Length) == 0)
+ {
+ LOGWARN("Couldn't notify the input thread; the server will hang before shutdown!");
+ m_TerminateEventRaised = true;
+ m_InputThread.detach();
+ }
+ else
+ {
+ m_InputThread.join();
+ }
+ #else
+ if (pthread_kill(m_InputThread.native_handle(), SIGKILL) != 0)
+ {
+ LOGWARN("Couldn't notify the input thread; the server will hang before shutdown!");
+ m_TerminateEventRaised = true;
+ m_InputThread.detach();
+ }
+ #endif
+
+ if (m_TerminateEventRaised)
+ {
LOG("Shutdown successful!");
}
-
+ else
+ {
+ LOG("Shutdown successful - restarting...");
+ }
LOG("--- Stopped Log ---");
cLogger::GetInstance().DetachListener(consoleLogListener);
@@ -475,19 +513,9 @@ void cRoot::TickCommands(void)
void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output)
{
- // Some commands are built-in:
- if (a_Cmd == "stop")
- {
- m_ShouldStop = true;
- }
- else if (a_Cmd == "restart")
- {
- m_bRestart = true;
- }
-
// Put the command into a queue (Alleviates FS #363):
cCSLock Lock(m_CSPendingCommands);
- m_PendingCommands.push_back(cCommand(a_Cmd, &a_Output));
+ m_PendingCommands.emplace_back(a_Cmd, &a_Output);
}
@@ -507,15 +535,18 @@ void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd)
void cRoot::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output)
{
- // cRoot handles stopping and restarting due to our access to controlling variables
+ // Some commands are built-in:
if (a_Cmd == "stop")
{
- m_ShouldStop = true;
+ m_TerminateEventRaised = true;
+ m_StopEvent.Set();
+ m_InputThreadRunFlag.clear();
return;
}
else if (a_Cmd == "restart")
{
- m_bRestart = true;
+ m_StopEvent.Set();
+ m_InputThreadRunFlag.clear();
return;
}
diff --git a/src/Root.h b/src/Root.h
index b29fe0a5e..772d858d9 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -7,6 +7,7 @@
#include "Defines.h"
#include "RankManager.h"
#include <thread>
+#include <atomic>
@@ -48,13 +49,12 @@ public:
static bool m_TerminateEventRaised;
static bool m_RunAsService;
- static bool m_ShouldStop;
cRoot(void);
~cRoot();
- void Start(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo);
+ void Start(std::unique_ptr<cSettingsRepositoryInterface> a_OverridesRepo);
// tolua_begin
cServer * GetServer(void) { return m_Server; }
@@ -200,6 +200,8 @@ private:
cCommandQueue m_PendingCommands;
std::thread m_InputThread;
+ cEvent m_StopEvent;
+ std::atomic_flag m_InputThreadRunFlag;
cServer * m_Server;
cMonsterConfig * m_MonsterConfig;
@@ -213,9 +215,7 @@ private:
std::unique_ptr<cRankManager> m_RankManager;
- cHTTPServer m_HTTPServer;
-
- bool m_bRestart;
+ cHTTPServer m_HTTPServer;
void LoadGlobalSettings();
diff --git a/src/main.cpp b/src/main.cpp
index d0a5eb203..bc2439616 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -22,9 +22,6 @@
/** If something has told the server to stop; checked periodically in cRoot */
bool cRoot::m_TerminateEventRaised = false;
-/** Set to true when the server terminates, so our CTRL handler can then tell the OS to close the console. */
-static bool g_ServerTerminated = false;
-
/** If set to true, the protocols will log each player's incoming (C->S) communication to a per-connection logfile */
bool g_ShouldLogCommIn;
@@ -72,7 +69,7 @@ Synchronize this with Server.cpp to enable the "dumpmem" console command. */
void NonCtrlHandler(int a_Signal)
{
LOGD("Terminate event raised from std::signal");
- cRoot::m_TerminateEventRaised = true;
+ cRoot::Get()->QueueExecuteConsoleCommand("stop");
switch (a_Signal)
{
@@ -189,13 +186,11 @@ LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_Except
// Handle CTRL events in windows, including console window close
BOOL CtrlHandler(DWORD fdwCtrlType)
{
- cRoot::m_TerminateEventRaised = true;
+ cRoot::Get()->QueueExecuteConsoleCommand("stop");
LOGD("Terminate event raised from the Windows CtrlHandler");
- while (!g_ServerTerminated)
- {
- std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Delay as much as possible to try to get the server to shut down cleanly
- }
+ std::this_thread::sleep_for(std::chrono::seconds(10)); // Delay as much as possible to try to get the server to shut down cleanly - 10 seconds given by Windows
+ // Returning from main() automatically aborts this handler thread
return TRUE;
}
@@ -206,29 +201,22 @@ BOOL CtrlHandler(DWORD fdwCtrlType)
////////////////////////////////////////////////////////////////////////////////
-// universalMain - Main startup logic for both standard running and as a service
+// UniversalMain - Main startup logic for both standard running and as a service
-void universalMain(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo)
+void UniversalMain(std::unique_ptr<cSettingsRepositoryInterface> a_OverridesRepo)
{
- #ifdef _WIN32
- if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE))
- {
- LOGERROR("Could not install the Windows CTRL handler!");
- }
- #endif
-
// Initialize logging subsystem:
cLogger::InitiateMultithreading();
// Initialize LibEvent:
- cNetworkSingleton::Get();
+ cNetworkSingleton::Get().Initialise();
#if !defined(ANDROID_NDK)
try
#endif
{
cRoot Root;
- Root.Start(std::move(overridesRepo));
+ Root.Start(std::move(a_OverridesRepo));
}
#if !defined(ANDROID_NDK)
catch (std::exception & e)
@@ -241,8 +229,6 @@ void universalMain(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo)
}
#endif
- g_ServerTerminated = true;
-
// Shutdown all of LibEvent:
cNetworkSingleton::Get().Terminate();
}
@@ -259,8 +245,11 @@ DWORD WINAPI serviceWorkerThread(LPVOID lpParam)
{
UNREFERENCED_PARAMETER(lpParam);
- // Do the normal startup
- universalMain(cpp14::make_unique<cMemorySettingsRepository>());
+ while (!cRoot::m_TerminateEventRaised)
+ {
+ // Do the normal startup
+ UniversalMain(cpp14::make_unique<cMemorySettingsRepository>());
+ }
return ERROR_SUCCESS;
}
@@ -274,8 +263,7 @@ DWORD WINAPI serviceWorkerThread(LPVOID lpParam)
void serviceSetState(DWORD acceptedControls, DWORD newState, DWORD exitCode)
{
- SERVICE_STATUS serviceStatus;
- ZeroMemory(&serviceStatus, sizeof(SERVICE_STATUS));
+ SERVICE_STATUS serviceStatus = {};
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwControlsAccepted = acceptedControls;
serviceStatus.dwCurrentState = newState;
@@ -302,11 +290,10 @@ void WINAPI serviceCtrlHandler(DWORD CtrlCode)
{
case SERVICE_CONTROL_STOP:
{
- cRoot::m_ShouldStop = true;
+ cRoot::Get()->QueueExecuteConsoleCommand("stop");
serviceSetState(0, SERVICE_STOP_PENDING, 0);
break;
}
-
default:
{
break;
@@ -365,7 +352,7 @@ void WINAPI serviceMain(DWORD argc, TCHAR *argv[])
-std::unique_ptr<cMemorySettingsRepository> parseArguments(int argc, char **argv)
+std::unique_ptr<cMemorySettingsRepository> ParseArguments(int argc, char **argv)
{
try
{
@@ -484,7 +471,13 @@ int main(int argc, char **argv)
#endif // SIGABRT_COMPAT
#endif
- auto argsRepo = parseArguments(argc, argv);
+
+ #ifdef _WIN32
+ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE))
+ {
+ LOGERROR("Could not install the Windows CTRL handler!");
+ }
+ #endif
// Attempt to run as a service
if (cRoot::m_RunAsService)
@@ -522,13 +515,19 @@ int main(int argc, char **argv)
close(STDOUT_FILENO);
close(STDERR_FILENO);
- universalMain(std::move(argsRepo));
+ while (!cRoot::m_TerminateEventRaised)
+ {
+ UniversalMain(std::move(ParseArguments(argc, argv)));
+ }
#endif
}
else
{
- // Not running as a service, do normal startup
- universalMain(std::move(argsRepo));
+ while (!cRoot::m_TerminateEventRaised)
+ {
+ // Not running as a service, do normal startup
+ UniversalMain(std::move(ParseArguments(argc, argv)));
+ }
}
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
diff --git a/tests/Network/Google.cpp b/tests/Network/Google.cpp
index ab366f9e2..23017d23b 100644
--- a/tests/Network/Google.cpp
+++ b/tests/Network/Google.cpp
@@ -118,6 +118,7 @@ static void DoTest(void)
int main()
{
+ cNetworkSingleton::Get().Initialise();
DoTest();
cNetworkSingleton::Get().Terminate();