Author: aconway
Date: Mon Apr 30 11:08:17 2007
New Revision: 533819
URL: http://svn.apache.org/viewvc?view=rev&rev=533819
Log:
* README: added new dependency, libdaemon.
* qpidc.spec.in: libdaemon dependencies.
* broker/Daemon.h|cpp: Daemon and pid file management, wrapper for libdaemon.
* qpidd.cpp modifid flags
-d [ --daemon ] - waits till deamon is listening before returning.
* qpidd.cpp: new flags
-q [ --quit ] Stop the running daemon politely.
-k [ --kill ] Kill the running daemon harshly.
-c [ --check ] If daemon is running return 0.
--wait SECONDS (=10) Maximum wait for daemon response.
--ppid Print daemon pid to stdout
* tests/dameon_test: Test daemon startup, shutdown.
* deleted tests/broker: obsolete script.
Added:
incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp (with props)
incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h (with props)
incubator/qpid/branches/M2/cpp/tests/daemon_test (with props)
Removed:
incubator/qpid/branches/M2/cpp/tests/broker
Modified:
incubator/qpid/branches/M2/cpp/README
incubator/qpid/branches/M2/cpp/lib/broker/Makefile.am
incubator/qpid/branches/M2/cpp/qpidc.spec.in
incubator/qpid/branches/M2/cpp/src/qpidd.cpp
incubator/qpid/branches/M2/cpp/tests/Makefile.am
Modified: incubator/qpid/branches/M2/cpp/README
URL:
http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/README?view=diff&rev=533819&r1=533818&r2=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/README (original)
+++ incubator/qpid/branches/M2/cpp/README Mon Apr 30 11:08:17 2007
@@ -33,7 +33,7 @@
* apr <http://apr.apache.org> (1.2.7)
* boost <http://www.boost.org> (1.33.1)
* cppunit <http://cppunit.sourceforge.net> (1.11.4)
-
+ * libdaemon <http://www.stud.uni-hamburg.de/users/lennart/projects/libdaemon>
(0.10)
Using tools:
* boost-jam <http://boost.sourceforge.net/> (3.1.13)
Added: incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp
URL:
http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp?view=auto&rev=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp (added)
+++ incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp Mon Apr 30 11:08:17
2007
@@ -0,0 +1,144 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "QpidError.h"
+#include "Daemon.h"
+#include <libdaemon/daemon.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/operations.hpp>
+
+namespace qpid {
+namespace broker {
+
+using namespace std;
+
+string Daemon::pidFile;
+string Daemon::name;
+
+string Daemon::nameFromArgv0(const char* argv0) {
+ return string(daemon_ident_from_argv0(const_cast<char*>(argv0)));
+}
+
+const char* Daemon::getPidFile() {
+ if (pidFile.empty()) {
+ const char* home=getenv("HOME");
+ if (!home)
+ throw(Exception("$HOME is not set, cant create $HOME/.qpidd."));
+ using namespace boost::filesystem;
+ path dir = path(home,native) / path(".qpidd", native);
+ create_directory(dir);
+ dir /= name;
+ pidFile = dir.string();
+ }
+ return pidFile.c_str();
+}
+
+Daemon::Daemon(const string& name_, int secs) : timeout(secs)
+{
+ name = name_;
+ daemon_pid_file_ident = daemon_log_ident = name.c_str();
+ if (getuid() != 0) {
+ // For normal users put pid file under $HOME/.qpid
+ daemon_pid_file_proc = getPidFile;
+ }
+ // For root use the libdaemon default: /var/run.
+}
+
+Daemon::~Daemon() {
+ if (isChild())
+ daemon_pid_file_remove();
+}
+
+class Daemon::Retval {
+ public:
+ Retval();
+ ~Retval();
+ int send(int s);
+ int wait(int timeout);
+ private:
+ bool completed;
+};
+
+pid_t Daemon::fork() {
+ retval.reset(new Retval());
+ pid = daemon_fork();
+ if (pid < 0)
+ throw Exception("Failed to fork daemon: "+strError(errno));
+ else if (pid > 0) {
+ int ret = retval->wait(timeout); // parent, wait for child.
+ if (ret != 0) {
+ string err;
+ if (ret > 0)
+ err = strError(ret);
+ else if (ret == -1)
+ err= strError(errno);
+ else
+ err= "unknown error";
+ throw Exception("Deamon startup failed: "+err);
+ }
+ }
+ else if (pid == 0) { // child.
+ // TODO aconway 2007-04-26: Should log failures.
+ if (daemon_pid_file_create())
+ failed();
+ }
+ return pid;
+}
+
+void Daemon::notify(int i) {
+ assert(retval);
+ if (retval->send(i))
+ throw Exception("Failed to notify parent: "+strError(errno));
+}
+
+void Daemon::ready() { notify(0); }
+
+// NB: Not -1, confused with failure of fork() on the parent side.
+void Daemon::failed() { notify(errno? errno:-2); }
+
+void Daemon::quit() {
+ if (daemon_pid_file_kill_wait(SIGINT, timeout))
+ throw Exception("Failed to stop daemon: " + strError(errno));
+}
+
+void Daemon::kill() {
+ if (daemon_pid_file_kill_wait(SIGKILL, timeout) < 0)
+ throw Exception("Failed to stop daemon: " + strError(errno));
+}
+
+pid_t Daemon::check() {
+ return daemon_pid_file_is_running();
+}
+
+Daemon::Retval::Retval() : completed(false) {
+ daemon_retval_init();
+}
+Daemon::Retval::~Retval() {
+ if (!completed) daemon_retval_done();
+}
+int Daemon::Retval::send(int s) {
+ return daemon_retval_send(s);
+}
+int Daemon::Retval::wait(int timeout) {
+ return daemon_retval_wait(timeout);
+}
+
+}} // namespace qpid::broker
Propchange: incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/qpid/branches/M2/cpp/lib/broker/Daemon.cpp
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h
URL:
http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h?view=auto&rev=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h (added)
+++ incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h Mon Apr 30 11:08:17 2007
@@ -0,0 +1,91 @@
+#ifndef _broker_Daemon_h
+#define _broker_Daemon_h
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string>
+#include <boost/scoped_ptr.hpp>
+
+namespace qpid {
+namespace broker {
+
+/**
+ * Tools for forking and managing a daemon process.
+ * NB: Only one Daemon instance is allowed in a process.
+ */
+class Daemon
+{
+ public:
+
+ /** Extract the daemon's name from argv[0] */
+ static std::string nameFromArgv0(const char* argv0);
+
+ /**
+ * Creating a Daemon instance forks a daemon process.
+ [EMAIL PROTECTED] name used to create pid files etc.
+ [EMAIL PROTECTED] timeout in seconds for all operations that wait.
+ */
+ Daemon(const std::string& name, int timeout);
+
+ ~Daemon();
+
+ /** Fork the daemon, wait till it signals readiness */
+ pid_t fork();
+
+ /** Child only, send ready signal so parent fork() will return. */
+ void ready();
+
+ /** Child only, send failed signal so parent fork() will throw. */
+ void failed();
+
+ /** Kill the daemon with SIGINT. */
+ void quit();
+
+ /** Kill the daemon with SIGKILL. */
+ void kill();
+
+ /** Check daemon is running, throw exception if not */
+ pid_t check();
+
+ bool isParent() { return pid > 0; }
+
+ bool isChild() { return pid == 0; }
+
+ std::string getName() const { return name; }
+
+ pid_t getPid() const {return pid; }
+
+ private:
+ class Retval;
+
+ void notify(int);
+
+ static std::string name;
+ static std::string pidFile;
+ static const char* getPidFile();
+ boost::scoped_ptr<Retval> retval;
+ pid_t pid;
+ int timeout;
+};
+
+}} // namespace qpid::broker
+
+
+
+#endif /*!_broker_Daemon_h*/
Propchange: incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: incubator/qpid/branches/M2/cpp/lib/broker/Daemon.h
------------------------------------------------------------------------------
svn:keywords = Rev Date
Modified: incubator/qpid/branches/M2/cpp/lib/broker/Makefile.am
URL:
http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/lib/broker/Makefile.am?view=diff&rev=533819&r1=533818&r2=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/lib/broker/Makefile.am (original)
+++ incubator/qpid/branches/M2/cpp/lib/broker/Makefile.am Mon Apr 30 11:08:17
2007
@@ -7,7 +7,11 @@
$(APR_CXXFLAGS)
lib_LTLIBRARIES = libqpidbroker.la
-libqpidbroker_la_LIBADD = ../common/libqpidcommon.la
+libqpidbroker_la_LIBADD = \
+ ../common/libqpidcommon.la \
+ -ldaemon \
+ -lboost_filesystem
+
libqpidbroker_la_LDFLAGS = -version-info $(LIBTOOL_VERSION_INFO_ARG)
libqpidbroker_la_SOURCES = \
AccumulatedAck.cpp \
@@ -27,6 +31,8 @@
ConnectionToken.h \
Consumer.h \
Content.h \
+ Daemon.cpp \
+ Daemon.h \
DeletingTxOp.cpp \
DeletingTxOp.h \
Deliverable.h \
Modified: incubator/qpid/branches/M2/cpp/qpidc.spec.in
URL:
http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/qpidc.spec.in?view=diff&rev=533819&r1=533818&r2=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/qpidc.spec.in (original)
+++ incubator/qpid/branches/M2/cpp/qpidc.spec.in Mon Apr 30 11:08:17 2007
@@ -13,17 +13,19 @@
Source0: http://rhm.et.redhat.com/download/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-BuildRequires: libtool
+BuildRequires: apr-devel
BuildRequires: boost-devel
BuildRequires: cppunit-devel
BuildRequires: doxygen
+BuildRequires: e2fsprogs-devel
BuildRequires: graphviz
BuildRequires: help2man
+BuildRequires: libdaemon-devel
+BuildRequires: libtool
BuildRequires: pkgconfig
-BuildRequires: e2fsprogs-devel
-BuildRequires: apr-devel
Requires: boost
+Requires: libdaemon
Requires(post):/sbin/chkconfig
Requires(preun):/sbin/chkconfig
Modified: incubator/qpid/branches/M2/cpp/src/qpidd.cpp
URL:
http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/src/qpidd.cpp?view=diff&rev=533819&r1=533818&r2=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/src/qpidd.cpp (original)
+++ incubator/qpid/branches/M2/cpp/src/qpidd.cpp Mon Apr 30 11:08:17 2007
@@ -19,35 +19,58 @@
*
*/
#include <Broker.h>
-#include <signal.h>
#include <iostream>
#include <memory>
#include <config.h>
-#include <unistd.h>
#include <fstream>
+#include <signal.h>
+#include <Daemon.h>
+#include <boost/format.hpp>
+using boost::format;
using namespace qpid;
using namespace qpid::broker;
using namespace qpid::sys;
using namespace std;
+Broker::shared_ptr brokerPtr;
+
+void handle_signal(int /*signal*/){
+ std::cerr << "Shutting down..." << std::endl;
+ brokerPtr->shutdown();
+}
+
+
/** Command line options */
struct QpiddOptions : public Broker::Options
{
bool help;
bool version;
bool daemon;
+ bool quit;
+ bool kill;
+ bool check;
+ bool ppid;
+ int wait;
string config;
po::options_description desc;
QpiddOptions() :
help(false), version(false), daemon(false),
+ quit(false), kill(false), check(false), ppid(false), wait(10),
config("/etc/qpidd.conf"),
desc("Options")
{
using namespace po;
desc.add_options()
- ("daemon,d", optValue(daemon), "Run as a daemon");
+ ("daemon,d", optValue(daemon), "Run as a daemon.")
+ ("quit,q", optValue(quit), "Stop the running daemon politely.")
+ ("kill,k", optValue(kill), "Kill the running daemon harshly.")
+ ("check,c", optValue(check), "If daemon is running return 0.")
+ ("wait", optValue(wait, "SECONDS"),
+ "Maximum wait for daemon response.")
+ ("ppid", optValue(ppid), "Print daemon pid to stdout" );
+ po::options_description brokerOpts;
Broker::Options::addTo(desc);
desc.add_options()
("config", optValue(config, "FILE"), "Configuation file")
@@ -87,43 +110,80 @@
config.usage(out); return out;
}
-Broker::shared_ptr brokerPtr;
-
-void handle_signal(int /*signal*/){
- if (brokerPtr) {
- cerr << "Shutting down..." << endl;
- brokerPtr->shutdown();
- }
-}
-
int main(int argc, char* argv[])
{
QpiddOptions config;
try {
config.parse(argc, argv);
+ string name=(format("%s.%d")
+ % Daemon::nameFromArgv0(argv[0])
+ % (config.port)).str();
+ // Spelled 'demon' to avoid clash with daemon.h function.
+ Daemon demon(name, config.wait);
+
+ // Options that just print information.
if(config.help) {
config.usage(cout);
+ return 0;
}
- else if (config.version) {
+ if (config.version) {
cout << "qpidd (" << PACKAGE_NAME << ") version "
<< PACKAGE_VERSION << endl;
+ return 0;
}
- else {
- brokerPtr=Broker::create(config);
- signal(SIGINT, handle_signal);
- if (config.daemon) {
- if (daemon(0, 0) < 0) // daemon(nochdir, noclose)
- throw QPID_ERROR(
- INTERNAL_ERROR,
- "Failed to detach as daemon: "+ strError(errno));
+
+ // Options that affect an already running daemon.
+ if (config.quit || config.kill || config.check) {
+ pid_t pid = demon.check();
+ if (config.ppid && pid > 0)
+ cout << pid << endl;
+ if (config.kill)
+ demon.kill();
+ else if (config.quit)
+ demon.quit();
+ if (config.check && pid <= 0)
+ return 1;
+ return 0;
+ }
+
+ // Starting the broker:
+ signal(SIGINT, handle_signal);
+ if (config.daemon) {
+ pid_t pid = demon.fork();
+ if (pid == 0) { // Child
+ try {
+ brokerPtr=Broker::create(config);
+ demon.ready(); // Notify parent we're ready.
+ brokerPtr->run();
+ } catch (const exception& e) {
+ // TODO aconway 2007-04-26: Log this, cerr is lost.
+ cerr << "Broker daemon failed: " << e.what() << endl;
+ demon.failed(); // Notify parent we failed.
+ return 1;
+ }
+ }
+ else if (pid > 0) { // Parent
+ if (config.ppid)
+ cout << pid << endl;
+ return 0;
}
- brokerPtr->run();
+ else { // pid < 0
+ throw Exception("fork failed"+strError(errno));
+ }
+ } // Non-daemon broker.
+ else {
+ brokerPtr = Broker::create(config);
+ brokerPtr->run();
}
return 0;
}
- catch(const exception& e) {
+ catch(const po::error& e) {
+ // Command line parsing error.
cerr << "Error: " << e.what() << endl
<< "Type 'qpidd --help' for usage." << endl;
+ }
+ catch(const exception& e) {
+ cerr << "Error: " << e.what() << endl;
}
return 1;
}
Modified: incubator/qpid/branches/M2/cpp/tests/Makefile.am
URL:
http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/tests/Makefile.am?view=diff&rev=533819&r1=533818&r2=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/tests/Makefile.am (original)
+++ incubator/qpid/branches/M2/cpp/tests/Makefile.am Mon Apr 30 11:08:17 2007
@@ -71,10 +71,10 @@
TESTS_ENVIRONMENT = \
VALGRIND=$(VALGRIND) \
abs_builddir='$(abs_builddir)' \
- PATH="$(abs_builddir)/../src$(PATH_SEPARATOR)$$PATH" \
+
PATH="$(abs_srcdir)$(PATH_SEPARATOR)$(abs_builddir)/../src$(PATH_SEPARATOR)$$PATH"
\
abs_srcdir='$(abs_srcdir)'
-TESTS = run-unit-tests run-python-tests
+TESTS = run-unit-tests run-python-tests daemon_test
EXTRA_DIST += $(TESTS)
CLEANFILES=qpidd.log
Added: incubator/qpid/branches/M2/cpp/tests/daemon_test
URL:
http://svn.apache.org/viewvc/incubator/qpid/branches/M2/cpp/tests/daemon_test?view=auto&rev=533819
==============================================================================
--- incubator/qpid/branches/M2/cpp/tests/daemon_test (added)
+++ incubator/qpid/branches/M2/cpp/tests/daemon_test Mon Apr 30 11:08:17 2007
@@ -0,0 +1,22 @@
+#!/bin/sh
+# Without arguments run all daemon tests, exit status is number of failures.
+# With arguments run just the test named by $1.
+#
+
+TEMP=`mktemp`
+trap 'rm -f $TEMP' 0
+
+fail() { echo FAIL: $0:$* 1>&2; exit 1; }
+
+# Start and stop daemon.
+PID=`qpidd --check --ppid` && fail $LINENO: qpidd already running $PID
+qpidd -d || $LINENO: qpidd -d failed
+qpidd --check || fail $LINENO: qpidd --check says qpidd didnt start
+client_test > $TEMP || fail $LINENO: client_test: `cat $TEMP`
+qpidd -q || fail $LINENO: qpidd -q failed
+qpidd -d || fail $LINENO: restart after quit failed.
+qpidd -k || fail $LINENO: qpidd -k failed
+# Supress expected message re. cleanup of old PID file.
+PID=`qpidd --check --ppid 2>/dev/null` && fail $LINENO: $PID still running
after kill.
+
+true
Propchange: incubator/qpid/branches/M2/cpp/tests/daemon_test
------------------------------------------------------------------------------
svn:executable = *