Fawkes API  Fawkes Development Version
main.cpp
1 
2 /***************************************************************************
3  * main.cpp - Fawkes main application
4  *
5  * Created: Sun Apr 11 19:34:09 2010
6  * Copyright 2006-2010 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include "beep.h"
25 
26 #include <core/threading/thread.h>
27 #include <utils/system/signal.h>
28 #include <utils/system/argparser.h>
29 #include <blackboard/remote.h>
30 #include <interfaces/SwitchInterface.h>
31 #include <utils/time/time.h>
32 
33 #include <cstdio>
34 #include <unistd.h>
35 #include <cmath>
36 #ifdef HAVE_LIBDAEMON
37 # include <cerrno>
38 # include <cstring>
39 # include <libdaemon/dfork.h>
40 # include <libdaemon/dlog.h>
41 # include <libdaemon/dpid.h>
42 # include <sys/stat.h>
43 # include <sys/wait.h>
44 #endif
45 
46 using namespace std;
47 using namespace fawkes;
48 
49 /** Fawkes beep daemon.
50  *
51  * @author Tim Niemueller
52  */
54  : public Thread,
55  public SignalHandler
56 {
57  public:
58  /** Constructor. */
60  : Thread("FawkesBeepDaemon", Thread::OPMODE_CONTINUOUS)
61  {
62  __until = NULL;
63  __bb = NULL;
64  __switch_if = NULL;
65  }
66 
67  virtual void loop()
68  {
69  while (! (__bb && __bb->is_alive() && __switch_if->is_valid())) {
70  if (__bb) {
71  printf("Lost connection to blackboard\n");
72  __bb->close(__switch_if);
73  delete __bb;
74  __bb = NULL;
75  }
76  try {
77  printf("Trying to connect to remote BB...");
78  __bb = new RemoteBlackBoard("localhost", 1910);
79  __switch_if = __bb->open_for_writing<SwitchInterface>("Beep");
80  printf("succeeded\n");
81  } catch (Exception &e) {
82  printf("failed\n");
83  delete __bb;
84  __bb = NULL;
85  sleep(5);
86  }
87  }
88 
89  if (__until) {
90  Time now;
91  if ((now - __until) >= 0) {
92  __beep.beep_off();
93  delete __until;
94  __until = NULL;
95  }
96  }
97 
98  while (! __switch_if->msgq_empty()) {
99  if ( __switch_if->msgq_first_is<SwitchInterface::SetMessage>() ) {
100  SwitchInterface::SetMessage *msg = __switch_if->msgq_first<SwitchInterface::SetMessage>();
101  if (msg->value() > 0.0) {
102  __beep.beep_on(msg->value());
103  } else if (msg->is_enabled()) {
104  __beep.beep_on();
105  } else {
106  __beep.beep_off();
107  }
108 
109  } else if ( __switch_if->msgq_first_is<SwitchInterface::EnableDurationMessage>() ) {
111  __switch_if->msgq_first<SwitchInterface::EnableDurationMessage>();
112  float duration = fabs(msg->duration());
113  float value = fabs(msg->value());
114 
115  delete __until;
116  __until = new Time();
117  *__until += duration;
118  __beep.beep_on(value);
119  } else if (__switch_if->msgq_first_is<SwitchInterface::EnableSwitchMessage>() ) {
120  __beep.beep_on();
121  } else if (__switch_if->msgq_first_is<SwitchInterface::DisableSwitchMessage>() ) {
122  __beep.beep_off();
123  }
124 
125  __switch_if->msgq_pop();
126  }
127 
128  usleep(10000);
129  }
130 
131 
132  /** Handle signals.
133  * @param signum signal number
134  */
135  void handle_signal(int signum)
136  {
137  this->cancel();
138  }
139 
140  private:
141  BeepController __beep;
142  BlackBoard *__bb;
143  SwitchInterface *__switch_if;
144 
145  Time *__until;
146 };
147 
148 
149 void
150 usage(const char *progname)
151 {
152 }
153 
154 
155 #ifdef HAVE_LIBDAEMON
156 void
157 daemonize_cleanup()
158 {
159  daemon_retval_send(-1);
160  daemon_retval_done();
161  daemon_pid_file_remove();
162 }
163 
164 pid_t
165 daemonize(int argc, char **argv)
166 {
167  pid_t pid;
168  mode_t old_umask = umask(0);
169 
170  // Prepare for return value passing
171  daemon_retval_init();
172 
173  // Do the fork
174  if ((pid = daemon_fork()) < 0) {
175  return -1;
176 
177  } else if (pid) { // the parent
178  int ret;
179 
180  // Wait for 20 seconds for the return value passed from the daemon process
181  if ((ret = daemon_retval_wait(20)) < 0) {
182  daemon_log(LOG_ERR, "Could not recieve return value from daemon process.");
183  return -1;
184  }
185 
186  if ( ret != 0 ) {
187  daemon_log(LOG_ERR, "*** Daemon startup failed, see syslog for details. ***");
188  switch (ret) {
189  case 1:
190  daemon_log(LOG_ERR, "Daemon failed to close file descriptors");
191  break;
192  case 2:
193  daemon_log(LOG_ERR, "Daemon failed to create PID file");
194  break;
195  }
196  return -1;
197  } else {
198  return pid;
199  }
200 
201  } else { // the daemon
202 #ifdef DAEMON_CLOSE_ALL_AVAILABLE
203  if (daemon_close_all(-1) < 0) {
204  daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
205  // Send the error condition to the parent process
206  daemon_retval_send(1);
207  return -1;
208  }
209 #endif
210 
211  // Create the PID file
212  if (daemon_pid_file_create() < 0) {
213  printf("Could not create PID file (%s).", strerror(errno));
214  daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
215 
216  // Send the error condition to the parent process
217  daemon_retval_send(2);
218  return -1;
219  }
220 
221  // Send OK to parent process
222  daemon_retval_send(0);
223 
224  daemon_log(LOG_INFO, "Sucessfully started");
225 
226  umask(old_umask);
227  return 0;
228  }
229 }
230 
231 /** Global variable containing the path to the PID file.
232  * unfortunately needed for libdaemon */
233 const char *fawkes_pid_file;
234 
235 /** Function that returns the PID file name.
236  * @return PID file name
237  */
238 const char *
239 fawkes_daemon_pid_file_proc()
240 {
241  return fawkes_pid_file;
242 }
243 #endif // HAVE_LIBDAEMON
244 
245 /** Fawkes application.
246  * @param argc argument count
247  * @param argv array of arguments
248  */
249 int
250 main(int argc, char **argv)
251 {
252  ArgumentParser *argp = new ArgumentParser(argc, argv, "hD::ks");
253 
254  // default user/group
255  const char *user = NULL;
256  const char *group = NULL;
257  if (argp->has_arg("u")) {
258  user = argp->arg("u");
259  }
260  if (argp->has_arg("g")) {
261  group = argp->arg("g");
262  }
263 
264 #ifdef HAVE_LIBDAEMON
265  pid_t pid;
266  int ret;
267 
268  if ( argp->has_arg("D") ) {
269  // Set identification string for the daemon for both syslog and PID file
270  daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]);
271  if ( argp->arg("D") != NULL ) {
272  fawkes_pid_file = argp->arg("D");
273  daemon_pid_file_proc = fawkes_daemon_pid_file_proc;
274  }
275 
276  // We should daemonize, check if we were called to kill a daemonized copy
277  if ( argp->has_arg("k") ) {
278  // Check that the daemon is not run twice a the same time
279  if ((pid = daemon_pid_file_is_running()) < 0) {
280  daemon_log(LOG_ERR, "Fawkes daemon not running.");
281  return 1;
282  }
283 
284  // Kill daemon with SIGINT
285  if ((ret = daemon_pid_file_kill_wait(SIGINT, 5)) < 0) {
286  daemon_log(LOG_WARNING, "Failed to kill daemon");
287  }
288  return (ret < 0) ? 1 : 0;
289  }
290 
291  if ( argp->has_arg("s") ) {
292  // Check daemon status
293  return (daemon_pid_file_is_running() < 0);
294  }
295 
296  // Check that the daemon is not run twice a the same time
297  if ((pid = daemon_pid_file_is_running()) >= 0) {
298  daemon_log(LOG_ERR, "Daemon already running on (PID %u)", pid);
299  return 201;
300  }
301 
302  pid = daemonize(argc, argv);
303  if ( pid < 0 ) {
304  daemonize_cleanup();
305  return 201;
306  } else if (pid) {
307  // parent
308  return 0;
309  } // else child, continue as usual
310  }
311 #else
312  if ( argp->has_arg("D") ) {
313  printf("Daemonizing support is not available.\n"
314  "(libdaemon[-devel] was not available at compile time)\n");
315  return 202;
316  }
317 #endif
318 
319  Thread::init_main();
320 
321  if ( argp->has_arg("h") ) {
322  usage(argv[0]);
323  delete argp;
324  return 0;
325  }
326 
327  FawkesBeepDaemon beepd;
328  SignalManager::register_handler(SIGINT, &beepd);
329  SignalManager::register_handler(SIGTERM, &beepd);
330 
331  beepd.start();
332  beepd.join();
333 
334  Thread::destroy_main();
335 
336 #ifdef HAVE_LIBDAEMON
337  if ( argp->has_arg("D") ) {
338  daemonize_cleanup();
339  }
340 #endif
341 
342  delete argp;
343  return 0;
344 }
SetMessage Fawkes BlackBoard Interface Message.
const char * arg(const char *argn)
Get argument value.
Definition: argparser.cpp:182
void handle_signal(int signum)
Handle signals.
Definition: main.cpp:135
Fawkes library namespace.
STL namespace.
Interface for signal handling.
Definition: signal.h:35
Parse command line arguments.
Definition: argparser.h:66
A class for handling time.
Definition: time.h:91
float value() const
Get value value.
Thread class encapsulation of pthreads.
Definition: thread.h:42
Simple speaker beep controller.
Definition: beep.h:24
bool is_enabled() const
Get enabled value.
SwitchInterface Fawkes BlackBoard Interface.
Base class for exceptions in Fawkes.
Definition: exception.h:36
Fawkes beep daemon.
Definition: main.cpp:53
DisableSwitchMessage Fawkes BlackBoard Interface Message.
float duration() const
Get duration value.
EnableSwitchMessage Fawkes BlackBoard Interface Message.
Remote BlackBoard.
Definition: remote.h:48
FawkesBeepDaemon()
Constructor.
Definition: main.cpp:59
void join()
Join the thread.
Definition: thread.cpp:610
bool has_arg(const char *argn)
Check if argument has been supplied.
Definition: argparser.cpp:169
EnableDurationMessage Fawkes BlackBoard Interface Message.
The BlackBoard abstract class.
Definition: blackboard.h:48
virtual void loop()
Code to execute in the thread.
Definition: main.cpp:67
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:511