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