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 <blackboard/remote.h>
27 #include <core/threading/thread.h>
28 #include <interfaces/SwitchInterface.h>
29 #include <utils/system/argparser.h>
30 #include <utils/system/signal.h>
31 #include <utils/time/time.h>
32 
33 #include <cmath>
34 #include <cstdio>
35 #include <unistd.h>
36 #ifdef HAVE_LIBDAEMON
37 # include <libdaemon/dfork.h>
38 # include <libdaemon/dlog.h>
39 # include <libdaemon/dpid.h>
40 # include <sys/stat.h>
41 # include <sys/wait.h>
42 
43 # include <cerrno>
44 # include <cstring>
45 #endif
46 
47 using namespace std;
48 using namespace fawkes;
49 
50 /** Fawkes beep daemon.
51  *
52  * @author Tim Niemueller
53  */
54 class FawkesBeepDaemon : public Thread, public SignalHandler
55 {
56 public:
57  /** Constructor. */
58  FawkesBeepDaemon() : Thread("FawkesBeepDaemon", Thread::OPMODE_CONTINUOUS)
59  {
60  until_ = NULL;
61  bb_ = NULL;
62  switch_if_ = NULL;
63  }
64 
65  virtual void
66  loop()
67  {
68  while (!(bb_ && bb_->is_alive() && switch_if_->is_valid())) {
69  if (bb_) {
70  printf("Lost connection to blackboard\n");
71  bb_->close(switch_if_);
72  delete bb_;
73  bb_ = NULL;
74  }
75  try {
76  printf("Trying to connect to remote BB...");
77  bb_ = new RemoteBlackBoard("localhost", 1910);
78  switch_if_ = bb_->open_for_writing<SwitchInterface>("Beep");
79  printf("succeeded\n");
80  } catch (Exception &e) {
81  printf("failed\n");
82  delete bb_;
83  bb_ = NULL;
84  sleep(5);
85  }
86  }
87 
88  if (until_) {
89  Time now;
90  if ((now - until_) >= 0) {
91  beep_.beep_off();
92  delete until_;
93  until_ = NULL;
94  }
95  }
96 
97  while (!switch_if_->msgq_empty()) {
98  if (switch_if_->msgq_first_is<SwitchInterface::SetMessage>()) {
99  SwitchInterface::SetMessage *msg = switch_if_->msgq_first<SwitchInterface::SetMessage>();
100  if (msg->value() > 0.0) {
101  beep_.beep_on(msg->value());
102  } else if (msg->is_enabled()) {
103  beep_.beep_on();
104  } else {
105  beep_.beep_off();
106  }
107 
108  } else if (switch_if_->msgq_first_is<SwitchInterface::EnableDurationMessage>()) {
110  switch_if_->msgq_first<SwitchInterface::EnableDurationMessage>();
111  float duration = fabs(msg->duration());
112  float value = fabs(msg->value());
113 
114  delete until_;
115  until_ = new Time();
116  *until_ += duration;
117  beep_.beep_on(value);
118  } else if (switch_if_->msgq_first_is<SwitchInterface::EnableSwitchMessage>()) {
119  beep_.beep_on();
120  } else if (switch_if_->msgq_first_is<SwitchInterface::DisableSwitchMessage>()) {
121  beep_.beep_off();
122  }
123 
124  switch_if_->msgq_pop();
125  }
126 
127  usleep(10000);
128  }
129 
130  /** Handle signals.
131  * @param signum signal number
132  */
133  void
134  handle_signal(int signum)
135  {
136  this->cancel();
137  }
138 
139 private:
140  BeepController beep_;
141  BlackBoard * bb_;
142  SwitchInterface *switch_if_;
143 
144  Time *until_;
145 };
146 
147 void
148 usage(const char *progname)
149 {
150 }
151 
152 #ifdef HAVE_LIBDAEMON
153 void
154 daemonize_cleanup()
155 {
156  daemon_retval_send(-1);
157  daemon_retval_done();
158  daemon_pid_file_remove();
159 }
160 
161 pid_t
162 daemonize(int argc, char **argv)
163 {
164  pid_t pid;
165  mode_t old_umask = umask(0);
166 
167  // Prepare for return value passing
168  daemon_retval_init();
169 
170  // Do the fork
171  if ((pid = daemon_fork()) < 0) {
172  return -1;
173 
174  } else if (pid) { // the parent
175  int ret;
176 
177  // Wait for 20 seconds for the return value passed from the daemon process
178  if ((ret = daemon_retval_wait(20)) < 0) {
179  daemon_log(LOG_ERR, "Could not recieve return value from daemon process.");
180  return -1;
181  }
182 
183  if (ret != 0) {
184  daemon_log(LOG_ERR, "*** Daemon startup failed, see syslog for details. ***");
185  switch (ret) {
186  case 1: daemon_log(LOG_ERR, "Daemon failed to close file descriptors"); break;
187  case 2: daemon_log(LOG_ERR, "Daemon failed to create PID file"); break;
188  }
189  return -1;
190  } else {
191  return pid;
192  }
193 
194  } else { // the daemon
195 # ifdef DAEMON_CLOSE_ALL_AVAILABLE
196  if (daemon_close_all(-1) < 0) {
197  daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
198  // Send the error condition to the parent process
199  daemon_retval_send(1);
200  return -1;
201  }
202 # endif
203 
204  // Create the PID file
205  if (daemon_pid_file_create() < 0) {
206  printf("Could not create PID file (%s).", strerror(errno));
207  daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
208 
209  // Send the error condition to the parent process
210  daemon_retval_send(2);
211  return -1;
212  }
213 
214  // Send OK to parent process
215  daemon_retval_send(0);
216 
217  daemon_log(LOG_INFO, "Sucessfully started");
218 
219  umask(old_umask);
220  return 0;
221  }
222 }
223 
224 /** Global variable containing the path to the PID file.
225  * unfortunately needed for libdaemon */
226 const char *fawkes_pid_file;
227 
228 /** Function that returns the PID file name.
229  * @return PID file name
230  */
231 const char *
232 fawkes_daemon_pid_file_proc()
233 {
234  return fawkes_pid_file;
235 }
236 #endif // HAVE_LIBDAEMON
237 
238 /** Fawkes application.
239  * @param argc argument count
240  * @param argv array of arguments
241  */
242 int
243 main(int argc, char **argv)
244 {
245  ArgumentParser *argp = new ArgumentParser(argc, argv, "hD::ks");
246 
247 #ifdef HAVE_LIBDAEMON
248  pid_t pid;
249 
250  if (argp->has_arg("D")) {
251  // Set identification string for the daemon for both syslog and PID file
252  daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]);
253  if (argp->arg("D") != NULL) {
254  fawkes_pid_file = argp->arg("D");
255  daemon_pid_file_proc = fawkes_daemon_pid_file_proc;
256  }
257 
258  // We should daemonize, check if we were called to kill a daemonized copy
259  if (argp->has_arg("k")) {
260  // Check that the daemon is not run twice a the same time
261  if ((pid = daemon_pid_file_is_running()) < 0) {
262  daemon_log(LOG_ERR, "Fawkes daemon not running.");
263  return 1;
264  }
265 
266  // Kill daemon with SIGINT
267  int ret;
268  if ((ret = daemon_pid_file_kill_wait(SIGINT, 5)) < 0) {
269  daemon_log(LOG_WARNING, "Failed to kill daemon");
270  }
271  return (ret < 0) ? 1 : 0;
272  }
273 
274  if (argp->has_arg("s")) {
275  // Check daemon status
276  return (daemon_pid_file_is_running() < 0);
277  }
278 
279  // Check that the daemon is not run twice a the same time
280  if ((pid = daemon_pid_file_is_running()) >= 0) {
281  daemon_log(LOG_ERR, "Daemon already running on (PID %u)", pid);
282  return 201;
283  }
284 
285  pid = daemonize(argc, argv);
286  if (pid < 0) {
287  daemonize_cleanup();
288  return 201;
289  } else if (pid) {
290  // parent
291  return 0;
292  } // else child, continue as usual
293  }
294 #else
295  if (argp->has_arg("D")) {
296  printf("Daemonizing support is not available.\n"
297  "(libdaemon[-devel] was not available at compile time)\n");
298  return 202;
299  }
300 #endif
301 
302  Thread::init_main();
303 
304  if (argp->has_arg("h")) {
305  usage(argv[0]);
306  delete argp;
307  return 0;
308  }
309 
310  FawkesBeepDaemon beepd;
311  SignalManager::register_handler(SIGINT, &beepd);
312  SignalManager::register_handler(SIGTERM, &beepd);
313 
314  beepd.start();
315  beepd.join();
316 
317  Thread::destroy_main();
318 
319 #ifdef HAVE_LIBDAEMON
320  if (argp->has_arg("D")) {
321  daemonize_cleanup();
322  }
323 #endif
324 
325  delete argp;
326  return 0;
327 }
FawkesBeepDaemon
Fawkes beep daemon.
Definition: main.cpp:54
fawkes::SwitchInterface::SetMessage
Definition: SwitchInterface.h:92
fawkes::SwitchInterface::EnableDurationMessage::value
float value() const
Get value value.
Definition: SwitchInterface.cpp:675
fawkes::SwitchInterface
Definition: SwitchInterface.h:39
fawkes::SignalHandler
Definition: signal.h:45
FawkesBeepDaemon::loop
virtual void loop()
Code to execute in the thread.
Definition: main.cpp:66
fawkes::SwitchInterface::EnableDurationMessage
Definition: SwitchInterface.h:167
fawkes::BlackBoard
Definition: blackboard.h:50
fawkes::RemoteBlackBoard
Definition: remote.h:53
fawkes::SwitchInterface::DisableSwitchMessage
Definition: SwitchInterface.h:147
fawkes::ArgumentParser::has_arg
bool has_arg(const char *argn)
Check if argument has been supplied.
Definition: argparser.cpp:171
fawkes::SwitchInterface::SetMessage::is_enabled
bool is_enabled() const
Get enabled value.
Definition: SwitchInterface.cpp:413
FawkesBeepDaemon::FawkesBeepDaemon
FawkesBeepDaemon()
Constructor.
Definition: main.cpp:58
fawkes::SwitchInterface::EnableSwitchMessage
Definition: SwitchInterface.h:127
FawkesBeepDaemon::handle_signal
void handle_signal(int signum)
Handle signals.
Definition: main.cpp:134
fawkes
fawkes::ArgumentParser
Definition: argparser.h:69
fawkes::SwitchInterface::SetMessage::value
float value() const
Get value value.
Definition: SwitchInterface.cpp:449
fawkes::ArgumentParser::arg
const char * arg(const char *argn)
Get argument value.
Definition: argparser.cpp:183
fawkes::Time
Definition: time.h:98
fawkes::Thread
Definition: thread.h:45
BeepController
Definition: beep.h:24
fawkes::SwitchInterface::EnableDurationMessage::duration
float duration() const
Get duration value.
Definition: SwitchInterface.cpp:640
fawkes::Thread::start
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:505
fawkes::Thread::join
void join()
Join the thread.
Definition: thread.cpp:603
fawkes::Exception
Definition: exception.h:41