main.cpp

00001 
00002 /***************************************************************************
00003  *  main.cpp - Fawkes main application
00004  *
00005  *  Created: Sun Apr 11 19:34:09 2010
00006  *  Copyright  2006-2010  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include "beep.h"
00025 
00026 #include <core/threading/thread.h>
00027 #include <utils/system/signal.h>
00028 #include <utils/system/argparser.h>
00029 #include <blackboard/remote.h>
00030 #include <interfaces/SwitchInterface.h>
00031 #include <utils/time/time.h>
00032 
00033 #include <cstdio>
00034 #include <unistd.h>
00035 #include <cmath>
00036 #ifdef HAVE_LIBDAEMON
00037 #  include <cerrno>
00038 #  include <cstring>
00039 #  include <libdaemon/dfork.h>
00040 #  include <libdaemon/dlog.h>
00041 #  include <libdaemon/dpid.h>
00042 #  include <sys/stat.h>
00043 #  include <sys/wait.h>
00044 #endif
00045 
00046 using namespace std;
00047 using namespace fawkes;
00048 
00049 /** Fawkes beep daemon.
00050  *
00051  * @author Tim Niemueller
00052  */
00053 class FawkesBeepDaemon
00054   : public Thread,
00055     public SignalHandler
00056 {
00057  public:
00058   /** Constructor. */
00059   FawkesBeepDaemon()
00060     : Thread("FawkesBeepDaemon", Thread::OPMODE_CONTINUOUS)
00061   {
00062     __until     = NULL;
00063     __bb        = NULL;
00064     __switch_if = NULL;
00065   }
00066 
00067   virtual void loop()
00068   {
00069     while (! (__bb && __bb->is_alive() && __switch_if->is_valid())) {
00070       if (__bb) {
00071         printf("Lost connection to blackboard\n");
00072         __bb->close(__switch_if);
00073         delete __bb;
00074         __bb = NULL;
00075       }
00076       try {
00077         printf("Trying to connect to remote BB...");
00078         __bb = new RemoteBlackBoard("localhost", 1910);
00079         __switch_if = __bb->open_for_writing<SwitchInterface>("Beep");
00080         printf("succeeded\n");
00081       } catch (Exception &e) {
00082         printf("failed\n");
00083         delete __bb;
00084         __bb = NULL;
00085         sleep(5);
00086       }
00087     }
00088 
00089     if (__until) {
00090       Time now;
00091       if ((now - __until) >= 0) {
00092         __beep.beep_off();
00093         delete __until;
00094         __until = NULL;
00095       }
00096     }
00097 
00098     while (! __switch_if->msgq_empty()) {
00099       if (  __switch_if->msgq_first_is<SwitchInterface::SetMessage>() ) {
00100         SwitchInterface::SetMessage *msg = __switch_if->msgq_first<SwitchInterface::SetMessage>();
00101         if (msg->value() > 0.0) {
00102           __beep.beep_on(msg->value());
00103         } else if (msg->is_enabled()) {
00104           __beep.beep_on();
00105         } else {
00106           __beep.beep_off();
00107         }
00108 
00109       } else if (  __switch_if->msgq_first_is<SwitchInterface::EnableDurationMessage>() ) {
00110         SwitchInterface::EnableDurationMessage *msg =
00111           __switch_if->msgq_first<SwitchInterface::EnableDurationMessage>();
00112         float duration = fabs(msg->duration());
00113         float value    = fabs(msg->value());
00114 
00115         delete __until;
00116         __until = new Time();
00117         *__until += duration;
00118         __beep.beep_on(value);
00119       } else if (__switch_if->msgq_first_is<SwitchInterface::EnableSwitchMessage>() ) {
00120         __beep.beep_on();
00121       } else if (__switch_if->msgq_first_is<SwitchInterface::DisableSwitchMessage>() ) {
00122         __beep.beep_off();
00123       }
00124       
00125       __switch_if->msgq_pop();
00126     }
00127 
00128     usleep(10000);
00129   }
00130 
00131 
00132   /** Handle signals.
00133    * @param signum signal number
00134    */
00135   void handle_signal(int signum)
00136   {
00137     this->cancel();
00138   }
00139 
00140  private:
00141   BeepController __beep;
00142   BlackBoard *__bb;
00143   SwitchInterface *__switch_if;
00144 
00145   Time *__until;
00146 };
00147 
00148 
00149 void
00150 usage(const char *progname)
00151 {
00152 }
00153 
00154 
00155 #ifdef HAVE_LIBDAEMON
00156 void
00157 daemonize_cleanup()
00158 {
00159   daemon_retval_send(-1);
00160   daemon_retval_done();
00161   daemon_pid_file_remove();
00162 }
00163 
00164 pid_t
00165 daemonize(int argc, char **argv)
00166 {
00167   pid_t pid;
00168   mode_t old_umask = umask(0);
00169 
00170   // Prepare for return value passing
00171   daemon_retval_init();
00172 
00173   // Do the fork
00174   if ((pid = daemon_fork()) < 0) {
00175     return -1;
00176         
00177   } else if (pid) { // the parent
00178     int ret;
00179 
00180     // Wait for 20 seconds for the return value passed from the daemon process
00181     if ((ret = daemon_retval_wait(20)) < 0) {
00182       daemon_log(LOG_ERR, "Could not recieve return value from daemon process.");
00183       return -1;
00184     }
00185 
00186     if ( ret != 0 ) {
00187       daemon_log(LOG_ERR, "*** Daemon startup failed, see syslog for details. ***");
00188       switch (ret) {
00189       case 1:
00190         daemon_log(LOG_ERR, "Daemon failed to close file descriptors");
00191         break;
00192       case 2:
00193         daemon_log(LOG_ERR, "Daemon failed to create PID file");
00194         break;
00195       }
00196       return -1;
00197     } else {
00198       return pid;
00199     }
00200 
00201   } else { // the daemon
00202 #ifdef DAEMON_CLOSE_ALL_AVAILABLE
00203     if (daemon_close_all(-1) < 0) {
00204       daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
00205       // Send the error condition to the parent process
00206       daemon_retval_send(1);
00207       return -1;
00208     }
00209 #endif
00210 
00211     // Create the PID file
00212     if (daemon_pid_file_create() < 0) {
00213       printf("Could not create PID file (%s).", strerror(errno));
00214       daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
00215 
00216       // Send the error condition to the parent process
00217       daemon_retval_send(2);
00218       return -1;
00219     }
00220 
00221     // Send OK to parent process
00222     daemon_retval_send(0);
00223 
00224     daemon_log(LOG_INFO, "Sucessfully started");
00225 
00226     umask(old_umask);
00227     return 0;
00228   }
00229 }
00230 
00231 /** Global variable containing the path to the PID file.
00232  * unfortunately needed for libdaemon */
00233 const char *fawkes_pid_file;
00234 
00235 /** Function that returns the PID file name.
00236  * @return PID file name
00237  */
00238 const char *
00239 fawkes_daemon_pid_file_proc()
00240 {
00241   return fawkes_pid_file;
00242 }
00243 #endif // HAVE_LIBDAEMON
00244 
00245 /** Fawkes application.
00246  * @param argc argument count
00247  * @param argv array of arguments
00248  */
00249 int
00250 main(int argc, char **argv)
00251 {
00252   ArgumentParser *argp = new ArgumentParser(argc, argv, "hD::ks");
00253 
00254   // default user/group
00255   const char *user  = NULL;
00256   const char *group = NULL;
00257   if (argp->has_arg("u")) {
00258     user = argp->arg("u");
00259   }
00260   if (argp->has_arg("g")) {
00261     group = argp->arg("g");
00262   }
00263 
00264 #ifdef HAVE_LIBDAEMON
00265   pid_t pid;
00266   int ret;
00267 
00268   if ( argp->has_arg("D") ) {
00269     // Set identification string for the daemon for both syslog and PID file
00270     daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]);
00271     if ( argp->arg("D") != NULL ) {
00272       fawkes_pid_file      = argp->arg("D");
00273       daemon_pid_file_proc = fawkes_daemon_pid_file_proc;
00274     }
00275 
00276     // We should daemonize, check if we were called to kill a daemonized copy
00277     if ( argp->has_arg("k") ) {
00278       // Check that the daemon is not run twice a the same time
00279       if ((pid = daemon_pid_file_is_running()) < 0) {
00280         daemon_log(LOG_ERR, "Fawkes daemon not running.");
00281         return 1;
00282       }
00283 
00284       // Kill daemon with SIGINT
00285       if ((ret = daemon_pid_file_kill_wait(SIGINT, 5)) < 0) {
00286         daemon_log(LOG_WARNING, "Failed to kill daemon");
00287       }
00288       return (ret < 0) ? 1 : 0;
00289     }
00290 
00291     if ( argp->has_arg("s") ) {
00292       // Check daemon status
00293       return (daemon_pid_file_is_running() < 0);
00294     }
00295 
00296     // Check that the daemon is not run twice a the same time
00297     if ((pid = daemon_pid_file_is_running()) >= 0) {
00298       daemon_log(LOG_ERR, "Daemon already running on (PID %u)", pid);
00299       return 201;
00300     }
00301 
00302     pid = daemonize(argc, argv);
00303     if ( pid < 0 ) {
00304       daemonize_cleanup();
00305       return 201;
00306     } else if (pid) {
00307       // parent
00308       return 0;
00309     } // else child, continue as usual
00310   }
00311 #else
00312   if ( argp->has_arg("D") ) {
00313     printf("Daemonizing support is not available.\n"
00314            "(libdaemon[-devel] was not available at compile time)\n");
00315     return 202;
00316   }
00317 #endif
00318 
00319   Thread::init_main();
00320 
00321   if ( argp->has_arg("h") ) {
00322     usage(argv[0]);
00323     delete argp;
00324     return 0;
00325   }
00326 
00327   FawkesBeepDaemon beepd;
00328   SignalManager::register_handler(SIGINT, &beepd);
00329   SignalManager::register_handler(SIGTERM, &beepd);
00330 
00331   beepd.start();
00332   beepd.join();
00333 
00334   Thread::destroy_main();
00335 
00336 #ifdef HAVE_LIBDAEMON
00337   if ( argp->has_arg("D") ) {
00338     daemonize_cleanup();
00339   }
00340 #endif
00341 
00342   delete argp;
00343   return 0;
00344 }

Generated on Tue Feb 22 13:32:17 2011 for Fawkes API by  doxygen 1.4.7