| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584 |
- //
- // ServerApplication.cpp
- //
- // $Id: //poco/Main/Util/src/ServerApplication.cpp#22 $
- //
- // Library: Util
- // Package: Application
- // Module: ServerApplication
- //
- // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
- // and Contributors.
- //
- // Permission is hereby granted, free of charge, to any person or organization
- // obtaining a copy of the software and accompanying documentation covered by
- // this license (the "Software") to use, reproduce, display, distribute,
- // execute, and transmit the Software, and to prepare derivative works of the
- // Software, and to permit third-parties to whom the Software is furnished to
- // do so, all subject to the following:
- //
- // The copyright notices in the Software and this entire statement, including
- // the above license grant, this restriction and the following disclaimer,
- // must be included in all copies of the Software, in whole or in part, and
- // all derivative works of the Software, unless such copies or derivative
- // works are solely in the form of machine-executable object code generated by
- // a source language processor.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
- // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
- // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
- // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- // DEALINGS IN THE SOFTWARE.
- //
- #include "Poco/Util/ServerApplication.h"
- #include "Poco/Util/Option.h"
- #include "Poco/Util/OptionSet.h"
- #include "Poco/Exception.h"
- #include "Poco/Process.h"
- #include "Poco/NumberFormatter.h"
- #include "Poco/NamedEvent.h"
- #include "Poco/Logger.h"
- #if defined(POCO_OS_FAMILY_UNIX)
- #include <stdlib.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <signal.h>
- #include <sys/stat.h>
- #elif defined(POCO_OS_FAMILY_WINDOWS)
- #include "Poco/Util/WinService.h"
- #include "Poco/UnWindows.h"
- #include <cstring>
- #endif
- #if defined(POCO_WIN32_UTF8)
- #include "Poco/UnicodeConverter.h"
- #endif
- using Poco::NamedEvent;
- using Poco::Process;
- using Poco::NumberFormatter;
- using Poco::Exception;
- using Poco::SystemException;
- namespace Poco {
- namespace Util {
- #if defined(POCO_OS_FAMILY_WINDOWS)
- Poco::Event ServerApplication::_terminated;
- SERVICE_STATUS ServerApplication::_serviceStatus;
- SERVICE_STATUS_HANDLE ServerApplication::_serviceStatusHandle = 0;
- #endif
- ServerApplication::ServerApplication()
- {
- #if defined(POCO_OS_FAMILY_WINDOWS)
- _action = SRV_RUN;
- std::memset(&_serviceStatus, 0, sizeof(_serviceStatus));
- #endif
- }
- ServerApplication::~ServerApplication()
- {
- }
- bool ServerApplication::isInteractive() const
- {
- bool runsInBackground = config().getBool("application.runAsDaemon", false) || config().getBool("application.runAsService", false);
- return !runsInBackground;
- }
- int ServerApplication::run()
- {
- return Application::run();
- }
- void ServerApplication::terminate()
- {
- Process::requestTermination(Process::id());
- }
- #if defined(POCO_OS_FAMILY_WINDOWS)
- //
- // Windows specific code
- //
- BOOL ServerApplication::ConsoleCtrlHandler(DWORD ctrlType)
- {
- switch (ctrlType)
- {
- case CTRL_C_EVENT:
- case CTRL_CLOSE_EVENT:
- case CTRL_BREAK_EVENT:
- terminate();
- return _terminated.tryWait(10000) ? TRUE : FALSE;
- default:
- return FALSE;
- }
- }
- void ServerApplication::ServiceControlHandler(DWORD control)
- {
- switch (control)
- {
- case SERVICE_CONTROL_STOP:
- case SERVICE_CONTROL_SHUTDOWN:
- terminate();
- _serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
- break;
- case SERVICE_CONTROL_INTERROGATE:
- break;
- }
- SetServiceStatus(_serviceStatusHandle, &_serviceStatus);
- }
- #if defined(POCO_WIN32_UTF8)
- void ServerApplication::ServiceMain(DWORD argc, LPWSTR* argv)
- #else
- void ServerApplication::ServiceMain(DWORD argc, LPTSTR* argv)
- #endif
- {
- ServerApplication& app = static_cast<ServerApplication&>(Application::instance());
- #if defined(POCO_WIN32_UTF8)
- _serviceStatusHandle = RegisterServiceCtrlHandlerW(L"", ServiceControlHandler);
- #else
- _serviceStatusHandle = RegisterServiceCtrlHandler("", ServiceControlHandler);
- #endif
- if (!_serviceStatusHandle)
- throw SystemException("cannot register service control handler");
- _serviceStatus.dwServiceType = SERVICE_WIN32;
- _serviceStatus.dwCurrentState = SERVICE_START_PENDING;
- _serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
- _serviceStatus.dwWin32ExitCode = 0;
- _serviceStatus.dwServiceSpecificExitCode = 0;
- _serviceStatus.dwCheckPoint = 0;
- _serviceStatus.dwWaitHint = 0;
- SetServiceStatus(_serviceStatusHandle, &_serviceStatus);
- try
- {
- #if defined(POCO_WIN32_UTF8)
- std::vector<std::string> args;
- for (DWORD i = 0; i < argc; ++i)
- {
- std::string arg;
- Poco::UnicodeConverter::toUTF8(argv[i], arg);
- args.push_back(arg);
- }
- app.init(args);
- #else
- app.init(argc, argv);
- #endif
- _serviceStatus.dwCurrentState = SERVICE_RUNNING;
- SetServiceStatus(_serviceStatusHandle, &_serviceStatus);
- int rc = app.run();
- _serviceStatus.dwWin32ExitCode = rc ? ERROR_SERVICE_SPECIFIC_ERROR : 0;
- _serviceStatus.dwServiceSpecificExitCode = rc;
- }
- catch (Exception& exc)
- {
- app.logger().log(exc);
- _serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
- _serviceStatus.dwServiceSpecificExitCode = EXIT_CONFIG;
- }
- catch (...)
- {
- app.logger().error("fatal error - aborting");
- _serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
- _serviceStatus.dwServiceSpecificExitCode = EXIT_SOFTWARE;
- }
- try
- {
- app.uninitialize();
- }
- catch (...)
- {
- }
- _serviceStatus.dwCurrentState = SERVICE_STOPPED;
- SetServiceStatus(_serviceStatusHandle, &_serviceStatus);
- }
- void ServerApplication::waitForTerminationRequest()
- {
- SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
- std::string evName("POCOTRM");
- evName.append(NumberFormatter::formatHex(Process::id(), 8));
- NamedEvent ev(evName);
- ev.wait();
- _terminated.set();
- }
- int ServerApplication::run(int argc, char** argv)
- {
- if (!hasConsole() && isService())
- {
- config().setBool("application.runAsService", true);
- return 0;
- }
- else
- {
- int rc = EXIT_OK;
- try
- {
- init(argc, argv);
- switch (_action)
- {
- case SRV_REGISTER:
- registerService();
- rc = EXIT_OK;
- break;
- case SRV_UNREGISTER:
- unregisterService();
- rc = EXIT_OK;
- break;
- default:
- rc = run();
- uninitialize();
- }
- }
- catch (Exception& exc)
- {
- logger().log(exc);
- rc = EXIT_SOFTWARE;
- }
- return rc;
- }
- }
- #if defined(POCO_WIN32_UTF8)
- int ServerApplication::run(int argc, wchar_t** argv)
- {
- if (!hasConsole() && isService())
- {
- config().setBool("application.runAsService", true);
- return 0;
- }
- else
- {
- int rc = EXIT_OK;
- try
- {
- init(argc, argv);
- switch (_action)
- {
- case SRV_REGISTER:
- registerService();
- rc = EXIT_OK;
- break;
- case SRV_UNREGISTER:
- unregisterService();
- rc = EXIT_OK;
- break;
- default:
- rc = run();
- uninitialize();
- }
- }
- catch (Exception& exc)
- {
- logger().log(exc);
- rc = EXIT_SOFTWARE;
- }
- return rc;
- }
- }
- #endif
- bool ServerApplication::isService()
- {
- #if defined(POCO_WIN32_UTF8)
- SERVICE_TABLE_ENTRYW svcDispatchTable[2];
- svcDispatchTable[0].lpServiceName = L"";
- svcDispatchTable[0].lpServiceProc = ServiceMain;
- svcDispatchTable[1].lpServiceName = NULL;
- svcDispatchTable[1].lpServiceProc = NULL;
- return StartServiceCtrlDispatcherW(svcDispatchTable) != 0;
- #else
- SERVICE_TABLE_ENTRY svcDispatchTable[2];
- svcDispatchTable[0].lpServiceName = "";
- svcDispatchTable[0].lpServiceProc = ServiceMain;
- svcDispatchTable[1].lpServiceName = NULL;
- svcDispatchTable[1].lpServiceProc = NULL;
- return StartServiceCtrlDispatcher(svcDispatchTable) != 0;
- #endif
- }
- bool ServerApplication::hasConsole()
- {
- HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
- return hStdOut != INVALID_HANDLE_VALUE && hStdOut != NULL;
- }
- void ServerApplication::registerService()
- {
- std::string name = config().getString("application.baseName");
- std::string path = config().getString("application.path");
-
- WinService service(name);
- if (_displayName.empty())
- service.registerService(path);
- else
- service.registerService(path, _displayName);
- logger().information("The application has been successfully registered as a service");
- }
- void ServerApplication::unregisterService()
- {
- std::string name = config().getString("application.baseName");
-
- WinService service(name);
- service.unregisterService();
- logger().information("The service has been successfully unregistered");
- }
- void ServerApplication::defineOptions(OptionSet& options)
- {
- Application::defineOptions(options);
- options.addOption(
- Option("registerService", "", "register application as a service")
- .required(false)
- .repeatable(false));
- options.addOption(
- Option("unregisterService", "", "unregister application as a service")
- .required(false)
- .repeatable(false));
- options.addOption(
- Option("displayName", "", "specify a display name for the service (only with /registerService)")
- .required(false)
- .repeatable(false)
- .argument("name"));
- }
- void ServerApplication::handleOption(const std::string& name, const std::string& value)
- {
- if (name == "registerService")
- _action = SRV_REGISTER;
- else if (name == "unregisterService")
- _action = SRV_UNREGISTER;
- else if (name == "displayName")
- _displayName = value;
- else
- Application::handleOption(name, value);
- }
- #elif defined(POCO_OS_FAMILY_UNIX)
- //
- // Unix specific code
- //
- void ServerApplication::waitForTerminationRequest()
- {
- sigset_t sset;
- sigemptyset(&sset);
- sigaddset(&sset, SIGINT);
- sigaddset(&sset, SIGQUIT);
- sigaddset(&sset, SIGTERM);
- sigprocmask(SIG_BLOCK, &sset, NULL);
- int sig;
- sigwait(&sset, &sig);
- }
- int ServerApplication::run(int argc, char** argv)
- {
- bool runAsDaemon = isDaemon(argc, argv);
- if (runAsDaemon)
- {
- beDaemon();
- }
- try
- {
- init(argc, argv);
- if (runAsDaemon)
- {
- chdir("/");
- }
- }
- catch (Exception& exc)
- {
- logger().log(exc);
- return EXIT_CONFIG;
- }
- int rc = run();
- try
- {
- uninitialize();
- }
- catch (Exception& exc)
- {
- logger().log(exc);
- rc = EXIT_CONFIG;
- }
- return rc;
- }
- bool ServerApplication::isDaemon(int argc, char** argv)
- {
- std::string option("--daemon");
- for (int i = 1; i < argc; ++i)
- {
- if (option == argv[i])
- return true;
- }
- return false;
- }
- void ServerApplication::beDaemon()
- {
- pid_t pid;
- if ((pid = fork()) < 0)
- throw SystemException("cannot fork daemon process");
- else if (pid != 0)
- exit(0);
-
- setsid();
- umask(0);
- close(0);
- close(1);
- close(2);
- }
- void ServerApplication::defineOptions(OptionSet& options)
- {
- Application::defineOptions(options);
- options.addOption(
- Option("daemon", "", "run application as a daemon")
- .required(false)
- .repeatable(false));
- }
- void ServerApplication::handleOption(const std::string& name, const std::string& value)
- {
- if (name == "daemon")
- {
- config().setBool("application.runAsDaemon", true);
- }
- else Application::handleOption(name, value);
- }
- #elif defined(POCO_OS_FAMILY_VMS)
- //
- // VMS specific code
- //
- namespace
- {
- static void handleSignal(int sig)
- {
- ServerApplication::terminate();
- }
- }
- void ServerApplication::waitForTerminationRequest()
- {
- struct sigaction handler;
- handler.sa_handler = handleSignal;
- handler.sa_flags = 0;
- sigemptyset(&handler.sa_mask);
- sigaction(SIGINT, &handler, NULL);
- sigaction(SIGQUIT, &handler, NULL);
- long ctrlY = LIB$M_CLI_CTRLY;
- unsigned short ioChan;
- $DESCRIPTOR(ttDsc, "TT:");
- lib$disable_ctrl(&ctrlY);
- sys$assign(&ttDsc, &ioChan, 0, 0);
- sys$qiow(0, ioChan, IO$_SETMODE | IO$M_CTRLYAST, 0, 0, 0, terminate, 0, 0, 0, 0, 0);
- sys$qiow(0, ioChan, IO$_SETMODE | IO$M_CTRLCAST, 0, 0, 0, terminate, 0, 0, 0, 0, 0);
- std::string evName("POCOTRM");
- evName.append(NumberFormatter::formatHex(Process::id(), 8));
- NamedEvent ev(evName);
- try
- {
- ev.wait();
- }
- catch (...)
- {
- // CTRL-C will cause an exception to be raised
- }
- sys$dassgn(ioChan);
- lib$enable_ctrl(&ctrlY);
- }
- int ServerApplication::run(int argc, char** argv)
- {
- try
- {
- init(argc, argv);
- }
- catch (Exception& exc)
- {
- logger().log(exc);
- return EXIT_CONFIG;
- }
- int rc = run();
- try
- {
- uninitialize();
- }
- catch (Exception& exc)
- {
- logger().log(exc);
- rc = EXIT_CONFIG;
- }
- return rc;
- }
- void ServerApplication::defineOptions(OptionSet& options)
- {
- Application::defineOptions(options);
- }
- void ServerApplication::handleOption(const std::string& name, const std::string& value)
- {
- Application::handleOption(name, value);
- }
- #endif
- } } // namespace Poco::Util
|