* wrapping DLT calls in a new Class because of performance, codesize and lazyness...
[profile/ivi/audiomanager.git] / AudioManagerDaemon / src / main.cpp
1 /**
2  * Copyright (C) 2011, BMW AG
3  *
4  * GeniviAudioMananger AudioManagerDaemon
5  *
6  * \file main.cpp
7  *
8  * \date 20-Oct-2011 3:42:04 PM
9  * \author Christian Mueller (christian.ei.mueller@bmw.de)
10  *
11  * \section License
12  * GNU Lesser General Public License, version 2.1, with special exception (GENIVI clause)
13  * Copyright (C) 2011, BMW AG Christian Mueller  Christian.ei.mueller@bmw.de
14  *
15  * This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 2.1, as published by the Free Software Foundation.
16  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License, version 2.1, for more details.
17  * You should have received a copy of the GNU Lesser General Public License, version 2.1, along with this program; if not, see <http://www.gnu.org/licenses/lgpl-2.1.html>.
18  * Note that the copyright holders assume that the GNU Lesser General Public License, version 2.1, may also be applicable to programs even in cases in which the program is not a library in the technical sense.
19  * Linking AudioManager statically or dynamically with other modules is making a combined work based on AudioManager. You may license such other modules under the GNU Lesser General Public License, version 2.1. If you do not want to license your linked modules under the GNU Lesser General Public License, version 2.1, you may use the program under the following exception.
20  * As a special exception, the copyright holders of AudioManager give you permission to combine AudioManager with software programs or libraries that are released under any license unless such a combination is not permitted by the license of such a software program or library. You may copy and distribute such a system following the terms of the GNU Lesser General Public License, version 2.1, including this special exception, for AudioManager and the licenses of the other code concerned.
21  * Note that people who make modified versions of AudioManager are not obligated to grant this special exception for their modified versions; it is their choice whether to do so. The GNU Lesser General Public License, version 2.1, gives permission to release a modified version without this exception; this exception also makes it possible to release a modified version which carries forward this exception.
22  *
23  */
24
25 /**
26  * Please make sure to have read the documentation on genivi.org!
27  */
28
29 //todo: make real daemon out of it- systemd conform
30 //todo: versioning of PluginInterfaces on linux level (.symver stuff)
31 //todo: all communication like all plugins loaded etc...
32 //todo: seperate documentation of test from normal project
33 //todo: check the startup sequence. Dbus shall be activated last...
34 //todo: there is a bug in the visible flags of sinks and sources. fix it.
35 //todo: make sure that iterators have a fixed end to prevent crashed while adding vectors while iterating on critical vectors
36 //todo: make sure all configurations are tested
37 //todo: clean up startup sequences controller, command and routing interfaces----
38 #include <config.h>
39 #include <SocketHandler.h>
40 #ifdef WITH_DBUS_WRAPPER
41 #include <dbus/DBusWrapper.h>
42 #endif
43 #include "DatabaseHandler.h"
44 #include "ControlSender.h"
45 #include "CommandSender.h"
46 #include "RoutingSender.h"
47 #include "RoutingReceiver.h"
48 #include "CommandReceiver.h"
49 #include "ControlReceiver.h"
50 #include "DatabaseObserver.h"
51 #include "TelnetServer.h"
52 #include "Router.h"
53 #include "DLTWrapper.h"
54 #include <sys/resource.h>
55 #include <sys/stat.h>
56 #include <unistd.h>
57 #include <stdlib.h>
58 #include <cstdlib>
59 #include <assert.h>
60 #include <fcntl.h>
61 #include <signal.h>
62 #include <string.h>
63 #include <stdio.h>
64
65 DLT_DECLARE_CONTEXT(AudioManager)
66
67 using namespace am;
68
69 const char* USAGE_DESCRIPTION = "Usage:\tAudioManagerDaemon [options]\n"
70         "options:\t\n"
71         "\t-h: print this message\t\n"
72         "\t-i: info about current settings \t\n"
73         "\t-v: print version\t\n"
74         "\t-d: daemonize AudioManager \t\n"
75         "\t-p<path> path for sqlite database (default is in memory)\t\n"
76         "\t-t<port> port for telnetconnection\t\n"
77         "\t-m<max> number of max telnetconnections\t\n"
78         "\t-c<Name> use controllerPlugin <Name> (full path with .so ending)\t\n"
79         "\t-l<Name> replace command plugin directory with <Name> (full path)\t\n"
80         "\t-r<Name> replace routing plugin directory with <Name> (full path)\t\n"
81         "\t-L<Name> add command plugin directory with <Name> (full path)\t\n"
82         "\t-R<Name> add routing plugin directory with <Name> (full path)\t\n";
83
84 std::string controllerPlugin = std::string(CONTROLLER_PLUGIN);
85 std::vector<std::string> listCommandPluginDirs;
86 std::vector<std::string> listRoutingPluginDirs;
87 std::string databasePath = std::string(":memory:");
88 unsigned int telnetport = DEFAULT_TELNETPORT;
89 unsigned int maxConnections = MAX_TELNETCONNECTIONS;
90 int fd0, fd1, fd2;
91
92 void daemonize()
93 {
94     umask(0);
95     std::string dir = "/";
96
97     rlimit rl;
98     if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
99     {
100         logError("can't get file limit ");
101     }
102
103     pid_t pid;
104     if ((pid = fork()) < 0)
105     {
106         logError("cannot fork!");
107     }
108     else if (pid != 0)
109     {
110         exit(0);
111     }
112
113     setsid();
114
115     if (!dir.empty() && chdir(dir.c_str()) < 0)
116     {
117         logError("couldn't chdir to the new directory");
118     }
119
120     if (rl.rlim_max == RLIM_INFINITY)
121     {
122         rl.rlim_max = 1024;
123     }
124
125     for (unsigned int i = 0; i < rl.rlim_max; i++)
126     {
127         close(i);
128     }
129
130     fd0 = open("/dev/null", O_RDONLY);
131     fd1 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
132     fd2 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
133
134     if (fd0 != STDIN_FILENO || fd1 != STDOUT_FILENO || fd2 != STDERR_FILENO)
135     {
136         logError("new standard file descriptors were not opened");
137     }
138 }
139
140 void parseCommandLine(int argc, char **argv)
141 {
142     while (optind < argc)
143     {
144         int option = getopt(argc, argv, "h::v::c::l::r::L::R::d::t::m::i::p::");
145
146         switch (option)
147         {
148         case 'i':
149             printf("Current settings:\n");
150             printf("\tAudioManagerDaemon Version:\t\t%s\n", DAEMONVERSION);
151             printf("\tTelnet portNumber:\t\t\t%i\n", telnetport);
152             printf("\tTelnet maxConnections:\t\t\t%i\n", maxConnections);
153             printf("\tSqlite Database path:\t\t\t%s\n", databasePath.c_str());
154             printf("\tControllerPlugin: \t\t\t%s\n", controllerPlugin.c_str());
155             printf("\tDirectory of CommandPlugins: \t\t%s\n", listCommandPluginDirs.front().c_str());
156             printf("\tDirectory of RoutingPlugins: \t\t%s\n", listRoutingPluginDirs.front().c_str());
157             exit(0);
158             break;
159         case 't':
160             assert(atoi(optarg)!=0);
161             telnetport = atoi(optarg);
162             break;
163         case 'm':
164             assert(atoi(optarg)!=0);
165             maxConnections = atoi(optarg);
166             break;
167         case 'p':
168             assert(!controllerPlugin.empty());
169             databasePath = std::string(optarg);
170             break;
171         case 'd':
172             daemonize();
173             break;
174         case 'l':
175             listCommandPluginDirs.clear();
176             listCommandPluginDirs.push_back(std::string(optarg));
177             break;
178         case 'r':
179             listRoutingPluginDirs.clear();
180             listRoutingPluginDirs.push_back(std::string(optarg));
181             break;
182         case 'L':
183             listCommandPluginDirs.push_back(std::string(optarg));
184             break;
185         case 'R':
186             listRoutingPluginDirs.push_back(std::string(optarg));
187             break;
188         case 'c':
189             controllerPlugin = std::string(optarg);
190             assert(!controllerPlugin.empty());
191             assert(controllerPlugin.find(".so")!=std::string::npos);
192             break;
193         case 'v':
194             printf("AudioManagerDaemon Version: %s\n", DAEMONVERSION);
195             exit(-1);
196             break;
197         case 'h':
198         default:
199             printf("AudioManagerDaemon Version: %s\n", DAEMONVERSION);
200             puts(USAGE_DESCRIPTION);
201             exit(-1);
202         }
203     }
204 }
205
206 static void signalHandler(int sig, siginfo_t *siginfo, void *context)
207 {
208     (void) sig;
209     (void) siginfo;
210     (void) context;
211     logError("signal handler was called, exit now...");
212     gDispatchDone = 1;
213     //todo: maually fire the mainloop
214     //todo: ifdef no sockethandler
215     exit(1);
216 }
217
218 int main(int argc, char *argv[])
219 {
220     DLTWrapper::instance()->registerApp("AudioManagerDeamon", "AudioManagerDeamon");
221     DLTWrapper::instance()->registerContext(AudioManager,"Main", "Main Context");
222     logInfo("The Audiomanager is started");
223     log(&AudioManager,DLT_LOG_ERROR,"The version of the Audiomanager",DAEMONVERSION);
224
225     listCommandPluginDirs.push_back(std::string(DEFAULT_PLUGIN_COMMAND_DIR));
226     listRoutingPluginDirs.push_back(std::string(DEFAULT_PLUGIN_ROUTING_DIR));
227
228     //parse the commandline options
229     parseCommandLine(argc, (char**) argv);
230
231     //now the signal handler:
232     struct sigaction signalAction;
233     memset(&signalAction, '\0', sizeof(signalAction));
234     signalAction.sa_sigaction = &signalHandler;
235     signalAction.sa_flags = SA_SIGINFO;
236     sigaction(SIGINT, &signalAction, NULL);
237     sigaction(SIGQUIT, &signalAction, NULL);
238     sigaction(SIGTERM, &signalAction, NULL);
239     sigaction(SIGHUP, &signalAction, NULL);
240     sigaction(SIGQUIT, &signalAction, NULL);
241
242     struct sigaction signalChildAction;
243     memset(&signalChildAction, '\0', sizeof(signalChildAction));
244     signalChildAction.sa_flags = SA_NOCLDWAIT;
245     sigaction(SIGCHLD, &signalChildAction, NULL);
246
247     //Instantiate all classes. Keep in same order !
248 #ifdef WITH_SOCKETHANDLER_LOOP
249     SocketHandler iSocketHandler;
250 #endif
251
252 #ifdef WITH_DBUS_WRAPPER
253 #ifdef WITH_SOCKETHANDLER_LOOP
254     DBusWrapper iDBusWrapper(&iSocketHandler);
255 #else /*WITH_SOCKETHANDLER_LOOP*/
256     DBusWrapper iDBusWrapper;
257 #endif /*WITH_SOCKETHANDLER_LOOP*/
258 #endif /*WITH_DBUS_WRAPPER */
259
260     DatabaseHandler iDatabaseHandler(databasePath);
261     RoutingSender iRoutingSender(listRoutingPluginDirs);
262     CommandSender iCommandSender(listCommandPluginDirs);
263     ControlSender iControlSender(controllerPlugin);
264     Router iRouter(&iDatabaseHandler, &iControlSender);
265
266 #ifdef WITH_DBUS_WRAPPER
267 #ifdef WITH_SOCKETHANDLER_LOOP
268     CommandReceiver iCommandReceiver(&iDatabaseHandler, &iControlSender, &iSocketHandler, &iDBusWrapper);
269     RoutingReceiver iRoutingReceiver(&iDatabaseHandler, &iRoutingSender, &iControlSender, &iSocketHandler, &iDBusWrapper);
270     ControlReceiver iControlReceiver(&iDatabaseHandler, &iRoutingSender, &iCommandSender, &iSocketHandler, &iRouter);
271 #ifdef WITH_TELNET
272     TelnetServer iTelnetServer(&iSocketHandler,&iCommandSender,&iCommandReceiver,&iRoutingSender,&iRoutingReceiver,&iControlSender,&iControlReceiver,&iDatabaseHandler,telnetport,maxConnections);
273 #endif
274 #else /*WITH_SOCKETHANDLER_LOOP */
275     CommandReceiver iCommandReceiver(&iDatabaseHandler,&iControlSender,&iDBusWrapper);
276     RoutingReceiver iRoutingReceiver(&iDatabaseHandler,&iRoutingSender,&iControlSender,&iDBusWrapper);
277     ControlReceiver iControlReceiver(&iDatabaseHandler,&iRoutingSender,&iCommandSender, &iRouter);
278 #endif /*WITH_SOCKETHANDLER_LOOP*/
279 #else /*WITH_DBUS_WRAPPER*/
280     CommandReceiver iCommandReceiver(&iDatabaseHandler,&iControlSender,&iSocketHandler);
281     RoutingReceiver iRoutingReceiver(&iDatabaseHandler,&iRoutingSender,&iControlSender,&iSocketHandler);
282     ControlReceiver iControlReceiver(&iDatabaseHandler,&iRoutingSender,&iCommandSender,&iSocketHandler, &iRouter);
283 #ifdef WITH_TELNET
284     TelnetServer iTelnetServer(&iSocketHandler,telnetport,maxConnections);
285 #endif
286 #endif /*WITH_DBUS_WRAPPER*/
287
288 #ifdef WITH_TELNET
289     DatabaseObserver iObserver(&iCommandSender, &iRoutingSender,&iTelnetServer);
290 #else
291     DatabaseObserver iObserver(&iCommandSender, &iRoutingSender);
292 #endif
293
294     //since the plugins have been loaded by the *Senders before, we can tell the Controller this:
295     iControlSender.hookAllPluginsLoaded();
296
297     //the controller should startup the interfaces - this is just for testing
298     iCommandSender.startupInterface(&iCommandReceiver);
299     iRoutingSender.startupRoutingInterface(&iRoutingReceiver);
300     iRoutingSender.routingInterfacesReady();
301
302 #ifdef WITH_SOCKETHANDLER_LOOP
303     iSocketHandler.start_listenting();
304 #endif /*WITH_SOCKETHANDLER_LOOP*/
305
306 #ifdef WITH_DBUS_WRAPPER
307 #ifdef WITH_SIMPLEDBUS_LOOP
308     iDBusWrapper.dbusMainLoop();
309 #endif/*WITH_SIMPLEDBUS_LOOP*/
310 #endif /*WITH_DBUS_WRAPPER*/
311
312     close(fd0);
313     close(fd1);
314     close(fd2);
315     exit(0);
316
317 }
318