2012-06-14 13:06:06 +00:00
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2020-10-05 10:27:14 +00:00
# include "main.h"
2015-05-04 08:07:03 +00:00
# include "BuildInfo.h"
2015-08-30 21:57:43 +00:00
# include "Logger.h"
2015-05-14 14:47:51 +00:00
# include "MemorySettingsRepository.h"
2020-07-22 23:34:43 +00:00
# include "Root.h"
# include "tclap/CmdLine.h"
2012-08-15 21:24:11 +00:00
2021-04-21 15:07:48 +00:00
# include "OSSupport/ConsoleSignalHandler.h"
# include "OSSupport/NetworkSingleton.h"
# include "OSSupport/MiniDumpWriter.h"
# include "OSSupport/SleepResolutionBooster.h"
# include "OSSupport/StartAsService.h"
2016-01-06 15:20:12 +00:00
2015-01-26 13:46:20 +00:00
2014-01-26 16:54:18 +00:00
bool g_ShouldLogCommIn ;
bool g_ShouldLogCommOut ;
2020-07-22 23:34:43 +00:00
bool g_RunAsService ;
2014-01-24 22:03:48 +00:00
2013-12-22 20:03:58 +00:00
2015-04-05 15:07:10 +00:00
2015-03-31 13:50:03 +00:00
////////////////////////////////////////////////////////////////////////////////
2020-07-22 23:34:43 +00:00
// ParseArguments - Read the startup arguments and store into a settings object
2015-03-31 13:50:03 +00:00
2021-04-21 15:07:48 +00:00
static void ParseArguments ( int argc , char * * argv , cMemorySettingsRepository & a_Settings )
2015-03-31 13:50:03 +00:00
{
2020-07-22 23:34:43 +00:00
// Parse the comand line args:
TCLAP : : CmdLine cmd ( " Cuberite " ) ;
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 ) ;
TCLAP : : ValueArg < AString > confArg ( " c " , " config-file " , " Config file to use " , false , " settings.ini " , " string " , cmd ) ;
TCLAP : : MultiArg < int > portsArg ( " p " , " port " , " The port number the server should listen to " , false , " port " , cmd ) ;
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 ) ;
TCLAP : : SwitchArg noFileLogArg ( " " , " no-log-file " , " Disable logging to file " , cmd ) ;
TCLAP : : SwitchArg runAsServiceArg ( " d " , " service " , " Run as a service on Windows, or daemon on UNIX like systems " , cmd ) ;
cmd . parse ( argc , argv ) ;
// Copy the parsed args' values into a settings repository:
if ( confArg . isSet ( ) )
2015-03-31 13:50:03 +00:00
{
2020-07-22 23:34:43 +00:00
AString conf_file = confArg . getValue ( ) ;
2021-04-21 15:07:48 +00:00
a_Settings . AddValue ( " Server " , " ConfigFile " , conf_file ) ;
2015-03-31 13:50:03 +00:00
}
2020-07-22 23:34:43 +00:00
if ( slotsArg . isSet ( ) )
2018-01-03 17:41:16 +00:00
{
2020-07-22 23:34:43 +00:00
int slots = slotsArg . getValue ( ) ;
2021-04-21 15:07:48 +00:00
a_Settings . AddValue ( " Server " , " MaxPlayers " , static_cast < Int64 > ( slots ) ) ;
2018-01-03 17:41:16 +00:00
}
2020-07-22 23:34:43 +00:00
if ( portsArg . isSet ( ) )
2015-03-31 13:50:03 +00:00
{
2020-07-22 23:34:43 +00:00
for ( auto port : portsArg . getValue ( ) )
{
2021-04-21 15:07:48 +00:00
a_Settings . AddValue ( " Server " , " Ports " , std : : to_string ( port ) ) ;
2020-07-22 23:34:43 +00:00
}
2015-03-31 13:50:03 +00:00
}
2020-07-22 23:34:43 +00:00
if ( noFileLogArg . getValue ( ) )
2015-03-31 13:50:03 +00:00
{
2021-04-21 15:07:48 +00:00
a_Settings . AddValue ( " Server " , " DisableLogFile " , true ) ;
2015-03-31 13:50:03 +00:00
}
2020-07-22 23:34:43 +00:00
if ( commLogArg . getValue ( ) )
2015-06-17 14:38:00 +00:00
{
2020-07-22 23:34:43 +00:00
g_ShouldLogCommIn = true ;
g_ShouldLogCommOut = true ;
2015-06-17 14:38:00 +00:00
}
2020-07-22 23:34:43 +00:00
else
2015-03-31 13:50:03 +00:00
{
2020-07-22 23:34:43 +00:00
g_ShouldLogCommIn = commLogInArg . getValue ( ) ;
g_ShouldLogCommOut = commLogOutArg . getValue ( ) ;
2015-03-31 13:50:03 +00:00
}
2020-07-22 23:34:43 +00:00
if ( noBufArg . getValue ( ) )
2015-03-31 13:50:03 +00:00
{
2020-07-22 23:34:43 +00:00
setvbuf ( stdout , nullptr , _IONBF , 0 ) ;
2015-03-31 13:50:03 +00:00
}
2021-04-21 15:07:48 +00:00
a_Settings . SetReadOnly ( ) ;
2015-03-31 13:50:03 +00:00
2020-07-22 23:34:43 +00:00
if ( runAsServiceArg . getValue ( ) )
2015-03-31 13:50:03 +00:00
{
2020-07-22 23:34:43 +00:00
g_RunAsService = true ;
2015-03-31 13:50:03 +00:00
}
2016-02-05 21:45:45 +00:00
2020-07-22 23:34:43 +00:00
// Apply the CrashDump flags for platforms that support them:
if ( crashDumpGlobals . getValue ( ) )
2015-03-31 13:50:03 +00:00
{
2021-04-21 15:07:48 +00:00
MiniDumpWriter : : AddDumpFlags ( MiniDumpFlags : : WithDataSegments ) ;
2020-07-22 23:34:43 +00:00
}
if ( crashDumpFull . getValue ( ) )
{
2021-04-21 15:07:48 +00:00
MiniDumpWriter : : AddDumpFlags ( MiniDumpFlags : : WithFullMemory ) ;
2015-03-31 13:50:03 +00:00
}
}
2015-06-02 10:58:19 +00:00
2020-07-22 23:34:43 +00:00
////////////////////////////////////////////////////////////////////////////////
// UniversalMain - Main startup logic for both standard running and as a service
2021-04-21 15:07:48 +00:00
static int UniversalMain ( int argc , char * argv [ ] , const bool a_RunningAsService )
2015-05-14 14:47:51 +00:00
{
2021-04-21 15:07:48 +00:00
const struct MiniDumpWriterRAII
{
MiniDumpWriterRAII ( )
{
// Registers a last chance exception handler to write a minidump on crash:
MiniDumpWriter : : Register ( ) ;
}
2020-07-22 23:34:43 +00:00
2021-04-21 15:07:48 +00:00
~ MiniDumpWriterRAII ( )
{
MiniDumpWriter : : Unregister ( ) ;
}
} MiniDumpWriter ;
const struct SleepResolutionBoosterRAII
2015-05-14 14:47:51 +00:00
{
2021-04-21 15:07:48 +00:00
SleepResolutionBoosterRAII ( )
2017-02-22 13:10:32 +00:00
{
2021-04-21 15:07:48 +00:00
// Boost timer resolution to keep TPS high:
SleepResolutionBooster : : Register ( ) ;
2017-02-22 13:10:32 +00:00
}
2020-07-22 23:34:43 +00:00
2021-04-21 15:07:48 +00:00
~ SleepResolutionBoosterRAII ( )
2015-05-18 14:43:26 +00:00
{
2021-04-21 15:07:48 +00:00
SleepResolutionBooster : : Unregister ( ) ;
2015-05-18 15:04:27 +00:00
}
2021-04-21 15:07:48 +00:00
} SleepResolutionBooster ;
// Register signal handlers, enabling graceful shutdown from the terminal:
ConsoleSignalHandler : : Register ( ) ;
// Initialize logging subsystem:
cLogger : : InitiateMultithreading ( ) ;
2020-07-22 23:34:43 +00:00
try
{
2020-10-05 10:27:14 +00:00
cMemorySettingsRepository Settings ;
2021-04-21 15:07:48 +00:00
ParseArguments ( argc , argv , Settings ) ; // Make sure g_RunAsService is set correctly before checking its value.
2020-07-22 23:34:43 +00:00
2020-10-05 12:09:42 +00:00
// Attempt to run as a service:
2021-04-21 15:07:48 +00:00
if ( g_RunAsService & & ! a_RunningAsService )
2015-05-18 15:04:27 +00:00
{
2020-07-22 23:34:43 +00:00
// This will either fork or call UniversalMain again:
2021-04-21 15:07:48 +00:00
if ( StartAsService : : MakeIntoService < & UniversalMain > ( ) )
2015-05-18 15:04:27 +00:00
{
2020-07-22 23:34:43 +00:00
return EXIT_SUCCESS ;
2015-05-18 15:04:27 +00:00
}
2015-05-18 14:43:26 +00:00
}
2015-05-18 17:57:16 +00:00
2020-07-22 23:34:43 +00:00
while ( true )
2015-06-01 13:41:06 +00:00
{
2021-04-21 15:07:48 +00:00
const struct NetworkRAII
{
NetworkRAII ( )
{
// Initialize LibEvent:
cNetworkSingleton : : Get ( ) . Initialise ( ) ;
}
~ NetworkRAII ( )
{
// Shutdown all of LibEvent:
cNetworkSingleton : : Get ( ) . Terminate ( ) ;
}
} LibEvent ;
2015-06-01 13:41:06 +00:00
2021-04-21 15:07:48 +00:00
cRoot Root ;
2020-07-22 23:34:43 +00:00
if ( ! Root . Run ( Settings ) )
2015-06-02 10:58:19 +00:00
{
2020-07-22 23:34:43 +00:00
break ;
2015-06-02 10:58:19 +00:00
}
2020-07-22 23:34:43 +00:00
}
2015-05-14 14:47:51 +00:00
2020-07-22 23:34:43 +00:00
return EXIT_SUCCESS ;
2015-05-14 14:47:51 +00:00
}
2020-07-22 23:34:43 +00:00
catch ( const fmt : : format_error & Oops )
2015-05-14 14:47:51 +00:00
{
2020-07-22 23:34:43 +00:00
std : : cerr < < " Formatting exception: " < < Oops . what ( ) < < ' \n ' ;
}
catch ( const TCLAP : : ArgException & Oops )
{
std : : cerr < < fmt : : sprintf ( " Error reading command line {} for argument {} \n " , Oops . error ( ) , Oops . argId ( ) ) ;
}
catch ( const std : : exception & Oops )
{
std : : cerr < < " Standard exception: " < < Oops . what ( ) < < ' \n ' ;
}
catch ( . . . )
{
std : : cerr < < " Unknown exception! \n " ;
2015-05-14 14:47:51 +00:00
}
2020-07-22 23:34:43 +00:00
return EXIT_FAILURE ;
}
2013-12-22 20:03:58 +00:00
2015-06-02 10:58:19 +00:00
2012-06-14 13:06:06 +00:00
2016-01-06 15:20:12 +00:00
int main ( int argc , char * * argv )
2012-06-14 13:06:06 +00:00
{
2020-07-22 23:34:43 +00:00
# if !defined(NDEBUG) && defined(_MSC_VER)
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ) ;
2015-03-31 13:50:03 +00:00
2020-07-22 23:34:43 +00: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);
2015-06-04 13:13:07 +00:00
2021-01-26 09:41:55 +00:00
# endif // !NDEBUG && _MSC_VER
2015-06-04 13:13:07 +00:00
2020-07-22 23:34:43 +00:00
return UniversalMain ( argc , argv , false ) ;
2012-06-14 13:06:06 +00:00
}