Fawkes API Fawkes Development Version
|
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 }