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