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