2
// ServerApplication.cpp
4
// $Id: //poco/1.2/Util/src/ServerApplication.cpp#2 $
7
// Package: Application
8
// Module: ServerApplication
10
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
13
// Permission is hereby granted, free of charge, to any person or organization
14
// obtaining a copy of the software and accompanying documentation covered by
15
// this license (the "Software") to use, reproduce, display, distribute,
16
// execute, and transmit the Software, and to prepare derivative works of the
17
// Software, and to permit third-parties to whom the Software is furnished to
18
// do so, all subject to the following:
20
// The copyright notices in the Software and this entire statement, including
21
// the above license grant, this restriction and the following disclaimer,
22
// must be included in all copies of the Software, in whole or in part, and
23
// all derivative works of the Software, unless such copies or derivative
24
// works are solely in the form of machine-executable object code generated by
25
// a source language processor.
27
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
30
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
31
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
32
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33
// DEALINGS IN THE SOFTWARE.
37
#include "Poco/Util/ServerApplication.h"
38
#include "Poco/Util/Option.h"
39
#include "Poco/Util/OptionSet.h"
40
#include "Poco/Exception.h"
41
#include "Poco/Process.h"
42
#include "Poco/NumberFormatter.h"
43
#include "Poco/NamedEvent.h"
44
#include "Poco/Logger.h"
45
#if defined(POCO_OS_FAMILY_UNIX)
51
#elif defined(POCO_OS_FAMILY_WINDOWS)
52
#include "Poco/Util/WinService.h"
56
#if defined(POCO_WIN32_UTF8)
57
#include "Poco/UnicodeConverter.h"
61
using Poco::NamedEvent;
63
using Poco::NumberFormatter;
64
using Poco::Exception;
65
using Poco::SystemException;
72
#if defined(POCO_OS_FAMILY_WINDOWS)
73
Poco::Event ServerApplication::_terminated;
74
SERVICE_STATUS ServerApplication::_serviceStatus;
75
SERVICE_STATUS_HANDLE ServerApplication::_serviceStatusHandle = 0;
79
ServerApplication::ServerApplication()
81
#if defined(POCO_OS_FAMILY_WINDOWS)
83
memset(&_serviceStatus, 0, sizeof(_serviceStatus));
88
ServerApplication::~ServerApplication()
93
bool ServerApplication::isInteractive() const
95
bool runsInBackground = config().getBool("application.runAsDaemon", false) || config().getBool("application.runAsService", false);
96
return !runsInBackground;
100
int ServerApplication::run()
102
return Application::run();
106
void ServerApplication::terminate()
108
Process::requestTermination(Process::id());
112
#if defined(POCO_OS_FAMILY_WINDOWS)
116
// Windows specific code
118
BOOL ServerApplication::ConsoleCtrlHandler(DWORD ctrlType)
123
case CTRL_CLOSE_EVENT:
124
case CTRL_BREAK_EVENT:
126
return _terminated.tryWait(10000) ? TRUE : FALSE;
133
void ServerApplication::ServiceControlHandler(DWORD control)
137
case SERVICE_CONTROL_STOP:
138
case SERVICE_CONTROL_SHUTDOWN:
140
_serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
142
case SERVICE_CONTROL_INTERROGATE:
145
SetServiceStatus(_serviceStatusHandle, &_serviceStatus);
149
void ServerApplication::ServiceMain(DWORD argc, LPTSTR* argv)
151
ServerApplication& app = static_cast<ServerApplication&>(Application::instance());
153
#if defined(POCO_WIN32_UTF8)
154
_serviceStatusHandle = RegisterServiceCtrlHandlerW(L"", ServiceControlHandler);
156
_serviceStatusHandle = RegisterServiceCtrlHandler("", ServiceControlHandler);
158
if (!_serviceStatusHandle)
159
throw SystemException("cannot register service control handler");
161
_serviceStatus.dwServiceType = SERVICE_WIN32;
162
_serviceStatus.dwCurrentState = SERVICE_START_PENDING;
163
_serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
164
_serviceStatus.dwWin32ExitCode = 0;
165
_serviceStatus.dwServiceSpecificExitCode = 0;
166
_serviceStatus.dwCheckPoint = 0;
167
_serviceStatus.dwWaitHint = 0;
168
SetServiceStatus(_serviceStatusHandle, &_serviceStatus);
172
#if defined(POCO_WIN32_UTF8)
173
std::vector<std::string> args;
174
for (DWORD i = 0; i < argc; ++i)
177
Poco::UnicodeConverter::toUTF8(argv[i], arg);
182
app.init(argc, argv);
184
_serviceStatus.dwCurrentState = SERVICE_RUNNING;
185
SetServiceStatus(_serviceStatusHandle, &_serviceStatus);
187
_serviceStatus.dwWin32ExitCode = rc ? ERROR_SERVICE_SPECIFIC_ERROR : 0;
188
_serviceStatus.dwServiceSpecificExitCode = rc;
190
catch (Exception& exc)
192
app.logger().log(exc);
193
_serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
194
_serviceStatus.dwServiceSpecificExitCode = EXIT_CONFIG;
198
app.logger().error("fatal error - aborting");
199
_serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
200
_serviceStatus.dwServiceSpecificExitCode = EXIT_SOFTWARE;
209
_serviceStatus.dwCurrentState = SERVICE_STOPPED;
210
SetServiceStatus(_serviceStatusHandle, &_serviceStatus);
214
void ServerApplication::waitForTerminationRequest()
216
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
217
std::string evName("POCOTRM");
218
evName.append(NumberFormatter::formatHex(Process::id(), 8));
219
NamedEvent ev(evName);
225
int ServerApplication::run(int argc, char** argv)
227
if (!hasConsole() && isService())
229
config().setBool("application.runAsService", true);
253
catch (Exception& exc)
263
#if defined(POCO_WIN32_UTF8)
264
int ServerApplication::run(int argc, wchar_t** argv)
266
if (!hasConsole() && isService())
268
config().setBool("application.runAsService", true);
292
catch (Exception& exc)
303
bool ServerApplication::isService()
305
SERVICE_TABLE_ENTRY svcDispatchTable[2];
306
#if defined(POCO_WIN32_UTF8)
307
svcDispatchTable[0].lpServiceName = L"";
309
svcDispatchTable[0].lpServiceName = "";
311
svcDispatchTable[0].lpServiceProc = ServiceMain;
312
svcDispatchTable[1].lpServiceName = NULL;
313
svcDispatchTable[1].lpServiceProc = NULL;
315
return StartServiceCtrlDispatcher(svcDispatchTable) != 0;
319
bool ServerApplication::hasConsole()
321
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
322
return hStdOut != INVALID_HANDLE_VALUE && hStdOut != NULL;
326
void ServerApplication::registerService()
328
std::string name = config().getString("application.baseName");
329
std::string path = config().getString("application.path");
331
WinService service(name);
332
if (_displayName.empty())
333
service.registerService(path);
335
service.registerService(path, _displayName);
336
logger().information("The application has been successfully registered as a service");
340
void ServerApplication::unregisterService()
342
std::string name = config().getString("application.baseName");
344
WinService service(name);
345
service.unregisterService();
346
logger().information("The service has been successfully unregistered");
350
void ServerApplication::defineOptions(OptionSet& options)
352
Application::defineOptions(options);
355
Option("registerService", "", "register application as a service")
360
Option("unregisterService", "", "unregister application as a service")
365
Option("displayName", "", "specify a display name for the service (only with /registerService)")
372
void ServerApplication::handleOption(const std::string& name, const std::string& value)
374
if (name == "registerService")
375
_action = SRV_REGISTER;
376
else if (name == "unregisterService")
377
_action = SRV_UNREGISTER;
378
else if (name == "displayName")
379
_displayName = value;
381
Application::handleOption(name, value);
385
#elif defined(POCO_OS_FAMILY_UNIX)
389
// Unix specific code
391
void ServerApplication::waitForTerminationRequest()
395
sigaddset(&sset, SIGINT);
396
sigaddset(&sset, SIGQUIT);
397
sigaddset(&sset, SIGTERM);
398
sigprocmask(SIG_BLOCK, &sset, NULL);
400
sigwait(&sset, &sig);
404
int ServerApplication::run(int argc, char** argv)
406
bool runAsDaemon = isDaemon(argc, argv);
419
catch (Exception& exc)
429
catch (Exception& exc)
438
bool ServerApplication::isDaemon(int argc, char** argv)
440
std::string option("--daemon");
441
for (int i = 1; i < argc; ++i)
443
if (option == argv[i])
450
void ServerApplication::beDaemon()
453
if ((pid = fork()) < 0)
454
throw SystemException("cannot fork daemon process");
466
void ServerApplication::defineOptions(OptionSet& options)
468
Application::defineOptions(options);
471
Option("daemon", "", "run application as a daemon")
477
void ServerApplication::handleOption(const std::string& name, const std::string& value)
479
if (name == "daemon")
481
config().setBool("application.runAsDaemon", true);
483
else Application::handleOption(name, value);
487
#elif defined(POCO_OS_FAMILY_VMS)
495
static void handleSignal(int sig)
497
ServerApplication::terminate();
502
void ServerApplication::waitForTerminationRequest()
504
struct sigaction handler;
505
handler.sa_handler = handleSignal;
506
handler.sa_flags = 0;
507
sigemptyset(&handler.sa_mask);
508
sigaction(SIGINT, &handler, NULL);
509
sigaction(SIGQUIT, &handler, NULL);
511
long ctrlY = LIB$M_CLI_CTRLY;
512
unsigned short ioChan;
513
$DESCRIPTOR(ttDsc, "TT:");
515
lib$disable_ctrl(&ctrlY);
516
sys$assign(&ttDsc, &ioChan, 0, 0);
517
sys$qiow(0, ioChan, IO$_SETMODE | IO$M_CTRLYAST, 0, 0, 0, terminate, 0, 0, 0, 0, 0);
518
sys$qiow(0, ioChan, IO$_SETMODE | IO$M_CTRLCAST, 0, 0, 0, terminate, 0, 0, 0, 0, 0);
520
std::string evName("POCOTRM");
521
evName.append(NumberFormatter::formatHex(Process::id(), 8));
522
NamedEvent ev(evName);
529
// CTRL-C will cause an exception to be raised
532
lib$enable_ctrl(&ctrlY);
536
int ServerApplication::run(int argc, char** argv)
542
catch (Exception& exc)
552
catch (Exception& exc)
561
void ServerApplication::defineOptions(OptionSet& options)
563
Application::defineOptions(options);
567
void ServerApplication::handleOption(const std::string& name, const std::string& value)
569
Application::handleOption(name, value);
576
} } // namespace Poco::Util