2012-06-14 09:06:06 -04:00
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2012-09-23 18:09:57 -04:00
# include "Root.h"
2015-05-14 10:47:51 -04:00
# include "tclap/CmdLine.h"
2012-06-14 09:06:06 -04:00
2014-07-17 13:13:23 -04:00
# include <exception>
# include <csignal>
# include <stdlib.h>
2012-06-14 09:06:06 -04:00
2017-02-22 08:10:32 -05:00
2016-11-07 17:15:07 -05:00
# ifdef ANDROID
// Workaround for Android NDK builds that do not support std::to_string
namespace std
{
template < typename T >
std : : string to_string ( T Value )
{
std : : ostringstream TempStream ;
TempStream < < Value ;
return TempStream . str ( ) ;
}
}
# endif
2013-05-25 10:59:41 -04:00
# ifdef _MSC_VER
2012-06-14 09:06:06 -04:00
# include <dbghelp.h>
2013-05-25 10:59:41 -04:00
# endif // _MSC_VER
2012-06-14 09:06:06 -04:00
2015-01-26 08:46:20 -05:00
# include "OSSupport/NetworkSingleton.h"
2015-05-04 04:07:03 -04:00
# include "BuildInfo.h"
2015-08-30 17:57:43 -04:00
# include "Logger.h"
2014-07-19 18:44:19 -04:00
2015-05-14 10:47:51 -04:00
# include "MemorySettingsRepository.h"
2012-08-15 17:24:11 -04:00
2012-06-14 09:06:06 -04:00
2016-01-06 10:20:12 -05:00
// Forward declarations to satisfy Clang's -Wmissing-variable-declarations:
extern bool g_ShouldLogCommIn ;
extern bool g_ShouldLogCommOut ;
2015-01-26 08:46:20 -05:00
/** If something has told the server to stop; checked periodically in cRoot */
bool cRoot : : m_TerminateEventRaised = false ;
2014-01-26 11:54:18 -05:00
/** If set to true, the protocols will log each player's incoming (C->S) communication to a per-connection logfile */
bool g_ShouldLogCommIn ;
/** If set to true, the protocols will log each player's outgoing (S->C) communication to a per-connection logfile */
bool g_ShouldLogCommOut ;
2014-01-24 17:03:48 -05:00
2015-03-31 09:50:03 -04:00
/** If set to true, binary will attempt to run as a service on Windows */
bool cRoot : : m_RunAsService = false ;
2014-01-24 17:03:48 -05:00
2015-04-05 11:07:10 -04:00
2015-03-31 09:50:03 -04:00
# if defined(_WIN32)
2015-06-02 06:58:19 -04:00
SERVICE_STATUS_HANDLE g_StatusHandle = nullptr ;
2015-04-05 11:07:10 -04:00
HANDLE g_ServiceThread = INVALID_HANDLE_VALUE ;
2015-09-26 17:19:29 -04:00
# define SERVICE_NAME L"CuberiteService"
2015-03-31 09:50:03 -04:00
# endif
2014-01-24 17:03:48 -05:00
2015-04-05 11:07:10 -04:00
2016-01-06 10:20:12 -05:00
# ifndef _DEBUG
static void NonCtrlHandler ( int a_Signal )
2012-06-14 09:06:06 -04:00
{
2013-12-22 15:03:58 -05:00
LOGD ( " Terminate event raised from std::signal " ) ;
2015-06-17 10:38:00 -04:00
cRoot : : Get ( ) - > QueueExecuteConsoleCommand ( " stop " ) ;
2012-06-14 09:06:06 -04:00
2013-12-22 15:03:58 -05:00
switch ( a_Signal )
{
case SIGSEGV :
{
std : : signal ( SIGSEGV , SIG_DFL ) ;
2015-09-25 04:14:17 -04:00
LOGERROR ( " D: | Cuberite has encountered an error and needs to close " ) ;
2014-01-16 17:30:57 -05:00
LOGERROR ( " Details | SIGSEGV: Segmentation fault " ) ;
2015-05-04 04:07:03 -04:00
# ifdef BUILD_ID
2015-09-25 04:14:17 -04:00
LOGERROR ( " Cuberite " BUILD_SERIES_NAME " build id: " BUILD_ID ) ;
2015-05-04 04:07:03 -04:00
LOGERROR ( " from commit id: " BUILD_COMMIT_ID " built at: " BUILD_DATETIME ) ;
# endif
2014-11-29 17:06:10 -05:00
PrintStackTrace ( ) ;
2014-06-01 12:23:02 -04:00
abort ( ) ;
2013-12-22 15:03:58 -05:00
}
2014-01-16 17:30:57 -05:00
case SIGABRT :
2014-01-17 05:13:35 -05:00
# ifdef SIGABRT_COMPAT
2014-01-16 17:30:57 -05:00
case SIGABRT_COMPAT :
2014-01-17 05:13:35 -05:00
# endif
2014-01-16 17:30:57 -05:00
{
std : : signal ( a_Signal , SIG_DFL ) ;
2015-09-25 04:14:17 -04:00
LOGERROR ( " D: | Cuberite has encountered an error and needs to close " ) ;
2014-01-16 17:30:57 -05:00
LOGERROR ( " Details | SIGABRT: Server self-terminated due to an internal fault " ) ;
2015-05-04 04:07:03 -04:00
# ifdef BUILD_ID
2015-09-25 04:14:17 -04:00
LOGERROR ( " Cuberite " BUILD_SERIES_NAME " build id: " BUILD_ID ) ;
2015-05-04 04:07:03 -04:00
LOGERROR ( " from commit id: " BUILD_COMMIT_ID " built at: " BUILD_DATETIME ) ;
# endif
2014-11-29 17:06:10 -05:00
PrintStackTrace ( ) ;
2014-06-01 12:23:02 -04:00
abort ( ) ;
2014-01-16 17:30:57 -05:00
}
2014-01-26 11:15:05 -05:00
case SIGINT :
2014-01-07 16:23:26 -05:00
case SIGTERM :
{
2014-07-17 13:13:23 -04:00
std : : signal ( a_Signal , SIG_IGN ) ; // Server is shutting down, wait for it...
2014-01-07 16:23:26 -05:00
break ;
}
2013-12-22 15:03:58 -05:00
default : break ;
}
2012-06-14 09:06:06 -04:00
}
2016-01-06 10:20:12 -05:00
# endif // _DEBUG
2012-06-14 09:06:06 -04:00
2013-05-25 10:59:41 -04:00
# if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER)
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2012-06-14 09:06:06 -04:00
// Windows 32-bit stuff: when the server crashes, create a "dump file" containing the callstack of each thread and some variables; let the user send us that crash file for analysis
typedef BOOL ( WINAPI * pMiniDumpWriteDump ) (
HANDLE hProcess ,
DWORD ProcessId ,
HANDLE hFile ,
MINIDUMP_TYPE DumpType ,
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam ,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam ,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam
) ;
2016-01-06 10:20:12 -05:00
static pMiniDumpWriteDump g_WriteMiniDump ; // The function in dbghlp DLL that creates dump files
2012-06-14 09:06:06 -04:00
2016-01-06 10:20:12 -05:00
static wchar_t g_DumpFileName [ MAX_PATH ] ; // Filename of the dump file; hes to be created before the dump handler kicks in
static char g_ExceptionStack [ 128 * 1024 ] ; // Substitute stack, just in case the handler kicks in because of "insufficient stack space"
static MINIDUMP_TYPE g_DumpFlags = MiniDumpNormal ; // By default dump only the stack and some helpers
2012-06-14 09:06:06 -04:00
/** This function gets called just before the "program executed an illegal instruction and will be terminated" or similar.
Its purpose is to create the crashdump using the dbghlp DLLs
*/
2016-01-06 10:20:12 -05:00
static LONG WINAPI LastChanceExceptionFilter ( __in struct _EXCEPTION_POINTERS * a_ExceptionInfo )
2012-06-14 09:06:06 -04:00
{
2015-06-02 06:58:19 -04:00
char * newStack = & g_ExceptionStack [ sizeof ( g_ExceptionStack ) - 1 ] ;
2012-06-14 09:06:06 -04:00
char * oldStack ;
// Use the substitute stack:
// This code is the reason why we don't support 64-bit (yet)
_asm
{
mov oldStack , esp
mov esp , newStack
}
MINIDUMP_EXCEPTION_INFORMATION ExcInformation ;
ExcInformation . ThreadId = GetCurrentThreadId ( ) ;
ExcInformation . ExceptionPointers = a_ExceptionInfo ;
ExcInformation . ClientPointers = 0 ;
// Write the dump file:
2014-10-20 16:55:07 -04:00
HANDLE dumpFile = CreateFile ( g_DumpFileName , GENERIC_WRITE , 0 , nullptr , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , nullptr ) ;
g_WriteMiniDump ( GetCurrentProcess ( ) , GetCurrentProcessId ( ) , dumpFile , g_DumpFlags , ( a_ExceptionInfo ) ? & ExcInformation : nullptr , nullptr , nullptr ) ;
2012-06-14 09:06:06 -04:00
CloseHandle ( dumpFile ) ;
2014-11-29 17:06:10 -05:00
// Print the stack trace for the basic debugging:
PrintStackTrace ( ) ;
2012-06-14 09:06:06 -04:00
// Revert to old stack:
_asm
{
mov esp , oldStack
}
return 0 ;
}
# endif // _WIN32 && !_WIN64
2015-04-05 11:07:10 -04:00
2013-12-22 15:03:58 -05:00
# ifdef _WIN32
// Handle CTRL events in windows, including console window close
2016-01-06 10:20:12 -05:00
static BOOL CtrlHandler ( DWORD fdwCtrlType )
2013-12-22 15:03:58 -05:00
{
2015-06-17 10:38:00 -04:00
cRoot : : Get ( ) - > QueueExecuteConsoleCommand ( " stop " ) ;
2013-12-22 15:03:58 -05:00
LOGD ( " Terminate event raised from the Windows CtrlHandler " ) ;
2015-06-17 10:38:00 -04:00
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
2013-12-22 15:03:58 -05:00
return TRUE ;
}
# endif
2015-04-05 11:07:10 -04:00
2015-03-31 09:50:03 -04:00
////////////////////////////////////////////////////////////////////////////////
2015-06-17 10:38:00 -04:00
// UniversalMain - Main startup logic for both standard running and as a service
2015-03-31 09:50:03 -04:00
2016-01-06 10:20:12 -05:00
static void UniversalMain ( std : : unique_ptr < cSettingsRepositoryInterface > a_OverridesRepo )
2015-03-31 09:50:03 -04:00
{
// Initialize logging subsystem:
cLogger : : InitiateMultithreading ( ) ;
// Initialize LibEvent:
2015-06-17 10:38:00 -04:00
cNetworkSingleton : : Get ( ) . Initialise ( ) ;
2015-03-31 09:50:03 -04:00
try
{
2015-04-05 11:07:10 -04:00
cRoot Root ;
2015-06-17 10:38:00 -04:00
Root . Start ( std : : move ( a_OverridesRepo ) ) ;
2015-03-31 09:50:03 -04:00
}
catch ( std : : exception & e )
{
LOGERROR ( " Standard exception: %s " , e . what ( ) ) ;
}
catch ( . . . )
{
LOGERROR ( " Unknown exception! " ) ;
}
// Shutdown all of LibEvent:
cNetworkSingleton : : Get ( ) . Terminate ( ) ;
}
2015-06-02 06:58:19 -04:00
2015-06-04 09:13:07 -04:00
# if defined(_WIN32) // Windows service support.
2015-03-31 09:50:03 -04:00
////////////////////////////////////////////////////////////////////////////////
// serviceWorkerThread: Keep the service alive
2016-01-06 10:20:12 -05:00
static DWORD WINAPI serviceWorkerThread ( LPVOID lpParam )
2015-03-31 09:50:03 -04:00
{
UNREFERENCED_PARAMETER ( lpParam ) ;
2015-06-17 10:38:00 -04:00
while ( ! cRoot : : m_TerminateEventRaised )
{
// Do the normal startup
UniversalMain ( cpp14 : : make_unique < cMemorySettingsRepository > ( ) ) ;
}
2015-03-31 09:50:03 -04:00
return ERROR_SUCCESS ;
}
2015-06-02 06:58:19 -04:00
2015-03-31 09:50:03 -04:00
////////////////////////////////////////////////////////////////////////////////
// serviceSetState: Set the internal status of the service
2016-01-06 10:20:12 -05:00
static void serviceSetState ( DWORD acceptedControls , DWORD newState , DWORD exitCode )
2015-03-31 09:50:03 -04:00
{
2015-06-17 10:38:00 -04:00
SERVICE_STATUS serviceStatus = { } ;
2015-03-31 09:50:03 -04:00
serviceStatus . dwCheckPoint = 0 ;
serviceStatus . dwControlsAccepted = acceptedControls ;
serviceStatus . dwCurrentState = newState ;
serviceStatus . dwServiceSpecificExitCode = 0 ;
serviceStatus . dwServiceType = SERVICE_WIN32 ;
serviceStatus . dwWaitHint = 0 ;
serviceStatus . dwWin32ExitCode = exitCode ;
if ( SetServiceStatus ( g_StatusHandle , & serviceStatus ) = = FALSE )
{
LOGERROR ( " SetServiceStatus() failed \n " ) ;
}
}
////////////////////////////////////////////////////////////////////////////////
// serviceCtrlHandler: Handle stop events from the Service Control Manager
2016-01-06 10:20:12 -05:00
static void WINAPI serviceCtrlHandler ( DWORD CtrlCode )
2015-03-31 09:50:03 -04:00
{
switch ( CtrlCode )
{
case SERVICE_CONTROL_STOP :
{
2015-06-17 10:38:00 -04:00
cRoot : : Get ( ) - > QueueExecuteConsoleCommand ( " stop " ) ;
2015-03-31 09:50:03 -04:00
serviceSetState ( 0 , SERVICE_STOP_PENDING , 0 ) ;
break ;
}
default :
{
break ;
}
}
}
////////////////////////////////////////////////////////////////////////////////
// serviceMain: Startup logic for running as a service
2016-01-06 10:20:12 -05:00
static void WINAPI serviceMain ( DWORD argc , TCHAR * argv [ ] )
2015-03-31 09:50:03 -04:00
{
2015-09-26 17:19:29 -04:00
wchar_t applicationFilename [ MAX_PATH ] ;
wchar_t applicationDirectory [ MAX_PATH ] ;
2015-03-31 09:50:03 -04:00
2015-06-02 06:58:19 -04:00
GetModuleFileName ( nullptr , applicationFilename , sizeof ( applicationFilename ) ) ; // This binary's file path.
2015-03-31 09:50:03 -04:00
2015-04-06 16:01:25 -04:00
// Strip off the filename, keep only the path:
2015-09-26 17:19:29 -04:00
wcsncpy_s ( applicationDirectory , sizeof ( applicationDirectory ) , applicationFilename , ( wcsrchr ( applicationFilename , ' \\ ' ) - applicationFilename ) ) ;
applicationDirectory [ wcslen ( applicationDirectory ) ] = ' \0 ' ; // Make sure new path is null terminated
2015-03-31 09:50:03 -04:00
// Services are run by the SCM, and inherit its working directory - usually System32.
// Set the working directory to the same location as the binary.
SetCurrentDirectory ( applicationDirectory ) ;
g_StatusHandle = RegisterServiceCtrlHandler ( SERVICE_NAME , serviceCtrlHandler ) ;
2015-06-02 06:58:19 -04:00
if ( g_StatusHandle = = nullptr )
2015-03-31 09:50:03 -04:00
{
2015-04-06 16:01:25 -04:00
OutputDebugStringA ( " RegisterServiceCtrlHandler() failed \n " ) ;
2015-03-31 09:50:03 -04:00
serviceSetState ( 0 , SERVICE_STOPPED , GetLastError ( ) ) ;
return ;
}
2016-02-05 16:45:45 -05:00
2015-03-31 09:50:03 -04:00
serviceSetState ( SERVICE_ACCEPT_STOP , SERVICE_RUNNING , 0 ) ;
2016-02-05 16:45:45 -05:00
2015-06-02 06:58:19 -04:00
DWORD ThreadID ;
g_ServiceThread = CreateThread ( nullptr , 0 , serviceWorkerThread , nullptr , 0 , & ThreadID ) ;
if ( g_ServiceThread = = nullptr )
2015-03-31 09:50:03 -04:00
{
2015-04-06 16:01:25 -04:00
OutputDebugStringA ( " CreateThread() failed \n " ) ;
2015-03-31 09:50:03 -04:00
serviceSetState ( 0 , SERVICE_STOPPED , GetLastError ( ) ) ;
return ;
}
WaitForSingleObject ( g_ServiceThread , INFINITE ) ; // Wait here for a stop signal.
2016-02-05 16:45:45 -05:00
2015-03-31 09:50:03 -04:00
CloseHandle ( g_ServiceThread ) ;
2016-02-05 16:45:45 -05:00
2015-03-31 09:50:03 -04:00
serviceSetState ( 0 , SERVICE_STOPPED , 0 ) ;
}
2015-06-04 09:13:07 -04:00
# endif // Windows service support.
2015-03-31 09:50:03 -04:00
2015-06-02 06:58:19 -04:00
2016-01-06 10:20:12 -05:00
static std : : unique_ptr < cMemorySettingsRepository > ParseArguments ( int argc , char * * argv )
2015-05-14 10:47:51 -04:00
{
try
{
2015-06-02 06:58:19 -04:00
// Parse the comand line args:
2015-09-25 04:14:17 -04:00
TCLAP : : CmdLine cmd ( " Cuberite " ) ;
2015-06-02 06:58:19 -04:00
TCLAP : : ValueArg < int > slotsArg ( " s " , " max-players " , " Maximum number of slots for the server to use, overrides setting in setting.ini " , false , - 1 , " number " , cmd ) ;
2017-02-22 08:10:32 -05:00
TCLAP : : ValueArg < AString > confArg ( " c " , " config-file " , " Config file to use " , false , " settings.ini " , " string " , cmd ) ;
2016-04-14 05:40:46 -04:00
TCLAP : : MultiArg < int > portsArg ( " p " , " port " , " The port number the server should listen to " , false , " port " , cmd ) ;
2015-06-02 06:58:19 -04:00
TCLAP : : SwitchArg commLogArg ( " " , " log-comm " , " Log server client communications to file " , cmd ) ;
TCLAP : : SwitchArg commLogInArg ( " " , " log-comm-in " , " Log inbound server client communications to file " , cmd ) ;
TCLAP : : SwitchArg commLogOutArg ( " " , " log-comm-out " , " Log outbound server client communications to file " , cmd ) ;
TCLAP : : SwitchArg crashDumpFull ( " " , " crash-dump-full " , " Crashdumps created by the server will contain full server memory " , cmd ) ;
TCLAP : : SwitchArg crashDumpGlobals ( " " , " crash-dump-globals " , " Crashdumps created by the server will contain the global variables' values " , cmd ) ;
TCLAP : : SwitchArg noBufArg ( " " , " no-output-buffering " , " Disable output buffering " , cmd ) ;
2017-04-01 11:28:42 -04:00
TCLAP : : SwitchArg noFileLogArg ( " " , " no-log-file " , " Disable logging to file " , cmd ) ;
2015-06-04 09:13:07 -04:00
TCLAP : : SwitchArg runAsServiceArg ( " d " , " service " , " Run as a service on Windows, or daemon on UNIX like systems " , cmd ) ;
2015-05-14 10:47:51 -04:00
cmd . parse ( argc , argv ) ;
2015-06-02 06:58:19 -04:00
// Copy the parsed args' values into a settings repository:
2015-05-15 08:57:27 -04:00
auto repo = cpp14 : : make_unique < cMemorySettingsRepository > ( ) ;
2017-02-22 08:10:32 -05:00
if ( confArg . isSet ( ) )
{
AString conf_file = confArg . getValue ( ) ;
repo - > AddValue ( " Server " , " ConfigFile " , conf_file ) ;
}
2015-05-18 10:43:26 -04:00
if ( slotsArg . isSet ( ) )
{
int slots = slotsArg . getValue ( ) ;
2015-05-18 11:04:27 -04:00
repo - > AddValue ( " Server " , " MaxPlayers " , static_cast < Int64 > ( slots ) ) ;
}
if ( portsArg . isSet ( ) )
{
2015-06-02 06:58:19 -04:00
for ( auto port : portsArg . getValue ( ) )
2015-05-18 11:04:27 -04:00
{
2016-07-30 07:21:11 -04:00
repo - > AddValue ( " Server " , " Ports " , std : : to_string ( port ) ) ;
2015-05-18 11:04:27 -04:00
}
2015-05-18 10:43:26 -04:00
}
2017-04-01 11:28:42 -04:00
if ( noFileLogArg . getValue ( ) )
{
repo - > AddValue ( " Server " , " DisableLogFile " , true ) ;
}
2015-05-18 13:50:29 -04:00
if ( commLogArg . getValue ( ) )
{
g_ShouldLogCommIn = true ;
g_ShouldLogCommOut = true ;
}
else
{
g_ShouldLogCommIn = commLogInArg . getValue ( ) ;
g_ShouldLogCommOut = commLogOutArg . getValue ( ) ;
}
2015-05-18 13:57:16 -04:00
if ( noBufArg . getValue ( ) )
{
setvbuf ( stdout , nullptr , _IONBF , 0 ) ;
}
2015-06-02 06:58:19 -04:00
repo - > SetReadOnly ( ) ;
2015-05-18 13:57:16 -04:00
2015-06-02 06:58:19 -04:00
// Set the service flag directly to cRoot:
2015-06-01 09:41:06 -04:00
if ( runAsServiceArg . getValue ( ) )
{
cRoot : : m_RunAsService = true ;
}
2015-06-02 06:58:19 -04:00
// Apply the CrashDump flags for platforms that support them:
# if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER) // 32-bit Windows app compiled in MSVC
if ( crashDumpGlobals . getValue ( ) )
{
g_DumpFlags = static_cast < MINIDUMP_TYPE > ( g_DumpFlags | MiniDumpWithDataSegs ) ;
}
if ( crashDumpFull . getValue ( ) )
{
g_DumpFlags = static_cast < MINIDUMP_TYPE > ( g_DumpFlags | MiniDumpWithFullMemory ) ;
}
# endif // 32-bit Windows app compiled in MSVC
2015-05-14 10:47:51 -04:00
return repo ;
}
2015-06-02 06:58:19 -04:00
catch ( const TCLAP : : ArgException & exc )
2015-05-14 10:47:51 -04:00
{
2015-06-02 06:58:19 -04:00
printf ( " Error reading command line %s for arg %s " , exc . error ( ) . c_str ( ) , exc . argId ( ) . c_str ( ) ) ;
2015-05-18 10:43:26 -04:00
return cpp14 : : make_unique < cMemorySettingsRepository > ( ) ;
2015-05-14 10:47:51 -04:00
}
}
2013-12-22 15:03:58 -05:00
2015-06-02 06:58:19 -04:00
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2012-06-14 09:06:06 -04:00
// main:
2016-01-06 10:20:12 -05:00
int main ( int argc , char * * argv )
2012-06-14 09:06:06 -04:00
{
// Magic code to produce dump-files on Windows if the server crashes:
2015-06-02 06:58:19 -04:00
# if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER) // 32-bit Windows app compiled in MSVC
2015-09-26 17:19:29 -04:00
HINSTANCE hDbgHelp = LoadLibrary ( L " DBGHELP.DLL " ) ;
2015-06-02 06:58:19 -04:00
g_WriteMiniDump = ( pMiniDumpWriteDump ) GetProcAddress ( hDbgHelp , " MiniDumpWriteDump " ) ;
if ( g_WriteMiniDump ! = nullptr )
2012-06-14 09:06:06 -04:00
{
2015-09-26 17:19:29 -04:00
_snwprintf_s ( g_DumpFileName , ARRAYCOUNT ( g_DumpFileName ) , _TRUNCATE , L " crash_mcs_%x.dmp " , GetCurrentProcessId ( ) ) ;
2015-06-02 06:58:19 -04:00
SetUnhandledExceptionFilter ( LastChanceExceptionFilter ) ;
}
# endif // 32-bit Windows app compiled in MSVC
2012-06-14 09:06:06 -04:00
// End of dump-file magic
2013-12-22 15:03:58 -05:00
2015-06-02 06:58:19 -04:00
2012-06-14 09:06:06 -04:00
# if defined(_DEBUG) && defined(_MSC_VER)
2015-06-02 06:58:19 -04:00
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ) ;
2016-02-05 16:45:45 -05:00
2015-06-02 06:58:19 -04:00
// _X: The simple built-in CRT leak finder - simply break when allocating the Nth block ({N} is listed in the leak output)
// Only useful when the leak is in the same sequence all the time
// _CrtSetBreakAlloc(85950);
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
# endif // _DEBUG && _MSC_VER
# ifndef _DEBUG
2015-06-02 06:58:19 -04:00
std : : signal ( SIGSEGV , NonCtrlHandler ) ;
std : : signal ( SIGTERM , NonCtrlHandler ) ;
std : : signal ( SIGINT , NonCtrlHandler ) ;
std : : signal ( SIGABRT , NonCtrlHandler ) ;
# ifdef SIGABRT_COMPAT
std : : signal ( SIGABRT_COMPAT , NonCtrlHandler ) ;
# endif // SIGABRT_COMPAT
2012-06-14 09:06:06 -04:00
# endif
2015-09-19 12:54:42 -04:00
# ifdef __unix__
std : : signal ( SIGPIPE , SIG_IGN ) ;
# endif
2016-02-05 16:45:45 -05:00
2015-06-17 10:38:00 -04:00
# ifdef _WIN32
if ( ! SetConsoleCtrlHandler ( ( PHANDLER_ROUTINE ) CtrlHandler , TRUE ) )
{
LOGERROR ( " Could not install the Windows CTRL handler! " ) ;
}
# endif
2015-06-04 09:13:07 -04:00
2016-01-21 10:22:05 -05:00
// Make sure m_RunAsService is set correctly before checking it's value
ParseArguments ( argc , argv ) ;
2015-06-04 09:13:07 -04:00
// Attempt to run as a service
if ( cRoot : : m_RunAsService )
{
# if defined(_WIN32) // Windows service.
2015-06-02 06:58:19 -04:00
SERVICE_TABLE_ENTRY ServiceTable [ ] =
{
{ SERVICE_NAME , ( LPSERVICE_MAIN_FUNCTION ) serviceMain } ,
{ nullptr , nullptr }
} ;
2015-03-31 09:50:03 -04:00
2015-06-02 06:58:19 -04:00
if ( StartServiceCtrlDispatcher ( ServiceTable ) = = FALSE )
{
LOGERROR ( " Attempted, but failed, service startup. " ) ;
return GetLastError ( ) ;
}
2015-06-04 09:13:07 -04:00
# else // UNIX daemon.
pid_t pid = fork ( ) ;
// fork() returns a negative value on error.
if ( pid < 0 )
{
LOGERROR ( " Could not fork process. " ) ;
return EXIT_FAILURE ;
}
// Check if we are the parent or child process. Parent stops here.
if ( pid > 0 )
{
return EXIT_SUCCESS ;
}
// Child process now goes quiet, running in the background.
close ( STDIN_FILENO ) ;
close ( STDOUT_FILENO ) ;
close ( STDERR_FILENO ) ;
2015-06-17 10:38:00 -04:00
while ( ! cRoot : : m_TerminateEventRaised )
{
2015-09-24 10:04:44 -04:00
UniversalMain ( ParseArguments ( argc , argv ) ) ;
2015-06-17 10:38:00 -04:00
}
2015-06-04 09:13:07 -04:00
# endif
}
else
2012-06-14 09:06:06 -04:00
{
2015-06-17 10:38:00 -04:00
while ( ! cRoot : : m_TerminateEventRaised )
{
// Not running as a service, do normal startup
2015-09-24 10:04:44 -04:00
UniversalMain ( ParseArguments ( argc , argv ) ) ;
2015-06-17 10:38:00 -04:00
}
2012-06-14 09:06:06 -04:00
}
2013-12-22 15:03:58 -05:00
return EXIT_SUCCESS ;
2012-06-14 09:06:06 -04:00
}