From d00592f6925cec4fe8ac12e331461f44dab5f297 Mon Sep 17 00:00:00 2001 From: finomen Date: Tue, 17 May 2011 19:22:56 +0400 Subject: [PATCH] [11500] Allow run mangos as daemon (linux/other posix) Signed-off-by: VladimirMangos --- src/mangosd/Main.cpp | 45 ++++++++---- src/mangosd/Master.cpp | 7 ++ src/realmd/Main.cpp | 45 ++++++++---- src/shared/CMakeLists.txt | 7 +- src/shared/PosixDaemon.cpp | 136 +++++++++++++++++++++++++++++++++++++ src/shared/PosixDaemon.h | 24 +++++++ src/shared/revision_nr.h | 2 +- 7 files changed, 238 insertions(+), 28 deletions(-) create mode 100644 src/shared/PosixDaemon.cpp create mode 100644 src/shared/PosixDaemon.h diff --git a/src/mangosd/Main.cpp b/src/mangosd/Main.cpp index f18fd7814..3be1ba9c1 100644 --- a/src/mangosd/Main.cpp +++ b/src/mangosd/Main.cpp @@ -46,6 +46,8 @@ char serviceDescription[] = "Massive Network Game Object Server"; * 2 - paused */ int m_ServiceStatus = -1; +#else +#include "PosixDaemon.h" #endif DatabaseType WorldDatabase; ///< Accessor to the world database @@ -65,6 +67,10 @@ void usage(const char *prog) " -s run run as service\n\r" " -s install install service\n\r" " -s uninstall uninstall service\n\r" + #else + " Running as daemon functions:\n\r" + " -s run run as daemon\n\r" + " -s stop stop daemon\n\r" #endif ,prog); } @@ -75,15 +81,19 @@ extern int main(int argc, char **argv) ///- Command line parsing char const* cfg_file = _MANGOSD_CONFIG; -#ifdef WIN32 + char const *options = ":c:s:"; -#else - char const *options = ":c:"; -#endif ACE_Get_Opt cmd_opts(argc, argv, options); cmd_opts.long_option("version", 'v'); + if (!sConfig.SetSource(cfg_file)) + { + sLog.outError("Could not find configuration file %s.", cfg_file); + Log::WaitBeforeContinueIfNeed(); + return 1; + } + int option; while ((option = cmd_opts()) != EOF) { @@ -95,9 +105,9 @@ extern int main(int argc, char **argv) case 'v': printf("%s\n", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID)); return 0; -#ifdef WIN32 case 's': - { + { +#ifdef WIN32 const char *mode = cmd_opts.opt_arg(); if (!strcmp(mode, "install")) @@ -122,8 +132,22 @@ extern int main(int argc, char **argv) return 1; } break; - } +#else + const char *mode = cmd_opts.opt_arg(); + if (!strcmp(mode, "run")) + startDaemon(120); + else if (!strcmp(mode, "stop")) + stopDaemon(); + else + { + sLog.outError("Runtime-Error: -%c unsupported argument %s", cmd_opts.opt_opt(), mode); + usage(argv[0]); + Log::WaitBeforeContinueIfNeed(); + return 1; + } #endif + } + break; case ':': sLog.outError("Runtime-Error: -%c option requires an input argument", cmd_opts.opt_opt()); usage(argv[0]); @@ -137,13 +161,6 @@ extern int main(int argc, char **argv) } } - if (!sConfig.SetSource(cfg_file)) - { - sLog.outError("Could not find configuration file %s.", cfg_file); - Log::WaitBeforeContinueIfNeed(); - return 1; - } - sLog.outString( "%s [world-daemon]", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID) ); sLog.outString( " to stop.\n\n" ); diff --git a/src/mangosd/Master.cpp b/src/mangosd/Master.cpp index bb3b38c66..eb9863c35 100644 --- a/src/mangosd/Master.cpp +++ b/src/mangosd/Master.cpp @@ -20,6 +20,10 @@ \ingroup mangosd */ +#ifndef WIN32 + #include "PosixDaemon.h" +#endif + #include "WorldSocketMgr.h" #include "Common.h" #include "Master.h" @@ -197,6 +201,9 @@ int Master::Run() ///- Initialize the World sWorld.SetInitialWorldSettings(); + #ifndef WIN32 + detachDaemon(); + #endif //server loaded successfully => enable async DB requests //this is done to forbid any async transactions during server startup! CharacterDatabase.AllowAsyncTransactions(); diff --git a/src/realmd/Main.cpp b/src/realmd/Main.cpp index 136599260..08356dbd4 100644 --- a/src/realmd/Main.cpp +++ b/src/realmd/Main.cpp @@ -54,6 +54,8 @@ char serviceDescription[] = "Massive Network Game Object Server"; * 2 - paused */ int m_ServiceStatus = -1; +#else +#include "PosixDaemon.h" #endif bool StartDB(); @@ -75,6 +77,10 @@ void usage(const char *prog) " -s run run as service\n\r" " -s install install service\n\r" " -s uninstall uninstall service\n\r" + #else + " Running as daemon functions:\n\r" + " -s run run as daemon\n\r" + " -s stop stop daemon\n\r" #endif ,prog); } @@ -85,16 +91,20 @@ extern int main(int argc, char **argv) ///- Command line parsing char const* cfg_file = _REALMD_CONFIG; -#ifdef WIN32 char const *options = ":c:s:"; -#else - char const *options = ":c:"; -#endif ACE_Get_Opt cmd_opts(argc, argv, options); cmd_opts.long_option("version", 'v'); int option; + + if (!sConfig.SetSource(cfg_file)) + { + sLog.outError("Could not find configuration file %s.", cfg_file); + Log::WaitBeforeContinueIfNeed(); + return 1; + } + while ((option = cmd_opts()) != EOF) { switch (option) @@ -105,9 +115,10 @@ extern int main(int argc, char **argv) case 'v': printf("%s\n", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID)); return 0; -#ifdef WIN32 + case 's': { +#ifdef WIN32 const char *mode = cmd_opts.opt_arg(); if (!strcmp(mode, "install")) @@ -131,9 +142,22 @@ extern int main(int argc, char **argv) Log::WaitBeforeContinueIfNeed(); return 1; } +#else + const char *mode = cmd_opts.opt_arg(); + if (!strcmp(mode, "run")) + startDaemon(); + else if (!strcmp(mode, "stop")) + stopDaemon(); + else + { + sLog.outError("Runtime-Error: -%c unsupported argument %s", cmd_opts.opt_opt(), mode); + usage(argv[0]); + Log::WaitBeforeContinueIfNeed(); + return 1; + } +#endif break; } -#endif case ':': sLog.outError("Runtime-Error: -%c option requires an input argument", cmd_opts.opt_opt()); usage(argv[0]); @@ -147,12 +171,6 @@ extern int main(int argc, char **argv) } } - if (!sConfig.SetSource(cfg_file)) - { - sLog.outError("Could not find configuration file %s.", cfg_file); - Log::WaitBeforeContinueIfNeed(); - return 1; - } sLog.Initialize(); sLog.outString( "%s [realm-daemon]", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID) ); @@ -294,6 +312,9 @@ extern int main(int argc, char **argv) uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / 100000)); uint32 loopCounter = 0; + #ifndef WIN32 + detachDaemon(); + #endif ///- Wait for termination signal while (!stopEvent) { diff --git a/src/shared/CMakeLists.txt b/src/shared/CMakeLists.txt index 5b04b1c21..8f6fab68f 100644 --- a/src/shared/CMakeLists.txt +++ b/src/shared/CMakeLists.txt @@ -20,7 +20,12 @@ file(GLOB_RECURSE shared_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp *.h) # Exclude Win32 files -if(NOT WIN32) +if(WIN32) + list(REMOVE_ITEM shared_SRCS + PosixDaemon.h + PosixDaemon.cpp + ) +else() list(REMOVE_ITEM shared_SRCS WheatyExceptionReport.cpp WheatyExceptionReport.h diff --git a/src/shared/PosixDaemon.cpp b/src/shared/PosixDaemon.cpp new file mode 100644 index 000000000..dde1e4b2e --- /dev/null +++ b/src/shared/PosixDaemon.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2005-2011 MaNGOS + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "Config/Config.h" +#include "PosixDaemon.h" +#include +#include +#include + +pid_t parent_pid = 0, sid = 0; + +void daemonSignal(int s) +{ + + if (getpid() != parent_pid) + { + return; + } + + if (s == SIGUSR1) + { + exit(EXIT_SUCCESS); + } + + if (sid) { + kill(sid, s); + } + + exit(EXIT_FAILURE); +} + + +void startDaemon(uint32_t timeout) +{ + parent_pid = getpid(); + pid_t pid; + + signal(SIGUSR1, daemonSignal); + signal(SIGINT, daemonSignal); + signal(SIGTERM, daemonSignal); + signal(SIGALRM, daemonSignal); + + sid = pid = fork(); + + if (pid < 0) { + exit(EXIT_FAILURE); + } + + if (pid > 0) { + alarm(timeout); + pause(); + exit(EXIT_FAILURE); + } + + umask(0); + + sid = setsid(); + + if (sid < 0) { + exit(EXIT_FAILURE); + } + + if ((chdir("/")) < 0) { + exit(EXIT_FAILURE); + } + + freopen("/dev/null", "rt", stdin); + freopen("/dev/null", "wt", stdout); + freopen("/dev/null", "wt", stderr); +} + +void stopDaemon() +{ + std::string pidfile = sConfig.GetStringDefault("PidFile", ""); + if(!pidfile.empty()) + { + std::fstream pf(pidfile.c_str(), std::ios::in); + uint32_t pid = 0; + pf >> pid; + if (kill(pid, SIGINT) < 0) + { + std::cerr << "Unable to stop daemon" << std::endl; + exit(EXIT_FAILURE); + } + pf.close(); + } + else + { + std::cerr << "No pid file specified" << std::endl; + } + + exit(EXIT_SUCCESS); +} + +void detachDaemon() +{ + if (parent_pid) + { + kill(parent_pid, SIGUSR1); + } +} + + +void exitDaemon() +{ + if (parent_pid && parent_pid != getpid()) + { + kill(parent_pid, SIGTERM); + } +} + + +struct WatchDog +{ + ~WatchDog() + { + exitDaemon(); + } +}; + +WatchDog dog; diff --git a/src/shared/PosixDaemon.h b/src/shared/PosixDaemon.h new file mode 100644 index 000000000..26fb7adb6 --- /dev/null +++ b/src/shared/PosixDaemon.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2005-2011 MaNGOS + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "Common.h" +#include "Log.h" + +void startDaemon(uint32_t timeout = 10); +void stopDaemon(); +void detachDaemon(); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index a2a47e705..59a98a564 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "11499" + #define REVISION_NR "11500" #endif // __REVISION_NR_H__