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