* add setSinkVolume to telnetserver
[profile/ivi/audiomanager.git] / AudioManagerDaemon / src / main.cpp
1 /**
2  * Copyright (C) 2012, BMW AG
3  *
4  * This file is part of GENIVI Project AudioManager.
5  *
6  * Contributions are licensed to the GENIVI Alliance under one or more
7  * Contribution License Agreements.
8  *
9  * \copyright
10  * This Source Code Form is subject to the terms of the
11  * Mozilla Public License, v. 2.0. If a  copy of the MPL was not distributed with
12  * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
13  *
14  *
15  * \author Christian Mueller, christian.ei.mueller@bmw.de BMW 2011,2012
16  * \author Frank Herchet, frank.fh.herchet@bmw.de BMW 2012
17  *
18  * \file main.cpp
19  * For further information see http://www.genivi.org/.
20  *
21  */
22
23 /**
24  * \todo create systemd compatibility
25  * \todo all communication like all plugins loaded etc...
26  * \todo check the startup sequence. Dbus shall be activated last...
27  * \bug package generation only works if package directory exists...
28  */
29
30 #include "config.h"
31
32 #ifdef  WITH_TELNET
33 #include "CAmTelnetServer.h"
34 #endif
35 #ifdef WITH_DBUS_WRAPPER
36 #include <shared/CAmDbusWrapper.h>
37 #endif
38
39 #include <sys/resource.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42 #include <cstdlib>
43 #include <cstdlib>
44 #include <cassert>
45 #include <fcntl.h>
46 #include <csignal>
47 #include <cstring>
48 #include <cstdio>
49 #include <new>
50 #include "CAmRouter.h"
51 #include "CAmDatabaseHandler.h"
52 #include "CAmControlSender.h"
53 #include "CAmCommandSender.h"
54 #include "CAmRoutingSender.h"
55 #include "CAmRoutingReceiver.h"
56 #include "CAmCommandReceiver.h"
57 #include "CAmControlReceiver.h"
58 #include "CAmDatabaseObserver.h"
59 #include "shared/CAmDltWrapper.h"
60 #include "shared/CAmSocketHandler.h"
61
62
63 using namespace am;
64 DLT_DECLARE_CONTEXT(AudioManager)
65
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 #ifndef WITH_DLT
73         "\t-V: print DLT logs to stdout\t\n"
74 #endif
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 bool enableNoDLTDebug = false;
93
94 /**
95  * the out of memory handler
96  */
97 void OutOfMemoryHandler()
98 {
99     logError("No more memory - bye");
100     //todo: add gracefull dead here. Do what can be done persistence wise
101     exit(1);
102 }
103
104 /**
105  * daemonizes the AudioManager
106  */
107 void daemonize()
108 {
109     umask(0);
110     std::string dir = "/";
111
112     rlimit rl;
113     if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
114     {
115         logError("can't get file limit ");
116     }
117
118     pid_t pid;
119     if ((pid = fork()) < 0)
120     {
121         logError("cannot fork!");
122     }
123     else if (pid != 0)
124     {
125         exit(0);
126     }
127
128     setsid();
129
130     if (!dir.empty() && chdir(dir.c_str()) < 0)
131     {
132         logError("couldn't chdir to the new directory");
133     }
134
135     if (rl.rlim_max == RLIM_INFINITY)
136     {
137         rl.rlim_max = 1024;
138     }
139
140     for (unsigned int i = 0; i < rl.rlim_max; i++)
141     {
142         close(i);
143     }
144
145     fd0 = open("/dev/null", O_RDONLY);
146     fd1 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
147     fd2 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
148
149     if (fd0 != STDIN_FILENO || fd1 != STDOUT_FILENO || fd2 != STDERR_FILENO)
150     {
151         logError("new standard file descriptors were not opened");
152     }
153 }
154
155 /**
156  * parses the command line
157  * @param argc
158  * @param argv
159  */
160 void parseCommandLine(int argc, char **argv)
161 {
162     while (optind < argc)
163     {
164 #ifdef WITH_DLT
165         int option = getopt(argc, argv, "h::v::c::l::r::L::R::d::t::m::i::p::");
166 #else
167         int option = getopt(argc, argv, "h::v::V::c::l::r::L::R::d::t::m::i::p::");
168 #endif
169
170         switch (option)
171         {
172         case 'i':
173             printf("Current settings:\n");
174             printf("\tAudioManagerDaemon Version:\t\t%s\n", DAEMONVERSION);
175             printf("\tTelnet portNumber:\t\t\t%i\n", telnetport);
176             printf("\tTelnet maxConnections:\t\t\t%i\n", maxConnections);
177             printf("\tSqlite Database path:\t\t\t%s\n", databasePath.c_str());
178             printf("\tControllerPlugin: \t\t\t%s\n", controllerPlugin.c_str());
179             printf("\tDirectory of CommandPlugins: \t\t%s\n", listCommandPluginDirs.front().c_str());
180             printf("\tDirectory of RoutingPlugins: \t\t%s\n", listRoutingPluginDirs.front().c_str());
181             exit(0);
182             break;
183         case 't':
184             assert(atoi(optarg)!=0);
185             telnetport = atoi(optarg);
186             break;
187         case 'm':
188             assert(atoi(optarg)!=0);
189             maxConnections = atoi(optarg);
190             break;
191         case 'p':
192             assert(!controllerPlugin.empty());
193             databasePath = std::string(optarg);
194             break;
195         case 'd':
196             daemonize();
197             break;
198         case 'l':
199             listCommandPluginDirs.clear();
200             listCommandPluginDirs.push_back(std::string(optarg));
201             break;
202         case 'r':
203             listRoutingPluginDirs.clear();
204             listRoutingPluginDirs.push_back(std::string(optarg));
205             break;
206         case 'L':
207             listCommandPluginDirs.push_back(std::string(optarg));
208             break;
209         case 'R':
210             listRoutingPluginDirs.push_back(std::string(optarg));
211             break;
212         case 'c':
213             controllerPlugin = std::string(optarg);
214             assert(!controllerPlugin.empty());
215             assert(controllerPlugin.find(".so")!=std::string::npos);
216             break;
217         case 'v':
218             printf("AudioManagerDaemon Version: %s\n", DAEMONVERSION);
219             exit(-1);
220             break;
221 #ifndef WITH_DLT
222             case 'V':
223             printf("[DLT] debug output to stdout enabled\n");
224             enableNoDLTDebug = true;
225             break;
226 #endif
227         case 'h':
228         default:
229             printf("AudioManagerDaemon Version: %s\n", DAEMONVERSION);
230             puts(USAGE_DESCRIPTION);
231             exit(-1);
232         }
233     }
234 }
235
236 /**
237  * the signal handler
238  * @param sig
239  * @param siginfo
240  * @param context
241  */
242 static void signalHandler(int sig, siginfo_t *siginfo, void *context)
243 {
244     (void) sig;
245     (void) siginfo;
246     (void) context;
247     logError("signal handler was called, exit now...");
248     gDispatchDone = 1;
249     //todo: maually fire the mainloop
250     exit(1);
251 }
252
253 /**
254  * main
255  * @param argc
256  * @param argv
257  * @return
258  */
259 int main(int argc, char *argv[])
260 {
261     listCommandPluginDirs.push_back(std::string(DEFAULT_PLUGIN_COMMAND_DIR));
262     listRoutingPluginDirs.push_back(std::string(DEFAULT_PLUGIN_ROUTING_DIR));
263
264     //parse the commandline options
265     parseCommandLine(argc, (char**) argv);
266
267     CAmDltWrapper::instance(enableNoDLTDebug)->registerApp("AudioManagerDeamon", "AudioManagerDeamon");
268     CAmDltWrapper::instance()->registerContext(AudioManager, "Main", "Main Context");
269     logInfo("The Audiomanager is started");
270     logInfo("The version of the Audiomanager", DAEMONVERSION);
271
272     //now the signal handler:
273     struct sigaction signalAction;
274     memset(&signalAction, '\0', sizeof(signalAction));
275     signalAction.sa_sigaction = &signalHandler;
276     signalAction.sa_flags = SA_SIGINFO;
277     sigaction(SIGINT, &signalAction, NULL);
278     sigaction(SIGQUIT, &signalAction, NULL);
279     sigaction(SIGTERM, &signalAction, NULL);
280     sigaction(SIGHUP, &signalAction, NULL);
281     sigaction(SIGQUIT, &signalAction, NULL);
282
283     struct sigaction signalChildAction;
284     memset(&signalChildAction, '\0', sizeof(signalChildAction));
285     signalChildAction.sa_flags = SA_NOCLDWAIT;
286     sigaction(SIGCHLD, &signalChildAction, NULL);
287
288     //register new out of memory handler
289     std::set_new_handler(&OutOfMemoryHandler);
290
291     //Instantiate all classes. Keep in same order !
292     CAmSocketHandler iSocketHandler;
293
294 #ifdef WITH_DBUS_WRAPPER
295     CAmDbusWrapper iDBusWrapper(&iSocketHandler);
296 #endif /*WITH_DBUS_WRAPPER */
297
298     CAmDatabaseHandler iDatabaseHandler(databasePath);
299     CAmRoutingSender iRoutingSender(listRoutingPluginDirs);
300     CAmCommandSender iCommandSender(listCommandPluginDirs);
301     CAmControlSender iControlSender(controllerPlugin);
302     CAmRouter iRouter(&iDatabaseHandler, &iControlSender);
303
304 #ifdef WITH_DBUS_WRAPPER
305     CAmCommandReceiver iCommandReceiver(&iDatabaseHandler, &iControlSender, &iSocketHandler, &iDBusWrapper);
306     CAmRoutingReceiver iRoutingReceiver(&iDatabaseHandler, &iRoutingSender, &iControlSender, &iSocketHandler, &iDBusWrapper);
307     CAmControlReceiver iControlReceiver(&iDatabaseHandler, &iRoutingSender, &iCommandSender, &iSocketHandler, &iRouter);
308 #else /*WITH_DBUS_WRAPPER*/
309     CAmCommandReceiver iCommandReceiver(&iDatabaseHandler,&iControlSender,&iSocketHandler);
310     CAmRoutingReceiver iRoutingReceiver(&iDatabaseHandler,&iRoutingSender,&iControlSender,&iSocketHandler);
311     ControlReceiver iControlReceiver(&iDatabaseHandler,&iRoutingSender,&iCommandSender,&iSocketHandler, &iRouter);
312 #endif /*WITH_DBUS_WRAPPER*/
313
314 #ifdef WITH_TELNET
315     CAmTelnetServer iTelnetServer(&iSocketHandler, &iCommandSender, &iCommandReceiver, &iRoutingSender, &iRoutingReceiver, &iControlSender, &iControlReceiver, &iDatabaseHandler, &iRouter, telnetport, maxConnections);
316     CAmDatabaseObserver iObserver(&iCommandSender, &iRoutingSender, &iSocketHandler, &iTelnetServer);
317 #else /*WITH_TELNET*/
318     CAmDatabaseObserver iObserver(&iCommandSender,&iRoutingSender, &iSocketHandler);
319 #endif
320
321     iDatabaseHandler.registerObserver(&iObserver);
322
323     //startup all the Plugins and Interfaces
324     iControlSender.startupController(&iControlReceiver);
325     iCommandSender.startupInterfaces(&iCommandReceiver);
326     iRoutingSender.startupInterfaces(&iRoutingReceiver);
327
328     //when the routingInterface is done, all plugins are loaded:
329     iControlSender.setControllerReady();
330
331     //start the mainloop here....
332     iSocketHandler.start_listenting();
333
334     close(fd0);
335     close(fd1);
336     close(fd2);
337     exit(0);
338
339 }
340