XmlRpcDaemon.cxx

Go to the documentation of this file.
00001 /*------------------------------------------------------------------------------
00002  
00003     Copyright (c) 2004 Media Development Loan Fund
00004   
00005     This file is part of the Campcaster project.
00006     https://www.campware.org/
00007     To report bugs, send an e-mail to [email protected]
00008   
00009     Campcaster is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013    
00014     Campcaster is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017     GNU General Public License for more details.
00018   
00019     You should have received a copy of the GNU General Public License
00020     along with Campcaster; if not, write to the Free Software
00021     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022   
00023   
00024     Author   : $Author: paul $
00025     Version  : $Revision: 2698 $
00026     Location : $URL: svn://code.campware.org/campcaster/trunk/campcaster/src/products/scheduler/src/XmlRpcDaemon.cxx $
00027  
00028 ------------------------------------------------------------------------------*/
00029 
00030 /* ============================================================ include files */
00031 
00032 #ifdef HAVE_CONFIG_H
00033  #include "configure.h"
00034 #endif
00035  
00036 #if HAVE_STDIO_H
00037  #include <stdio.h>
00038 #else
00039  #error "Need stdio.h"
00040  #endif
00041  
00042 #if HAVE_UNISTD_H
00043  #include <unistd.h>
00044 #else
00045  #error "Need unistd.h"
00046  #endif
00047  
00048 #if HAVE_FCNTL_H
00049  #include <fcntl.h>
00050 #else
00051  #error "Need fcntl.h"
00052  #endif
00053  
00054 #if HAVE_SIGNAL_H
00055  #include <signal.h>
00056 #else
00057  #error "Need signal.h"
00058  #endif
00059  
00060 #if HAVE_SYS_STAT_H
00061  #include <sys/stat.h>
00062 #else
00063  #error "Need sys/stat.h"
00064  #endif
00065  
00066 
00067 #include <iostream>
00068 #include <sstream>
00069 #include <fstream>
00070 #include <cstdio>
00071 
00072 #include "SignalDispatcher.h"
00073 #include "XmlRpcDaemonShutdownSignalHandler.h"
00074 #include "XmlRpcDaemon.h"
00075 
00076 
00077 using namespace LiveSupport::Scheduler;
00078 
00079 /* ===================================================  local data structures */
00080 
00081 
00082 /* ================================================  local constants & macros */
00083 
00084 /*------------------------------------------------------------------------------
00085  *  The name of the config element for this class
00086  *----------------------------------------------------------------------------*/
00087 const std::string XmlRpcDaemon::configElementNameStr =
00088                                                         "xmlRpcDaemon";
00089 
00093 static const std::string confXmlRpcHostAttr = "xmlRpcHost";
00094 
00098 static const std::string confXmlRpcPortAttr = "xmlRpcPort";
00099 
00103 static const std::string confPidFileNameAttr = "pidFileName";
00104 
00108 static const mode_t uMask = 022;
00109 
00110 
00111 /* ===============================================  local function prototypes */
00112 
00113 
00114 /* =============================================================  module code */
00115 
00116 /*------------------------------------------------------------------------------
00117  *  Configure the Scheder daemon according to an XML element
00118  *----------------------------------------------------------------------------*/
00119 void
00120 XmlRpcDaemon :: configureXmlRpcDaemon(
00121                         const xmlpp::Element   & element)
00122                                                 throw (std::invalid_argument,
00123                                                        std::logic_error)
00124 {
00125     if (configured) {
00126         throw std::logic_error("already configured");
00127     }
00128 
00129     const xmlpp::Attribute    * attribute = 0;
00130     std::stringstream           strStr;
00131 
00132     if (element.get_name() != configElementNameStr) {
00133         std::string eMsg = "Bad configuration element ";
00134         eMsg += element.get_name();
00135         throw std::invalid_argument(eMsg);
00136     }
00137 
00138     if (!(attribute = element.get_attribute(confXmlRpcHostAttr))) {
00139         std::string eMsg = "Missing attribute ";
00140         eMsg += confXmlRpcHostAttr;
00141         throw std::invalid_argument(eMsg);
00142     }
00143     xmlRpcHost = attribute->get_value();
00144 
00145     if (!(attribute = element.get_attribute(confXmlRpcPortAttr))) {
00146         std::string eMsg = "Missing attribute ";
00147         eMsg += confXmlRpcPortAttr;
00148         throw std::invalid_argument(eMsg);
00149     }
00150     strStr.str(attribute->get_value());
00151     strStr >> xmlRpcPort;
00152 
00153     if (!(attribute = element.get_attribute(confPidFileNameAttr))) {
00154         std::string eMsg = "Missing attribute ";
00155         eMsg += confPidFileNameAttr;
00156         throw std::invalid_argument(eMsg);
00157     }
00158     pidFileName = attribute->get_value();
00159 
00160     configured = true;
00161 }
00162 
00163 
00164 /*------------------------------------------------------------------------------
00165  *  Do all the necessary work of becoming a daemon.
00166  *  See http://www.enderunix.org/docs/eng/daemon.php and
00167  *  http://www.linuxprofilm.com/articles/linux-daemon-howto.html
00168  *  for hints.
00169  *----------------------------------------------------------------------------*/
00170 bool
00171 XmlRpcDaemon :: daemonize(void)                  throw (std::runtime_error)
00172 {
00173     int     i;
00174 
00175     if (getppid() == 1) {
00176         // we're already a daemon
00177         return true;
00178     }
00179 
00180     i = fork();
00181     if (i < 0) {
00182         throw std::runtime_error("fork error");
00183     } else if (i > 0) {
00184         // this is the parent, simply return
00185         return false;
00186     }
00187     // for twice, so that we're totally detached from our ancestor
00188     i = fork();
00189     if (i < 0) {
00190         throw std::runtime_error("fork error");
00191     } else if (i > 0) {
00192         // this is the parent, simply return
00193         return false;
00194     }
00195 
00196     // now we're in the child process
00197 
00198     // obtain a new process group
00199     setsid();
00200 
00201     // change the umask
00202     umask(uMask);
00203 
00204     /* TODO: wait with this until we have logging
00205     // close standard file descriptors
00206     for (i=getdtablesize();i>=0;--i) close(i); //
00207  
00208     // set all std in/out to /dev/null
00209     i=open("/dev/null",O_RDWR); // open stdin
00210     dup(i);                     // stdout
00211     dup(i);                     // stderr
00212     */
00213 
00214     // save the process id
00215     savePid();
00216 
00217     // ignore some signals
00218     signal(SIGCHLD,SIG_IGN);
00219     signal(SIGTSTP,SIG_IGN);
00220     signal(SIGTTOU,SIG_IGN);
00221     signal(SIGTTIN,SIG_IGN);
00222 
00223     // register our signal hanlder
00224     SignalDispatcher * signalDispatcher = SignalDispatcher::getInstance();
00225     XmlRpcDaemonShutdownSignalHandler * handler =
00226                                     new XmlRpcDaemonShutdownSignalHandler(this);
00227     signalDispatcher->registerHandler(SIGHUP, handler);
00228     signalDispatcher->registerHandler(SIGTERM, handler);
00229     // FIXME: this signal handler will not be deleted by anyone,
00230     //        possible memory leak
00231 
00232     return true;
00233 }
00234 
00235 
00236 /*------------------------------------------------------------------------------
00237  *  Save the current process id.
00238  *----------------------------------------------------------------------------*/
00239 void
00240 XmlRpcDaemon :: savePid(void)                            throw ()
00241 {
00242     std::ofstream   pidFile(pidFileName.c_str());
00243     pidFile << getpid();
00244     pidFile.flush();
00245     pidFile.close();
00246 }
00247 
00248 
00249 /*------------------------------------------------------------------------------
00250  *  Return the saved process id.
00251  *----------------------------------------------------------------------------*/
00252 pid_t
00253 XmlRpcDaemon :: loadPid(void)                            throw ()
00254 {
00255     pid_t   pid;
00256 
00257     std::ifstream   pidFile(pidFileName.c_str());
00258     if (pidFile.fail()) {
00259         //std::cout << "XmlRpcDaemon::loadPid - Failed to open file " << pidFileName.c_str() << "n";
00260         return 0;
00261     }
00262 
00263     pidFile >> pid;
00264     pidFile.close();
00265 
00266     return pid;
00267 }
00268 
00269 
00270 /*------------------------------------------------------------------------------
00271  *  Start the daemon.
00272  *----------------------------------------------------------------------------*/
00273 void
00274 XmlRpcDaemon :: start (void)                         throw (std::logic_error)
00275 {
00276     checkForConfiguration();
00277 
00278     if (isRunning()) {
00279         std::cout << "Campcaster Scheduler is already running.n";
00280         return;
00281     }
00282     
00283     if (background) {
00284         if (!daemonize()) {
00285             // return if we're the parent process that should not continue
00286             return;
00287         }
00288     }
00289 
00290     startup();
00291 }
00292 
00293 
00294 /*------------------------------------------------------------------------------
00295  *  Execute any daemon startup calls.
00296  *----------------------------------------------------------------------------*/
00297 void
00298 XmlRpcDaemon :: startup (void)                       throw (std::logic_error)
00299 {
00300     // and now our own XML-RPC methods
00301     registerXmlRpcFunctions(xmlRpcServer);
00302 
00303     // bind & run
00304     xmlRpcServer->enableIntrospection(true);
00305     xmlRpcServer->bindAndListen(xmlRpcPort);
00306     xmlRpcServer->work(-1.0);
00307 }
00308 
00309 
00310 /*------------------------------------------------------------------------------
00311  *  Tell if the daemon is running.
00312  *----------------------------------------------------------------------------*/
00313 bool
00314 XmlRpcDaemon :: isRunning (void)                     throw (std::logic_error)
00315 {
00316     checkForConfiguration();
00317 
00318     pid_t   pid = loadPid();
00319     // check if there is a stale pid stored
00320     if (pid && kill(pid, 0)) {
00321         if (errno == ESRCH) {
00322             // the pid does not exist, remove the stale pid file
00323             remove(pidFileName.c_str());
00324             pid = 0;
00325         }
00326     }
00327     //std::cout << "XmlRpcDaemon::isRunning - pid is " << pid << "n";
00328     return pid;
00329 }
00330 
00331 
00332 /*------------------------------------------------------------------------------
00333  *  Stop the daemon.
00334  *----------------------------------------------------------------------------*/
00335 void
00336 XmlRpcDaemon :: stop (void)                          throw (std::logic_error)
00337 {
00338     checkForConfiguration();
00339 
00340     pid_t   pid = loadPid();
00341     if (pid) {
00342         kill(pid, SIGTERM);
00343     }
00344 }
00345 
00346 
00347 /*------------------------------------------------------------------------------
00348  *  Shut down the daemon.
00349  *----------------------------------------------------------------------------*/
00350 void
00351 XmlRpcDaemon :: shutdown (void)                      throw (std::logic_error)
00352 {
00353     checkForConfiguration();
00354 
00355     xmlRpcServer->shutdown();
00356     remove(pidFileName.c_str());
00357 }
00358 
00359 

Generated on Thu Sep 20 02:00:32 2007 for Campcaster by  1.4.7