* formatting all the source code with eclipse source code style
[profile/ivi/genivi/genivi-audio-manager.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 #include <config.h>
38 #include <SocketHandler.h>
39 #ifdef WITH_DBUS_WRAPPER
40 #include <dbus/DBusWrapper.h>
41 #endif
42 #include "DatabaseHandler.h"
43 #include "ControlSender.h"
44 #include "CommandSender.h"
45 #include "RoutingSender.h"
46 #include "RoutingReceiver.h"
47 #include "CommandReceiver.h"
48 #include "ControlReceiver.h"
49 #include "DatabaseObserver.h"
50 #include "TelnetServer.h"
51 #include <sys/resource.h>
52 #include <sys/stat.h>
53 #include <unistd.h>
54 #include <stdlib.h>
55 #include <cstdlib>
56 #include <assert.h>
57 #include <fcntl.h>
58 #include <signal.h>
59 #include <string.h>
60 #include <stdio.h>
61
62 #include <dlt/dlt.h>
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
90 void daemonize()
91 {
92     umask(0);
93     std::string dir = "/";
94
95     rlimit rl;
96     if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
97     {
98         DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("can't get file limit "));
99     }
100
101     pid_t pid;
102     if ((pid = fork()) < 0)
103     {
104         DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("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         DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("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     int fd0 = open("/dev/null", O_RDONLY);
129     int fd1 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
130     int 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         DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("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     DLT_LOG(AudioManager, DLT_LOG_ERROR, DLT_STRING("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     DLT_REGISTER_APP("AudioManagerDeamon", "AudioManagerDeamon");
219     DLT_REGISTER_CONTEXT(AudioManager, "Main", "Main Context");
220     DLT_LOG(AudioManager, DLT_LOG_INFO, DLT_STRING("The AudioManager is started, "), DLT_STRING(DAEMONVERSION));
221
222     listCommandPluginDirs.push_back(std::string(DEFAULT_PLUGIN_COMMAND_DIR));
223     listRoutingPluginDirs.push_back(std::string(DEFAULT_PLUGIN_ROUTING_DIR));
224
225     //parse the commandline options
226     parseCommandLine(argc, (char**) argv);
227
228     //now the signal handler:
229     struct sigaction signalAction;
230     memset(&signalAction, '\0', sizeof(signalAction));
231     signalAction.sa_sigaction = &signalHandler;
232     signalAction.sa_flags = SA_SIGINFO;
233     sigaction(SIGINT, &signalAction, NULL);
234     sigaction(SIGQUIT, &signalAction, NULL);
235     sigaction(SIGTERM, &signalAction, NULL);
236     sigaction(SIGHUP, &signalAction, NULL);
237     sigaction(SIGQUIT, &signalAction, NULL);
238
239     struct sigaction signalChildAction;
240     memset(&signalChildAction, '\0', sizeof(signalChildAction));
241     signalChildAction.sa_flags = SA_NOCLDWAIT;
242     sigaction(SIGCHLD, &signalChildAction, NULL);
243
244     //Instantiate all classes. Keep in same order !
245 #ifdef WITH_SOCKETHANDLER_LOOP
246     SocketHandler iSocketHandler;
247 #endif
248
249 #ifdef WITH_DBUS_WRAPPER
250 #ifdef WITH_SOCKETHANDLER_LOOP
251     DBusWrapper iDBusWrapper(&iSocketHandler);
252 #else /*WITH_SOCKETHANDLER_LOOP*/
253     DBusWrapper iDBusWrapper;
254 #endif /*WITH_SOCKETHANDLER_LOOP*/
255 #endif /*WITH_DBUS_WRAPPER */
256
257     DatabaseHandler iDatabaseHandler(databasePath);
258     RoutingSender iRoutingSender(listRoutingPluginDirs);
259     CommandSender iCommandSender(listCommandPluginDirs);
260     ControlSender iControlSender(controllerPlugin);
261
262 #ifdef WITH_DBUS_WRAPPER
263 #ifdef WITH_SOCKETHANDLER_LOOP
264     CommandReceiver iCommandReceiver(&iDatabaseHandler, &iControlSender, &iSocketHandler, &iDBusWrapper);
265     RoutingReceiver iRoutingReceiver(&iDatabaseHandler, &iRoutingSender, &iControlSender, &iSocketHandler, &iDBusWrapper);
266     ControlReceiver iControlReceiver(&iDatabaseHandler, &iRoutingSender, &iCommandSender, &iSocketHandler);
267 #ifdef WITH_TELNET
268     TelnetServer iTelnetServer(&iSocketHandler,&iCommandSender,&iCommandReceiver,&iRoutingSender,&iRoutingReceiver,&iControlSender,&iControlReceiver,&iDatabaseHandler,telnetport,maxConnections);
269 #endif
270 #else /*WITH_SOCKETHANDLER_LOOP */
271     CommandReceiver iCommandReceiver(&iDatabaseHandler,&iControlSender,&iDBusWrapper);
272     RoutingReceiver iRoutingReceiver(&iDatabaseHandler,&iRoutingSender,&iControlSender,&iDBusWrapper);
273     ControlReceiver iControlReceiver(&iDatabaseHandler,&iRoutingSender,&iCommandSender);
274 #endif /*WITH_SOCKETHANDLER_LOOP*/
275 #else /*WITH_DBUS_WRAPPER*/
276     CommandReceiver iCommandReceiver(&iDatabaseHandler,&iControlSender,&iSocketHandler);
277     RoutingReceiver iRoutingReceiver(&iDatabaseHandler,&iRoutingSender,&iControlSender,&iSocketHandler);
278     ControlReceiver iControlReceiver(&iDatabaseHandler,&iRoutingSender,&iCommandSender,&iSocketHandler);
279 #ifdef WITH_TELNET
280     TelnetServer iTelnetServer(&iSocketHandler,telnetport,maxConnections);
281 #endif
282 #endif /*WITH_DBUS_WRAPPER*/
283
284 #ifdef WITH_TELNET
285     DatabaseObserver iObserver(&iCommandSender, &iRoutingSender,&iTelnetServer);
286 #else
287     DatabaseObserver iObserver(&iCommandSender, &iRoutingSender);
288 #endif
289
290     //since the plugins have been loaded by the *Senders before, we can tell the Controller this:
291     iControlSender.hookAllPluginsLoaded();
292
293     //the controller should startup the interfaces - this is just for testing
294     iCommandSender.startupInterface(&iCommandReceiver);
295     iRoutingSender.startupRoutingInterface(&iRoutingReceiver);
296     iRoutingSender.routingInterfacesReady();
297
298 #ifdef WITH_SOCKETHANDLER_LOOP
299     iSocketHandler.start_listenting();
300 #endif /*WITH_SOCKETHANDLER_LOOP*/
301
302 #ifdef WITH_DBUS_WRAPPER
303 #ifdef WITH_SIMPLEDBUS_LOOP
304     iDBusWrapper.dbusMainLoop();
305 #endif/*WITH_SIMPLEDBUS_LOOP*/
306 #endif /*WITH_DBUS_WRAPPER*/
307
308     exit(0);
309
310 }
311