Skip to content
Snippets Groups Projects
Daemon.hh 11.3 KiB
Newer Older
// $Id$
//
// Copyright (C) 2007 
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
// Kompetenzzentrum fuer NETwork research (NET)
//     Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

/** \file
    \brief Daemon public header */

#ifndef HH_Daemon_
#define HH_Daemon_ 1

// Custom includes
#include <boost/utility.hpp>

//#include "Daemon.mpp"
///////////////////////////////hh.p////////////////////////////////////////

namespace senf {

    /** \brief Daemon process

g0dil's avatar
g0dil committed
        senf::Daemon provides simple management for daemon processes. Specifically, the Daemon class
        implements
        \li <i>Safe startup.</i> If the startup fails, the foreground process which launches the
            daemon will terminate with an appropriate error exit code.
        \li <i>Straight forward application initialization.</i> The daemon process is forked before
            even initializing the application. The initialization procedure must not cater for a
            later fork().
        \li <i>Automatic pid file management.</i> The daemon will not be started, if a valid pid file is
            found. Stale pid files are automatically removed.
        \li <i>Console log management.</i> It is possible, to redirect standard output and error to
            one or two log files. Messages pertaining to application initialization will be written
            to both the console and the log file whereas later messages will be directed to the log
            file only.
        \li <i>Optional foreground execution.</i> The daemon may be started in the foreground for
            debugging purposes. In this case, the console log file(s) is/are automatically
            suppressed.
        
        Starting the daemon process proceeds along the following steps:
        \li The daemon is started by calling the daemon class instances start() member. This
            normally happens from the \c main() function generated by \ref SENF_DAEMON_MAIN().
        \li configure() is called. This (virtual) member configures the daemon manager by calling
            the Daemon class parameter members.
        \li The log files are opened, \c fork() is called and the pid file is checked and
            created. The parent (foreground) process keeps running overseeing the daemon process.
        \li main() is called. This virtual member may optionally be overridden in the derived
            class. Here we assume, main() is not overridden so the default implementation is used.
        \li main() calls init(). 
        \li after init() returns, main() calls detach().
        \li detach() signals successful startup to the parent process. The parent process terminates
            leaving the daemon process running in the background.
        \li main() calls run()
        \li If run() ever returns, the daemon process terminates.
        \li Whenever the process terminates normally (not necessarily successfully), the pid file is
            automatically removed.

        The parameter members are used from configure() to configure the daemon manager. See below
        for details. The \e default configure() implementation will scan the command line arguments
        to check for the following parameters:

        <table class="senf">

        <tr><td><tt>--no-daemon</tt></td><td>Run in foreground</td></tr>

        <tr><td><tt>--console-log=</tt><i>stdout</i>[<tt>,</tt><i>stderr</i>]</td><td>Set the
        console log file(s). If only \a stdout is specified (with no comma), the same log file
        configuration will be applied to the standard output and error stream. Otherwise each stream
        is assigned it's own log file. If either log file name is empty, the command will not change
        the log file of that stream, the default log file will be used. If the log file name is set
        to 'none', the log file will be disabled.</td></tr>

        <tr><td><tt>--pid-file=</tt><i>pidfile</i></td><td>Set pid file path</td></tr>

        </table>

        The default configure() implementation will use whatever parameters have been set beforehand
        as default values. These default values should be set in a derived class configure()
        implementation. After setting the default values, the configure() implementation may choose
        to call this default configure() implementation to scan for command line parmeters.  The
        default configure() implementation does \e not completely parse the command line
        arguments. It just checks, if any of above arguments are present and precesses them. Other
        arguments are completely ignored. The command line parameters should be completely processed
        within init().
        
      */
    class Daemon : boost::noncopyable
    {
    public:
        ///////////////////////////////////////////////////////////////////////////
        // Types
        
        /// Select standard stream to redirect
        enum StdStream { 
            StdOut  /** Standard output stream */
        ,   StdErr  /** Standard error stream */
        ,   Both    /** Both, standard output and error stream */
        }; 

        ///////////////////////////////////////////////////////////////////////////
        ///\name Structors and default members
        ///\{

        virtual ~Daemon();

        ///\}
        ///\name Parameters
        ///\{

        void daemonize(bool);           ///< Configure whether to run in fore- or background
        bool daemon();                  ///< \c true, if running as daemon

        void consoleLog(std::string const &, StdStream which = Both); 
                                        ///< Configure console log file
                                        /**< May be called multiple times to set the log file
                                             for stdout and stderr seperately. Any standard stream
                                             not assigned to a log file will be redirected to
                                             <tt>/dev/null</tt>. 

                                             When running in the foreground, the log files will be
                                             ignored. */

        void pidFile(std::string const &); ///< Configure pid file
g0dil's avatar
g0dil committed
                                        /**< If a pid file is configured it will be checked on
                                             daemon startup. If another running instance of the
                                             daemon is detected, starting the daemon will fail. */

        ///\}
        ///\name Auxiliary helpers
        ///\{

        void detach();                  ///< Detach into background now
                                        /**< This is \e not the same as forking. The process will
                                             already have forked into the background but until
                                             detach() is called (either automatically after init()
                                             returns or manually), the front end (foreground)
                                             process will wait for the background process to ensure
                                             successful startup. */

        int argc();                     ///< Access command line parameter count
        char const ** argv();           ///< Access command line parameters

g0dil's avatar
g0dil committed
        void fail(unsigned code=1);     ///< Terminate daemon with failure

        ///\}
        
        int start(int argc, char const ** argv); ///< Called from main() to launch daemon.
                                        /**< Normally not called directly but from the
                                             \ref SENF_DAEMON_MAIN macro. */

    protected:
        Daemon();

        virtual void configure();       ///< Called before forking to configure the daemon class
g0dil's avatar
g0dil committed
                                        /**< This default implementation will parser some command
                                             line parameters. See the class documentation above. */
#   ifdef DOXYGEN
    protected:
#   else
    private:
#   endif

        virtual void main();            ///< Called after forking to execute the main application
                                        /**< The default implementation will call init(), detach()
                                             and then run(). It is preferred to override init() and
                                             run() if possible. */
        virtual void init();            ///< Called to initialize the main application
                                        /**< While init() is running, the application still is
                                             connected to the controlling terminal. Error messages
                                             will be shown to the user.

                                             This member is only called, if the default main()
                                             implementation is not overridden. */
        virtual void run();             ///< Called to execute main application
                                        /**< Called after detaching from the controlling
                                             terminal.

                                             This member is only called, if the default main()
                                             implementation is not overridden. */
    private:

        void openLog();
        bool pidfileCreate();

        int argc_;
        char const ** argv_;

        bool daemonize_;
        std::string stdoutLog_;
        std::string stderrLog_;
        int stdout_;
        int stderr_;
        std::string pidfile_;

        bool detached_;
    };

    /** \brief Provide \c main() function

        This macro will provide a \c main() function to launch the daemon process defined in \a
        klass. \a klass must be a class derived from senf::Daemon.

        \ingroup process
     */
#   define SENF_DAEMON_MAIN(klass)                                                                \
        int main(int argc, char const ** argv)                                                    \
        {                                                                                         \
            klass instance;                                                                       \
            return instance.start(argc, argv);                                                    \
        }

}

///////////////////////////////hh.e////////////////////////////////////////
//#include "Daemon.cci"
//#include "Daemon.ct"
//#include "Daemon.cti"
#endif


// Local Variables:
// mode: c++
// fill-column: 100
// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
// End: