add functions for control interface to use dbus
[profile/ivi/genivi/genivi-audio-manager.git] / AudioManagerDaemon / src / main.cpp
1 /**
2  * Copyright (C) 2012, BMW AG
3  *
4  * This file is part of GENIVI Project AudioManager.
5  *
6  * Contributions are licensed to the GENIVI Alliance under one or more
7  * Contribution License Agreements.
8  *
9  * \copyright
10  * This Source Code Form is subject to the terms of the
11  * Mozilla Public License, v. 2.0. If a  copy of the MPL was not distributed with
12  * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
13  *
14  *
15  * \author Christian Mueller, christian.ei.mueller@bmw.de BMW 2011,2012
16  * \author Frank Herchet, frank.fh.herchet@bmw.de BMW 2012
17  *
18  * \file main.cpp
19  * For further information see http://www.genivi.org/.
20  *
21  */
22
23 /**
24  * \todo create systemd compatibility
25  * \todo all communication like all plugins loaded etc...
26  * \todo check the startup sequence. Dbus shall be activated last...
27  * \bug package generation only works if package directory exists...
28  */
29
30 #include "config.h"
31
32 #ifdef  WITH_TELNET
33     #include "CAmTelnetServer.h"
34 #endif
35
36 #ifdef WITH_CAPI_WRAPPER
37     #include "shared/CAmCommonAPIWrapper.h"
38 #else
39         #ifdef WITH_DBUS_WRAPPER
40                 #include "shared/CAmDbusWrapper.h"
41         #endif
42 #endif
43
44 #ifdef WITH_NSM
45         #ifdef WITH_DBUS_WRAPPER
46                 #include "CAmNodeStateCommunicatorDBus.h"
47         #else
48                 #include "CAmNodeStateCommunicatorCAPI.h"
49         #endif
50 #endif
51
52 #ifdef WITH_DATABASE_STORAGE
53     #include "CAmDatabaseHandlerSQLite.h"
54 #else
55     #include "CAmDatabaseHandlerMap.h"
56 #endif
57
58 #ifdef WITH_SYSTEMD_WATCHDOG
59     #include "CAmWatchdog.h"
60 #endif
61
62 #include <sys/resource.h>
63 #include <sys/stat.h>
64 #include <unistd.h>
65 #include <cstdlib>
66 #include <cstdlib>
67 #include <cassert>
68 #include <fcntl.h>
69 #include <csignal>
70 #include <cstring>
71 #include <cstdio>
72 #include <new>
73
74 #include "CAmRouter.h"
75 #include "CAmControlSender.h"
76 #include "CAmCommandSender.h"
77 #include "CAmRoutingSender.h"
78 #include "CAmRoutingReceiver.h"
79 #include "CAmCommandReceiver.h"
80 #include "CAmControlReceiver.h"
81 #include "CAmDatabaseObserver.h"
82 #include "shared/CAmDltWrapper.h"
83 #include "shared/CAmSocketHandler.h"
84
85
86 using namespace am;
87 DLT_DECLARE_CONTEXT(AudioManager)
88
89 const char* USAGE_DESCRIPTION = "Usage:\tAudioManagerDaemon [options]\n"
90         "options:\t\n"
91         "\t-h: print this message\t\n"
92         "\t-i: info about current settings \t\n"
93         "\t-v: print version\t\n"
94 #ifndef WITH_DLT
95         "\t-V: print DLT logs to stdout\t\n"
96 #endif
97         "\t-d: daemonize AudioManager \t\n"
98 #ifdef WITH_DBUS_WRAPPER
99         "\t-T: DbusType to be used by CAmDbusWrapper (0=DBUS_SESSION[default], 1=DBUS_SYSTEM)\t\n"
100 #endif
101         "\t-p<path> path for sqlite database (default is in memory)\t\n"
102         "\t-t<port> port for telnetconnection\t\n"
103         "\t-m<max> number of max telnetconnections\t\n"
104         "\t-c<Name> use controllerPlugin <Name> (full path with .so ending)\t\n"
105         "\t-l<Name> replace command plugin directory with <Name> (full path)\t\n"
106         "\t-r<Name> replace routing plugin directory with <Name> (full path)\t\n"
107         "\t-L<Name> add command plugin directory with <Name> (full path)\t\n"
108         "\t-R<Name> add routing plugin directory with <Name> (full path)\t\n";
109
110 std::string controllerPlugin = std::string(CONTROLLER_PLUGIN);
111 std::vector<std::string> listCommandPluginDirs;
112 std::vector<std::string> listRoutingPluginDirs;
113 std::string databasePath = std::string(":memory:");
114 unsigned int telnetport = DEFAULT_TELNETPORT;
115 unsigned int maxConnections = MAX_TELNETCONNECTIONS;
116 int fd0, fd1, fd2;
117 bool enableNoDLTDebug = false;
118
119 #ifdef WITH_DBUS_WRAPPER
120     DBusBusType dbusWrapperType=DBUS_BUS_SESSION;
121 #endif
122
123 /**
124  * the out of memory handler
125  */
126 void OutOfMemoryHandler()
127 {
128     logError("No more memory - bye");
129     //todo: add gracefull dead here. Do what can be done persistence wise
130     exit(1);
131 }
132
133 /**
134  * daemonizes the AudioManager
135  */
136 void daemonize()
137 {
138     umask(0);
139     std::string dir = "/";
140
141     rlimit rl;
142     if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
143     {
144         logError("can't get file limit ");
145     }
146
147     pid_t pid;
148     if ((pid = fork()) < 0)
149     {
150         logError("cannot fork!");
151     }
152     else if (pid != 0)
153     {
154         exit(0);
155     }
156
157     setsid();
158
159     if (!dir.empty() && chdir(dir.c_str()) < 0)
160     {
161         logError("couldn't chdir to the new directory");
162     }
163
164     if (rl.rlim_max == RLIM_INFINITY)
165     {
166         rl.rlim_max = 1024;
167     }
168
169     for (unsigned int i = 0; i < rl.rlim_max; i++)
170     {
171         close(i);
172     }
173
174     fd0 = open("/dev/null", O_RDONLY);
175     fd1 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
176     fd2 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
177
178     if (fd0 != STDIN_FILENO || fd1 != STDOUT_FILENO || fd2 != STDERR_FILENO)
179     {
180         logError("new standard file descriptors were not opened");
181     }
182 }
183
184 /**
185  * parses the command line
186  * @param argc
187  * @param argv
188  */
189 void parseCommandLine(int argc, char **argv)
190 {
191     while (optind < argc)
192     {
193 #ifdef WITH_DLT
194     #ifdef WITH_DBUS_WRAPPER
195             int option = getopt(argc, argv, "h::v::c::l::r::L::R::d::t::m::i::p::T::");
196     #else
197             int option = getopt(argc, argv, "h::v::c::l::r::L::R::d::t::m::i::p::");
198     #endif //WITH_DBUS_WRAPPER
199 #else
200     #ifdef WITH_DBUS_WRAPPER
201             int option = getopt(argc, argv, "h::v::V::c::l::r::L::R::d::t::m::i::p::T::");
202     #else
203             int option = getopt(argc, argv, "h::v::V::c::l::r::L::R::d::t::m::i::p::");
204     #endif //WITH_DBUS_WRAPPER
205 #endif
206
207         switch (option)
208         {
209         case 'i':
210             printf("Current settings:\n");
211             printf("\tAudioManagerDaemon Version:\t\t%s\n", DAEMONVERSION);
212             printf("\tTelnet portNumber:\t\t\t%i\n", telnetport);
213             printf("\tTelnet maxConnections:\t\t\t%i\n", maxConnections);
214             printf("\tSqlite Database path:\t\t\t%s\n", databasePath.c_str());
215             printf("\tControllerPlugin: \t\t\t%s\n", controllerPlugin.c_str());
216             printf("\tDirectory of CommandPlugins: \t\t%s\n", listCommandPluginDirs.front().c_str());
217             printf("\tDirectory of RoutingPlugins: \t\t%s\n", listRoutingPluginDirs.front().c_str());
218             exit(0);
219             break;
220         case 't':
221             assert(atoi(optarg)!=0);
222             telnetport = atoi(optarg);
223             break;
224         case 'm':
225             assert(atoi(optarg)!=0);
226             maxConnections = atoi(optarg);
227             break;
228         case 'p':
229             assert(!controllerPlugin.empty());
230             databasePath = std::string(optarg);
231             break;
232         case 'd':
233             daemonize();
234             break;
235         case 'l':
236             listCommandPluginDirs.clear();
237             listCommandPluginDirs.push_back(std::string(optarg));
238             break;
239         case 'r':
240             listRoutingPluginDirs.clear();
241             listRoutingPluginDirs.push_back(std::string(optarg));
242             break;
243         case 'L':
244             listCommandPluginDirs.push_back(std::string(optarg));
245             break;
246         case 'R':
247             listRoutingPluginDirs.push_back(std::string(optarg));
248             break;
249         case 'c':
250             controllerPlugin = std::string(optarg);
251             assert(!controllerPlugin.empty());
252             assert(controllerPlugin.find(".so")!=std::string::npos);
253             break;
254         case 'v':
255             printf("AudioManagerDaemon Version: %s\n", DAEMONVERSION);
256             exit(-1);
257             break;
258 #ifndef WITH_DLT
259             case 'V':
260             printf("\e[0;34m[DLT]\e[0;30m\tDebug output to stdout enabled\n");
261             enableNoDLTDebug = true;
262             break;
263 #endif
264 #ifdef WITH_DBUS_WRAPPER
265             case 'T':
266             dbusWrapperType=static_cast<DBusBusType>(atoi(optarg));
267             break;
268 #endif
269         case 'h':
270         default:
271             printf("AudioManagerDaemon Version: %s\n", DAEMONVERSION);
272             puts(USAGE_DESCRIPTION);
273             exit(-1);
274         }
275     }
276 }
277
278 /**
279  * the signal handler
280  * @param sig
281  * @param siginfo
282  * @param context
283  */
284 static void signalHandler(int sig, siginfo_t *siginfo, void *context)
285 {
286     (void) sig;
287     (void) siginfo;
288     (void) context;
289     logInfo("signal handler was called, signal",sig);
290
291     switch (sig)
292     {
293         /*ctl +c lets call direct controllerRundown, because we might be blocked at the moment.
294         But there is the risk of interrupting something important */
295         case SIGINT:
296             CAmControlSender::CallsetControllerRundown(sig);
297             break;
298
299         /* huch- we are getting killed. Better take the fast but risky way: */
300         case SIGQUIT:
301             CAmControlSender::CallsetControllerRundown(sig);
302             break;
303
304         /* more friendly here assuming systemd wants to stop us, so we can use the mainloop */
305         case SIGTERM:
306             CAmControlSender::CallsetControllerRundownSafe(sig);
307             break;
308
309         /* looks friendly, too, so lets take the long run */
310         case SIGHUP:
311             CAmControlSender::CallsetControllerRundownSafe(sig);
312             break;
313         default:
314             break;
315     }
316 }
317
318 void mainProgram()
319 {
320     //Instantiate all classes. Keep in same order !
321     CAmSocketHandler iSocketHandler;
322
323 #ifdef WITH_CAPI_WRAPPER
324     //We instantiate a singleton with the current socket handler, which loads the common-api runtime.
325     CAmCommonAPIWrapper *pCAPIWrapper = CAmCommonAPIWrapper::instantiateOnce(&iSocketHandler);
326     CAmCommonAPIWrapper iDBusWrapper = *pCAPIWrapper;
327 #ifdef WITH_NSM
328     CAmNodeStateCommunicatorCAPI iNodeStateCommunicator(&iDBusWrapper);
329 #endif /*WITH_NSM*/
330 #endif /*WITH_CAPI_WRAPPER */
331
332 #ifdef WITH_DBUS_WRAPPER
333     CAmDbusWrapper iDBusWrapper(&iSocketHandler,dbusWrapperType);
334 #ifdef WITH_NSM
335     CAmNodeStateCommunicatorDBus iNodeStateCommunicator(&iDBusWrapper);
336 #endif /*WITH_NSM*/
337 #endif /*WITH_DBUS_WRAPPER */
338
339 #ifdef WITH_SYSTEMD_WATCHDOG
340     CAmWatchdog iWatchdog(&iSocketHandler);
341 #endif /*WITH_SYSTEMD_WATCHDOG*/
342
343 #ifdef WITH_DATABASE_STORAGE
344     CAmDatabaseHandlerSQLite iDatabaseHandler(databasePath);
345 #else
346     CAmDatabaseHandlerMap iDatabaseHandler;
347 #endif /*WITH_DATABASE_STORAGE*/
348     IAmDatabaseHandler *pDatabaseHandler = dynamic_cast<IAmDatabaseHandler*>( &iDatabaseHandler );
349
350     CAmRoutingSender iRoutingSender(listRoutingPluginDirs);
351     CAmCommandSender iCommandSender(listCommandPluginDirs);
352     CAmControlSender iControlSender(controllerPlugin,&iSocketHandler);
353     CAmRouter iRouter(pDatabaseHandler, &iControlSender);
354
355 #ifdef WITH_DBUS_WRAPPER
356     CAmCommandReceiver iCommandReceiver(pDatabaseHandler, &iControlSender, &iSocketHandler, &iDBusWrapper);
357     CAmRoutingReceiver iRoutingReceiver(pDatabaseHandler, &iRoutingSender, &iControlSender, &iSocketHandler, &iDBusWrapper);
358 #else /*WITH_DBUS_WRAPPER*/
359             CAmCommandReceiver iCommandReceiver(pDatabaseHandler,&iControlSender,&iSocketHandler);
360             CAmRoutingReceiver iRoutingReceiver(pDatabaseHandler,&iRoutingSender,&iControlSender,&iSocketHandler);
361 #endif /*WITH_DBUS_WRAPPER*/
362
363 #ifdef WITH_NSM
364         CAmControlReceiver iControlReceiver(pDatabaseHandler,&iRoutingSender,&iCommandSender,&iSocketHandler, &iRouter, &iNodeStateCommunicator);
365         iNodeStateCommunicator.registerControlSender(&iControlSender);
366 #else /*WITH_NSM*/
367 #ifdef WITH_DBUS_WRAPPER
368         CAmControlReceiver iControlReceiver(pDatabaseHandler,&iRoutingSender,&iCommandSender,&iSocketHandler, &iRouter, &iDBusWrapper);
369 #else /*WITH_DBUS_WRAPPER*/
370         CAmControlReceiver iControlReceiver(pDatabaseHandler,&iRoutingSender,&iCommandSender,&iSocketHandler, &iRouter);
371 #endif /*WITH_DBUS_WRAPPER*/
372 #endif /*WITH_NSM*/
373
374 #ifdef WITH_TELNET
375     CAmTelnetServer iTelnetServer(&iSocketHandler, &iCommandSender, &iCommandReceiver, &iRoutingSender, &iRoutingReceiver, &iControlSender, &iControlReceiver, pDatabaseHandler, &iRouter, telnetport, maxConnections);
376     CAmDatabaseObserver iObserver(&iCommandSender, &iRoutingSender, &iSocketHandler, &iTelnetServer);
377 #else /*WITH_TELNET*/
378     CAmDatabaseObserver iObserver(&iCommandSender,&iRoutingSender, &iSocketHandler);
379 #endif
380
381     iDatabaseHandler.registerObserver(&iObserver);
382
383     //startup all the Plugins and Interfaces
384     iControlSender.startupController(&iControlReceiver);
385     iCommandSender.startupInterfaces(&iCommandReceiver);
386     iRoutingSender.startupInterfaces(&iRoutingReceiver);
387
388     //when the routingInterface is done, all plugins are loaded:
389     iControlSender.setControllerReady();
390
391 #ifdef WITH_SYSTEMD_WATCHDOG
392     iWatchdog.startWatchdog();
393 #endif /*WITH_SYSTEMD_WATCHDOG*/
394
395     //start the mainloop here....
396     iSocketHandler.start_listenting();
397 }
398
399 /**
400  * main
401  * @param argc
402  * @param argv
403  * @return
404  */
405 int main(int argc, char *argv[], char** envp)
406 {
407     (void) envp;
408     listCommandPluginDirs.push_back(std::string(DEFAULT_PLUGIN_COMMAND_DIR));
409     listRoutingPluginDirs.push_back(std::string(DEFAULT_PLUGIN_ROUTING_DIR));
410
411     //parse the commandline options
412     parseCommandLine(argc, (char**) argv);
413
414     CAmDltWrapper::instance(enableNoDLTDebug)->registerApp("AudioManagerDeamon", "AudioManagerDeamon");
415     CAmDltWrapper::instance()->registerContext(AudioManager, "Main", "Main Context");
416     logInfo("The Audiomanager is started");
417     logInfo("The version of the Audiomanager", DAEMONVERSION);
418
419     //now the signal handler:
420     struct sigaction signalAction;
421     memset(&signalAction, '\0', sizeof(signalAction));
422     signalAction.sa_sigaction = &signalHandler;
423     signalAction.sa_flags = SA_SIGINFO;
424     sigaction(SIGINT, &signalAction, NULL);
425     sigaction(SIGQUIT, &signalAction, NULL);
426     sigaction(SIGTERM, &signalAction, NULL);
427     sigaction(SIGHUP, &signalAction, NULL);
428
429     struct sigaction signalChildAction;
430     memset(&signalChildAction, '\0', sizeof(signalChildAction));
431     signalChildAction.sa_flags = SA_NOCLDWAIT;
432     sigaction(SIGCHLD, &signalChildAction, NULL);
433
434     //register new out of memory handler
435     std::set_new_handler(&OutOfMemoryHandler);
436
437     try
438     {
439         //we do this to catch all exceptions and have a graceful ending just in case
440         mainProgram();
441     }
442
443     catch (std::exception& exc)
444     {
445         logError("The AudioManager ended by throwing the exception", exc.what());
446         std::cerr<<"The AudioManager ended by throwing an exception "<<exc.what()<<std::endl;
447         exit(EXIT_FAILURE);
448     }
449
450     close(fd0);
451     close(fd1);
452     close(fd2);
453
454     //deinit the DLT
455     CAmDltWrapper* inst(getWrapper());
456     inst->deinit();
457
458     exit(0);
459
460 }
461