48b00a77a30292610ebb77b98cb96dd12a65d01c
[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 <sys/resource.h>
54 #include <sys/stat.h>
55 #include <unistd.h>
56 #include <stdlib.h>
57 #include <cstdlib>
58 #include <assert.h>
59 #include <fcntl.h>
60 #include <signal.h>
61 #include <string.h>
62 #include <stdio.h>
63
64 #include <dlt/dlt.h>
65
66 DLT_DECLARE_CONTEXT(AudioManager)
67
68 using namespace am;
69
70 const char* USAGE_DESCRIPTION = "Usage:\tAudioManagerDaemon [options]\n"
71         "options:\t\n"
72         "\t-h: print this message\t\n"
73         "\t-i: info about current settings \t\n"
74         "\t-v: print version\t\n"
75         "\t-d: daemonize AudioManager \t\n"
76         "\t-p<path> path for sqlite database (default is in memory)\t\n"
77         "\t-t<port> port for telnetconnection\t\n"
78         "\t-m<max> number of max telnetconnections\t\n"
79         "\t-c<Name> use controllerPlugin <Name> (full path with .so ending)\t\n"
80         "\t-l<Name> replace command plugin directory with <Name> (full path)\t\n"
81         "\t-r<Name> replace routing plugin directory with <Name> (full path)\t\n"
82         "\t-L<Name> add command plugin directory with <Name> (full path)\t\n"
83         "\t-R<Name> add routing plugin directory with <Name> (full path)\t\n";
84
85 std::string controllerPlugin = std::string(CONTROLLER_PLUGIN);
86 std::vector<std::string> listCommandPluginDirs;
87 std::vector<std::string> listRoutingPluginDirs;
88 std::string databasePath = std::string(":memory:");
89 unsigned int telnetport = DEFAULT_TELNETPORT;
90 unsigned int maxConnections = MAX_TELNETCONNECTIONS;
91 int fd0, fd1, fd2;
92
93 void daemonize()
94 {
95     umask(0);
96     std::string dir = "/";
97
98     rlimit rl;
99     if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
100     {
101         DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("can't get file limit "));
102     }
103
104     pid_t pid;
105     if ((pid = fork()) < 0)
106     {
107         DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("cannot fork!"));
108     }
109     else if (pid != 0)
110     {
111         exit(0);
112     }
113
114     setsid();
115
116     if (!dir.empty() && chdir(dir.c_str()) < 0)
117     {
118         DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("couldn't chdir to the new directory"));
119     }
120
121     if (rl.rlim_max == RLIM_INFINITY)
122     {
123         rl.rlim_max = 1024;
124     }
125
126     for (unsigned int i = 0; i < rl.rlim_max; i++)
127     {
128         close(i);
129     }
130
131     fd0 = open("/dev/null", O_RDONLY);
132     fd1 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
133     fd2 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
134
135     if (fd0 != STDIN_FILENO || fd1 != STDOUT_FILENO || fd2 != STDERR_FILENO)
136     {
137         DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("new standard file descriptors were not opened"));
138     }
139 }
140
141 void parseCommandLine(int argc, char **argv)
142 {
143     while (optind < argc)
144     {
145         int option = getopt(argc, argv, "h::v::c::l::r::L::R::d::t::m::i::p::");
146
147         switch (option)
148         {
149         case 'i':
150             printf("Current settings:\n");
151             printf("\tAudioManagerDaemon Version:\t\t%s\n", DAEMONVERSION);
152             printf("\tTelnet portNumber:\t\t\t%i\n", telnetport);
153             printf("\tTelnet maxConnections:\t\t\t%i\n", maxConnections);
154             printf("\tSqlite Database path:\t\t\t%s\n", databasePath.c_str());
155             printf("\tControllerPlugin: \t\t\t%s\n", controllerPlugin.c_str());
156             printf("\tDirectory of CommandPlugins: \t\t%s\n", listCommandPluginDirs.front().c_str());
157             printf("\tDirectory of RoutingPlugins: \t\t%s\n", listRoutingPluginDirs.front().c_str());
158             exit(0);
159             break;
160         case 't':
161             assert(atoi(optarg)!=0);
162             telnetport = atoi(optarg);
163             break;
164         case 'm':
165             assert(atoi(optarg)!=0);
166             maxConnections = atoi(optarg);
167             break;
168         case 'p':
169             assert(!controllerPlugin.empty());
170             databasePath = std::string(optarg);
171             break;
172         case 'd':
173             daemonize();
174             break;
175         case 'l':
176             listCommandPluginDirs.clear();
177             listCommandPluginDirs.push_back(std::string(optarg));
178             break;
179         case 'r':
180             listRoutingPluginDirs.clear();
181             listRoutingPluginDirs.push_back(std::string(optarg));
182             break;
183         case 'L':
184             listCommandPluginDirs.push_back(std::string(optarg));
185             break;
186         case 'R':
187             listRoutingPluginDirs.push_back(std::string(optarg));
188             break;
189         case 'c':
190             controllerPlugin = std::string(optarg);
191             assert(!controllerPlugin.empty());
192             assert(controllerPlugin.find(".so")!=std::string::npos);
193             break;
194         case 'v':
195             printf("AudioManagerDaemon Version: %s\n", DAEMONVERSION);
196             exit(-1);
197             break;
198         case 'h':
199         default:
200             printf("AudioManagerDaemon Version: %s\n", DAEMONVERSION);
201             puts(USAGE_DESCRIPTION);
202             exit(-1);
203         }
204     }
205 }
206
207 static void signalHandler(int sig, siginfo_t *siginfo, void *context)
208 {
209     (void) sig;
210     (void) siginfo;
211     (void) context;
212     DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("signal handler was called, exit now..."));
213     gDispatchDone = 1;
214     //todo: maually fire the mainloop
215     //todo: ifdef no sockethandler
216     exit(1);
217 }
218
219 int main(int argc, char *argv[])
220 {
221     DLT_REGISTER_APP("AudioManagerDeamon", "AudioManagerDeamon");
222     DLT_REGISTER_CONTEXT(AudioManager, "Main", "Main Context");
223     DLT_LOG(AudioManager, DLT_LOG_INFO, DLT_STRING("The AudioManager is started, "), DLT_STRING(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