* [GAM-35] implement DBus for SESSION or SYSTEM bus
[profile/ivi/audiomanager.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 #ifdef WITH_DBUS_WRAPPER
36 #include <shared/CAmDbusWrapper.h>
37 #endif
38
39 #include <sys/resource.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42 #include <cstdlib>
43 #include <cstdlib>
44 #include <cassert>
45 #include <fcntl.h>
46 #include <csignal>
47 #include <cstring>
48 #include <cstdio>
49 #include <new>
50 #include "CAmRouter.h"
51 #include "CAmDatabaseHandler.h"
52 #include "CAmControlSender.h"
53 #include "CAmCommandSender.h"
54 #include "CAmRoutingSender.h"
55 #include "CAmRoutingReceiver.h"
56 #include "CAmCommandReceiver.h"
57 #include "CAmControlReceiver.h"
58 #include "CAmDatabaseObserver.h"
59 #include "shared/CAmDltWrapper.h"
60 #include "shared/CAmSocketHandler.h"
61
62
63 using namespace am;
64 DLT_DECLARE_CONTEXT(AudioManager)
65
66
67 const char* USAGE_DESCRIPTION = "Usage:\tAudioManagerDaemon [options]\n"
68         "options:\t\n"
69         "\t-h: print this message\t\n"
70         "\t-i: info about current settings \t\n"
71         "\t-v: print version\t\n"
72 #ifndef WITH_DLT
73         "\t-V: print DLT logs to stdout\t\n"
74 #endif
75         "\t-d: daemonize AudioManager \t\n"
76 #ifdef WITH_DBUS_WRAPPER
77         "\t-T: DbusType to be used by CAmDbusWrapper (0=DBUS_SESSION[default], 1=DBUS_SYSTEM)\t\n"
78 #endif
79         "\t-p<path> path for sqlite database (default is in memory)\t\n"
80         "\t-t<port> port for telnetconnection\t\n"
81         "\t-m<max> number of max telnetconnections\t\n"
82         "\t-c<Name> use controllerPlugin <Name> (full path with .so ending)\t\n"
83         "\t-l<Name> replace command plugin directory with <Name> (full path)\t\n"
84         "\t-r<Name> replace routing plugin directory with <Name> (full path)\t\n"
85         "\t-L<Name> add command plugin directory with <Name> (full path)\t\n"
86         "\t-R<Name> add routing plugin directory with <Name> (full path)\t\n";
87
88 std::string controllerPlugin = std::string(CONTROLLER_PLUGIN);
89 std::vector<std::string> listCommandPluginDirs;
90 std::vector<std::string> listRoutingPluginDirs;
91 std::string databasePath = std::string(":memory:");
92 unsigned int telnetport = DEFAULT_TELNETPORT;
93 unsigned int maxConnections = MAX_TELNETCONNECTIONS;
94 int fd0, fd1, fd2;
95 bool enableNoDLTDebug = false;
96
97 #ifdef WITH_DBUS_WRAPPER
98     DBusBusType dbusWrapperType=DBUS_BUS_SESSION;
99 #endif
100
101 /**
102  * the out of memory handler
103  */
104 void OutOfMemoryHandler()
105 {
106     logError("No more memory - bye");
107     //todo: add gracefull dead here. Do what can be done persistence wise
108     exit(1);
109 }
110
111 /**
112  * daemonizes the AudioManager
113  */
114 void daemonize()
115 {
116     umask(0);
117     std::string dir = "/";
118
119     rlimit rl;
120     if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
121     {
122         logError("can't get file limit ");
123     }
124
125     pid_t pid;
126     if ((pid = fork()) < 0)
127     {
128         logError("cannot fork!");
129     }
130     else if (pid != 0)
131     {
132         exit(0);
133     }
134
135     setsid();
136
137     if (!dir.empty() && chdir(dir.c_str()) < 0)
138     {
139         logError("couldn't chdir to the new directory");
140     }
141
142     if (rl.rlim_max == RLIM_INFINITY)
143     {
144         rl.rlim_max = 1024;
145     }
146
147     for (unsigned int i = 0; i < rl.rlim_max; i++)
148     {
149         close(i);
150     }
151
152     fd0 = open("/dev/null", O_RDONLY);
153     fd1 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
154     fd2 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
155
156     if (fd0 != STDIN_FILENO || fd1 != STDOUT_FILENO || fd2 != STDERR_FILENO)
157     {
158         logError("new standard file descriptors were not opened");
159     }
160 }
161
162 /**
163  * parses the command line
164  * @param argc
165  * @param argv
166  */
167 void parseCommandLine(int argc, char **argv)
168 {
169     while (optind < argc)
170     {
171 #ifdef WITH_DLT
172     #ifdef WITH_DBUS_WRAPPER
173             int option = getopt(argc, argv, "h::v::c::l::r::L::R::d::t::m::i::p::T::");
174     #else
175             int option = getopt(argc, argv, "h::v::c::l::r::L::R::d::t::m::i::p::");
176     #endif WITH_DBUS_WRAPPER
177 #else
178     #ifdef WITH_DBUS_WRAPPER
179             int option = getopt(argc, argv, "h::v::V::c::l::r::L::R::d::t::m::i::p::T::");
180     #else
181             int option = getopt(argc, argv, "h::v::V::c::l::r::L::R::d::t::m::i::p::");
182     #endif //WITH_DBUS_WRAPPER
183 #endif
184
185         switch (option)
186         {
187         case 'i':
188             printf("Current settings:\n");
189             printf("\tAudioManagerDaemon Version:\t\t%s\n", DAEMONVERSION);
190             printf("\tTelnet portNumber:\t\t\t%i\n", telnetport);
191             printf("\tTelnet maxConnections:\t\t\t%i\n", maxConnections);
192             printf("\tSqlite Database path:\t\t\t%s\n", databasePath.c_str());
193             printf("\tControllerPlugin: \t\t\t%s\n", controllerPlugin.c_str());
194             printf("\tDirectory of CommandPlugins: \t\t%s\n", listCommandPluginDirs.front().c_str());
195             printf("\tDirectory of RoutingPlugins: \t\t%s\n", listRoutingPluginDirs.front().c_str());
196             exit(0);
197             break;
198         case 't':
199             assert(atoi(optarg)!=0);
200             telnetport = atoi(optarg);
201             break;
202         case 'm':
203             assert(atoi(optarg)!=0);
204             maxConnections = atoi(optarg);
205             break;
206         case 'p':
207             assert(!controllerPlugin.empty());
208             databasePath = std::string(optarg);
209             break;
210         case 'd':
211             daemonize();
212             break;
213         case 'l':
214             listCommandPluginDirs.clear();
215             listCommandPluginDirs.push_back(std::string(optarg));
216             break;
217         case 'r':
218             listRoutingPluginDirs.clear();
219             listRoutingPluginDirs.push_back(std::string(optarg));
220             break;
221         case 'L':
222             listCommandPluginDirs.push_back(std::string(optarg));
223             break;
224         case 'R':
225             listRoutingPluginDirs.push_back(std::string(optarg));
226             break;
227         case 'c':
228             controllerPlugin = std::string(optarg);
229             assert(!controllerPlugin.empty());
230             assert(controllerPlugin.find(".so")!=std::string::npos);
231             break;
232         case 'v':
233             printf("AudioManagerDaemon Version: %s\n", DAEMONVERSION);
234             exit(-1);
235             break;
236 #ifndef WITH_DLT
237             case 'V':
238             printf("[DLT] debug output to stdout enabled\n");
239             enableNoDLTDebug = true;
240             break;
241 #endif
242 #ifdef WITH_DBUS_WRAPPER
243             case 'T':
244             dbusWrapperType=static_cast<DBusBusType>(atoi(optarg));
245             break;
246 #endif
247         case 'h':
248         default:
249             printf("AudioManagerDaemon Version: %s\n", DAEMONVERSION);
250             puts(USAGE_DESCRIPTION);
251             exit(-1);
252         }
253     }
254 }
255
256 /**
257  * the signal handler
258  * @param sig
259  * @param siginfo
260  * @param context
261  */
262 static void signalHandler(int sig, siginfo_t *siginfo, void *context)
263 {
264     (void) sig;
265     (void) siginfo;
266     (void) context;
267     logError("signal handler was called, exit now...");
268     gDispatchDone = 1;
269     //todo: maually fire the mainloop
270     exit(1);
271 }
272
273 /**
274  * main
275  * @param argc
276  * @param argv
277  * @return
278  */
279 int main(int argc, char *argv[])
280 {
281     listCommandPluginDirs.push_back(std::string(DEFAULT_PLUGIN_COMMAND_DIR));
282     listRoutingPluginDirs.push_back(std::string(DEFAULT_PLUGIN_ROUTING_DIR));
283
284     //parse the commandline options
285     parseCommandLine(argc, (char**) argv);
286
287     CAmDltWrapper::instance(enableNoDLTDebug)->registerApp("AudioManagerDeamon", "AudioManagerDeamon");
288     CAmDltWrapper::instance()->registerContext(AudioManager, "Main", "Main Context");
289     logInfo("The Audiomanager is started");
290     logInfo("The version of the Audiomanager", DAEMONVERSION);
291
292     //now the signal handler:
293     struct sigaction signalAction;
294     memset(&signalAction, '\0', sizeof(signalAction));
295     signalAction.sa_sigaction = &signalHandler;
296     signalAction.sa_flags = SA_SIGINFO;
297     sigaction(SIGINT, &signalAction, NULL);
298     sigaction(SIGQUIT, &signalAction, NULL);
299     sigaction(SIGTERM, &signalAction, NULL);
300     sigaction(SIGHUP, &signalAction, NULL);
301     sigaction(SIGQUIT, &signalAction, NULL);
302
303     struct sigaction signalChildAction;
304     memset(&signalChildAction, '\0', sizeof(signalChildAction));
305     signalChildAction.sa_flags = SA_NOCLDWAIT;
306     sigaction(SIGCHLD, &signalChildAction, NULL);
307
308     //register new out of memory handler
309     std::set_new_handler(&OutOfMemoryHandler);
310
311     //Instantiate all classes. Keep in same order !
312     CAmSocketHandler iSocketHandler;
313
314 #ifdef WITH_DBUS_WRAPPER
315     CAmDbusWrapper iDBusWrapper(&iSocketHandler,dbusWrapperType);
316 #endif /*WITH_DBUS_WRAPPER */
317
318     CAmDatabaseHandler iDatabaseHandler(databasePath);
319     CAmRoutingSender iRoutingSender(listRoutingPluginDirs);
320     CAmCommandSender iCommandSender(listCommandPluginDirs);
321     CAmControlSender iControlSender(controllerPlugin);
322     CAmRouter iRouter(&iDatabaseHandler, &iControlSender);
323
324 #ifdef WITH_DBUS_WRAPPER
325     CAmCommandReceiver iCommandReceiver(&iDatabaseHandler, &iControlSender, &iSocketHandler, &iDBusWrapper);
326     CAmRoutingReceiver iRoutingReceiver(&iDatabaseHandler, &iRoutingSender, &iControlSender, &iSocketHandler, &iDBusWrapper);
327     CAmControlReceiver iControlReceiver(&iDatabaseHandler, &iRoutingSender, &iCommandSender, &iSocketHandler, &iRouter);
328 #else /*WITH_DBUS_WRAPPER*/
329     CAmCommandReceiver iCommandReceiver(&iDatabaseHandler,&iControlSender,&iSocketHandler);
330     CAmRoutingReceiver iRoutingReceiver(&iDatabaseHandler,&iRoutingSender,&iControlSender,&iSocketHandler);
331     CAmControlReceiver iControlReceiver(&iDatabaseHandler,&iRoutingSender,&iCommandSender,&iSocketHandler, &iRouter);
332 #endif /*WITH_DBUS_WRAPPER*/
333
334 #ifdef WITH_TELNET
335     CAmTelnetServer iTelnetServer(&iSocketHandler, &iCommandSender, &iCommandReceiver, &iRoutingSender, &iRoutingReceiver, &iControlSender, &iControlReceiver, &iDatabaseHandler, &iRouter, telnetport, maxConnections);
336     CAmDatabaseObserver iObserver(&iCommandSender, &iRoutingSender, &iSocketHandler, &iTelnetServer);
337 #else /*WITH_TELNET*/
338     CAmDatabaseObserver iObserver(&iCommandSender,&iRoutingSender, &iSocketHandler);
339 #endif
340
341     iDatabaseHandler.registerObserver(&iObserver);
342
343     //startup all the Plugins and Interfaces
344     iControlSender.startupController(&iControlReceiver);
345     iCommandSender.startupInterfaces(&iCommandReceiver);
346     iRoutingSender.startupInterfaces(&iRoutingReceiver);
347
348     //when the routingInterface is done, all plugins are loaded:
349     iControlSender.setControllerReady();
350
351     //start the mainloop here....
352     iSocketHandler.start_listenting();
353
354     close(fd0);
355     close(fd1);
356     close(fd2);
357     exit(0);
358
359 }
360