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
47using namespace std;
48using namespace fawkes;
49
50/** Fawkes beep daemon.
51 *
52 * @author Tim Niemueller
53 */
55{
56public:
57 /** Constructor. */
59 {
60 until_ = NULL;
61 bb_ = NULL;
62 switch_if_ = NULL;
63 }
64
65 virtual void
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>()) {
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>()) {
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
139private:
140 BeepController beep_;
141 BlackBoard * bb_;
142 SwitchInterface *switch_if_;
143
144 Time *until_;
145};
146
147void
148usage(const char *progname)
149{
150}
151
152#ifdef HAVE_LIBDAEMON
153void
154daemonize_cleanup()
155{
156 daemon_retval_send(-1);
157 daemon_retval_done();
158 daemon_pid_file_remove();
159}
160
161pid_t
162daemonize(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 */
226const char *fawkes_pid_file;
227
228/** Function that returns the PID file name.
229 * @return PID file name
230 */
231const char *
232fawkes_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 */
242int
243main(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}
Simple speaker beep controller.
Definition: beep.h:25
void beep_on(float freq=1000)
Enable beeping.
Definition: beep.cpp:67
void beep_off()
Disable beeping.
Definition: beep.cpp:90
Fawkes beep daemon.
Definition: main.cpp:55
virtual void loop()
Code to execute in the thread.
Definition: main.cpp:66
void handle_signal(int signum)
Handle signals.
Definition: main.cpp:134
FawkesBeepDaemon()
Constructor.
Definition: main.cpp:58
Parse command line arguments.
Definition: argparser.h:64
const char * arg(const char *argn)
Get argument value.
Definition: argparser.cpp:177
bool has_arg(const char *argn)
Check if argument has been supplied.
Definition: argparser.cpp:165
The BlackBoard abstract class.
Definition: blackboard.h:46
virtual bool is_alive() const noexcept=0
Check if the BlackBoard is still alive.
virtual Interface * open_for_writing(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for writing.
virtual void close(Interface *interface)=0
Close interface.
Base class for exceptions in Fawkes.
Definition: exception.h:36
bool msgq_first_is()
Check if first message has desired type.
Definition: interface.h:351
void msgq_pop()
Erase first message from queue.
Definition: interface.cpp:1215
Message * msgq_first()
Get the first message from the message queue.
Definition: interface.cpp:1200
bool msgq_empty()
Check if queue is empty.
Definition: interface.cpp:1062
bool is_valid() const
Check validity of interface.
Definition: interface.cpp:469
Remote BlackBoard.
Definition: remote.h:50
Interface for signal handling.
Definition: signal.h:36
DisableSwitchMessage Fawkes BlackBoard Interface Message.
EnableDurationMessage Fawkes BlackBoard Interface Message.
float duration() const
Get duration value.
EnableSwitchMessage Fawkes BlackBoard Interface Message.
SetMessage Fawkes BlackBoard Interface Message.
float value() const
Get value value.
bool is_enabled() const
Get enabled value.
SwitchInterface Fawkes BlackBoard Interface.
Thread class encapsulation of pthreads.
Definition: thread.h:46
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:499
void join()
Join the thread.
Definition: thread.cpp:597
void cancel()
Cancel a thread.
Definition: thread.cpp:646
@ OPMODE_CONTINUOUS
operate in continuous mode (default)
Definition: thread.h:57
A class for handling time.
Definition: time.h:93
Fawkes library namespace.