You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by sh...@apache.org on 2011/10/21 20:55:58 UTC
svn commit: r1187499 - in /qpid/trunk/qpid/cpp/src: ./ CMakeLists.txt
posix/QpiddBroker.cpp qpidd.cpp qpidd.h windows/QpiddBroker.cpp
windows/SCM.cpp windows/SCM.h
Author: shuston
Date: Fri Oct 21 18:55:57 2011
New Revision: 1187499
URL: http://svn.apache.org/viewvc?rev=1187499&view=rev
Log:
Add ability to run broker as a Windows service; resolves QPID-2519.
Added:
qpid/trunk/qpid/cpp/src/windows/SCM.cpp
- copied unchanged from r1079078, qpid/branches/QPID-2519/cpp/src/windows/SCM.cpp
qpid/trunk/qpid/cpp/src/windows/SCM.h
- copied unchanged from r1079078, qpid/branches/QPID-2519/cpp/src/windows/SCM.h
Modified:
qpid/trunk/qpid/cpp/src/ (props changed)
qpid/trunk/qpid/cpp/src/CMakeLists.txt (contents, props changed)
qpid/trunk/qpid/cpp/src/posix/QpiddBroker.cpp
qpid/trunk/qpid/cpp/src/qpidd.cpp
qpid/trunk/qpid/cpp/src/qpidd.h
qpid/trunk/qpid/cpp/src/windows/QpiddBroker.cpp
Propchange: qpid/trunk/qpid/cpp/src/
------------------------------------------------------------------------------
--- svn:mergeinfo (added)
+++ svn:mergeinfo Fri Oct 21 18:55:57 2011
@@ -0,0 +1,7 @@
+/qpid/branches/0.5.x-dev/qpid/cpp/src:892761,894875
+/qpid/branches/0.6-release-windows-installer/cpp/src:926803
+/qpid/branches/0.6-release-windows-installer/qpid/cpp/src:926803,927233
+/qpid/branches/QPID-2519/cpp/src:1072051-1079078
+/qpid/branches/java-network-refactor/qpid/cpp/src:805429-825319
+/qpid/branches/qpid-2935/qpid/cpp/src:1061302-1072333
+/qpid/branches/qpid-3346/qpid/cpp/src:1144319-1179855
Modified: qpid/trunk/qpid/cpp/src/CMakeLists.txt
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/CMakeLists.txt?rev=1187499&r1=1187498&r2=1187499&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/CMakeLists.txt (original)
+++ qpid/trunk/qpid/cpp/src/CMakeLists.txt Fri Oct 21 18:55:57 2011
@@ -665,6 +665,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL Windows)
set (qpidd_platform_SOURCES
windows/QpiddBroker.cpp
+ windows/SCM.cpp
)
set (qpidmessaging_platform_SOURCES
Propchange: qpid/trunk/qpid/cpp/src/CMakeLists.txt
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Oct 21 18:55:57 2011
@@ -1,6 +1,7 @@
/qpid/branches/0.5.x-dev/qpid/cpp/src/CMakeLists.txt:892761,894875
/qpid/branches/0.6-release-windows-installer/cpp/src/CMakeLists.txt:926803
/qpid/branches/0.6-release-windows-installer/qpid/cpp/src/CMakeLists.txt:926803,927233,932132
+/qpid/branches/QPID-2519/cpp/src/CMakeLists.txt:1072051-1079078
/qpid/branches/java-network-refactor/qpid/cpp/src/CMakeLists.txt:805429-825319
/qpid/branches/qpid-2935/qpid/cpp/src/CMakeLists.txt:1061302-1072333
/qpid/branches/qpid-3346/qpid/cpp/src/CMakeLists.txt:1144319-1179855
Modified: qpid/trunk/qpid/cpp/src/posix/QpiddBroker.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/posix/QpiddBroker.cpp?rev=1187499&r1=1187498&r2=1187499&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/posix/QpiddBroker.cpp (original)
+++ qpid/trunk/qpid/cpp/src/posix/QpiddBroker.cpp Fri Oct 21 18:55:57 2011
@@ -196,3 +196,8 @@ int QpiddBroker::execute (QpiddOptions *
}
return 0;
}
+
+int main(int argc, char* argv[])
+{
+ return run_broker(argc, argv);
+}
Modified: qpid/trunk/qpid/cpp/src/qpidd.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qpidd.cpp?rev=1187499&r1=1187498&r2=1187499&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/qpidd.cpp (original)
+++ qpid/trunk/qpid/cpp/src/qpidd.cpp Fri Oct 21 18:55:57 2011
@@ -31,7 +31,8 @@ using namespace std;
auto_ptr<QpiddOptions> options;
-int main(int argc, char* argv[])
+// Broker real entry; various system-invoked entrypoints call here.
+int run_broker(int argc, char *argv[], bool hidden)
{
try
{
@@ -43,6 +44,8 @@ int main(int argc, char* argv[])
// module-supplied options.
try {
bootOptions.parse (argc, argv, bootOptions.common.config, true);
+ if (hidden)
+ bootOptions.log.sinkOptions->detached();
qpid::log::Logger::instance().configure(bootOptions.log);
} catch (const std::exception& e) {
// Couldn't configure logging so write the message direct to stderr.
Modified: qpid/trunk/qpid/cpp/src/qpidd.h
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qpidd.h?rev=1187499&r1=1187498&r2=1187499&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/qpidd.h (original)
+++ qpid/trunk/qpid/cpp/src/qpidd.h Fri Oct 21 18:55:57 2011
@@ -67,4 +67,7 @@ public:
int execute (QpiddOptions *options);
};
+// Broker real entry; various system-invoked entrypoints call here.
+int run_broker(int argc, char *argv[], bool hidden = false);
+
#endif /*!QPID_H*/
Modified: qpid/trunk/qpid/cpp/src/windows/QpiddBroker.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/windows/QpiddBroker.cpp?rev=1187499&r1=1187498&r2=1187499&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/windows/QpiddBroker.cpp (original)
+++ qpid/trunk/qpid/cpp/src/windows/QpiddBroker.cpp Fri Oct 21 18:55:57 2011
@@ -19,17 +19,9 @@
*
*/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#else
-// These need to be made something sensible, like reading a value from
-// the registry. But for now, get things going with a local definition.
-namespace {
-const char *QPIDD_CONF_FILE = "qpid_broker.conf";
-const char *QPIDD_MODULE_DIR = ".";
-}
-#endif
+#include "config.h"
#include "qpidd.h"
+#include "SCM.h"
#include "qpid/Exception.h"
#include "qpid/Options.h"
#include "qpid/Plugin.h"
@@ -205,8 +197,56 @@ struct BrokerInfo {
DWORD pid;
};
+// Service-related items. Only involved when running the broker as a Windows
+// service.
+
+const std::string svcName = "qpidd";
+SERVICE_STATUS svcStatus;
+SERVICE_STATUS_HANDLE svcStatusHandle = 0;
+
+// This function is only called when the broker is run as a Windows
+// service. It receives control requests from Windows.
+VOID WINAPI SvcCtrlHandler(DWORD control)
+{
+ switch(control) {
+ case SERVICE_CONTROL_STOP:
+ svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
+ svcStatus.dwControlsAccepted = 0;
+ svcStatus.dwCheckPoint = 1;
+ svcStatus.dwWaitHint = 5000; // 5 secs.
+ ::SetServiceStatus(svcStatusHandle, &svcStatus);
+ CtrlHandler(CTRL_C_EVENT);
+ break;
+
+ case SERVICE_CONTROL_INTERROGATE:
+ break;
+
+ default:
+ break;
+ }
+}
+
+VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
+{
+ ::memset(&svcStatus, 0, sizeof(svcStatus));
+ svcStatusHandle = ::RegisterServiceCtrlHandler(svcName.c_str(),
+ SvcCtrlHandler);
+ svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ svcStatus.dwCheckPoint = 1;
+ svcStatus.dwWaitHint = 10000; // 10 secs.
+ svcStatus.dwCurrentState = SERVICE_START_PENDING;
+ ::SetServiceStatus(svcStatusHandle, &svcStatus);
+ // QpiddBroker class resets state to running.
+ svcStatus.dwWin32ExitCode = run_broker(argc, argv, true);
+ svcStatus.dwCurrentState = SERVICE_STOPPED;
+ svcStatus.dwCheckPoint = 0;
+ svcStatus.dwWaitHint = 0;
+ ::SetServiceStatus(svcStatusHandle, &svcStatus);
}
+} // namespace
+
+
struct ProcessControlOptions : public qpid::Options {
bool quit;
bool check;
@@ -225,9 +265,49 @@ struct ProcessControlOptions : public qp
}
};
+struct ServiceOptions : public qpid::Options {
+ bool install;
+ bool start;
+ bool stop;
+ bool uninstall;
+ bool daemon;
+ std::string startType;
+ std::string startArgs;
+ std::string account;
+ std::string password;
+ std::string depends;
+
+ ServiceOptions()
+ : qpid::Options("Service options"),
+ install(false),
+ start(false),
+ stop(false),
+ uninstall(false),
+ daemon(false),
+ startType("demand"),
+ startArgs(""),
+ account("NT AUTHORITY\\LocalService"),
+ password(""),
+ depends("")
+ {
+ addOptions()
+ ("install", qpid::optValue(install), "Install as service")
+ ("start-type", qpid::optValue(startType, "auto|demand|disabled"), "Service start type\nApplied at install time only.")
+ ("arguments", qpid::optValue(startArgs, "COMMAND LINE ARGS"), "Arguments to pass when service auto-starts")
+ ("account", qpid::optValue(account, "(LocalService)"), "Account to run as, default is LocalService\nApplied at install time only.")
+ ("password", qpid::optValue(password, "PASSWORD"), "Account password, if needed\nApplied at install time only.")
+ ("depends", qpid::optValue(depends, "(comma delimited list)"), "Names of services that must start before this service\nApplied at install time only.")
+ ("start", qpid::optValue(start), "Start the service.")
+ ("stop", qpid::optValue(stop), "Stop the service.")
+ ("uninstall", qpid::optValue(uninstall), "Uninstall the service.");
+ }
+};
+
struct QpiddWindowsOptions : public QpiddOptionsPrivate {
ProcessControlOptions control;
+ ServiceOptions service;
QpiddWindowsOptions(QpiddOptions *parent) : QpiddOptionsPrivate(parent) {
+ parent->add(service);
parent->add(control);
}
};
@@ -253,12 +333,63 @@ void QpiddOptions::usage() const {
}
int QpiddBroker::execute (QpiddOptions *options) {
+
+ // If running as a service, bump the status checkpoint to let SCM know
+ // we're still making progress.
+ if (svcStatusHandle != 0) {
+ svcStatus.dwCheckPoint++;
+ ::SetServiceStatus(svcStatusHandle, &svcStatus);
+ }
+
// Options that affect a running daemon.
QpiddWindowsOptions *myOptions =
- reinterpret_cast<QpiddWindowsOptions *>(options->platform.get());
+ reinterpret_cast<QpiddWindowsOptions *>(options->platform.get());
if (myOptions == 0)
throw qpid::Exception("Internal error obtaining platform options");
+ if (myOptions->service.install) {
+ // Handle start type
+ DWORD startType;
+ if (myOptions->service.startType.compare("demand") == 0)
+ startType = SERVICE_DEMAND_START;
+ else if (myOptions->service.startType.compare("auto") == 0)
+ startType = SERVICE_AUTO_START;
+ else if (myOptions->service.startType.compare("disabled") == 0)
+ startType = SERVICE_DISABLED;
+ else if (!myOptions->service.startType.empty())
+ throw qpid::Exception("Invalid service start type: " +
+ myOptions->service.startType);
+
+ // Install service and exit
+ qpid::windows::SCM manager;
+ manager.install(svcName,
+ "Apache Qpid Message Broker",
+ myOptions->service.startArgs,
+ startType,
+ myOptions->service.account,
+ myOptions->service.password,
+ myOptions->service.depends);
+ return 0;
+ }
+
+ if (myOptions->service.start) {
+ qpid::windows::SCM manager;
+ manager.start(svcName);
+ return 0;
+ }
+
+ if (myOptions->service.stop) {
+ qpid::windows::SCM manager;
+ manager.stop(svcName);
+ return 0;
+ }
+
+ if (myOptions->service.uninstall) {
+ qpid::windows::SCM manager;
+ manager.uninstall(svcName);
+ return 0;
+ }
+
if (myOptions->control.check || myOptions->control.quit) {
// Relies on port number being set via --port or QPID_PORT env variable.
NamedSharedMemory<BrokerInfo> info(brokerInfoName(options->broker.port));
@@ -301,10 +432,41 @@ int QpiddBroker::execute (QpiddOptions *
::SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
brokerPtr->accept();
std::cout << options->broker.port << std::endl;
+
+ // If running as a service, tell SCM we're up. There's still a chance
+ // that store recovery will drag out the time before the broker actually
+ // responds to requests, but integrating that mechanism with the SCM
+ // updating is probably more work than it's worth.
+ if (svcStatusHandle != 0) {
+ svcStatus.dwCheckPoint = 0;
+ svcStatus.dwWaitHint = 0;
+ svcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+ svcStatus.dwCurrentState = SERVICE_RUNNING;
+ ::SetServiceStatus(svcStatusHandle, &svcStatus);
+ }
+
brokerPtr->run();
waitShut.signal(); // In case we shut down some other way
waitThr.join();
+ return 0;
+}
- // CloseHandle(h);
+
+int main(int argc, char* argv[])
+{
+ // If started as a service, notify the SCM we're up. Else just run.
+ // If as a service, StartServiceControlDispatcher doesn't return until
+ // the service is stopped.
+ SERVICE_TABLE_ENTRY dispatchTable[] =
+ {
+ { "", (LPSERVICE_MAIN_FUNCTION)ServiceMain },
+ { NULL, NULL }
+ };
+ if (!StartServiceCtrlDispatcher(dispatchTable)) {
+ DWORD err = ::GetLastError();
+ if (err == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) // Run as console
+ return run_broker(argc, argv);
+ throw QPID_WINDOWS_ERROR(err);
+ }
return 0;
}
---------------------------------------------------------------------
Apache Qpid - AMQP Messaging Implementation
Project: http://qpid.apache.org
Use/Interact: mailto:commits-subscribe@qpid.apache.org