]> git.vomp.tv Git - vompclient.git/blob - main.cc
Server address/port to config. Clean up VConnect
[vompclient.git] / main.cc
1 /*
2     Copyright 2004-2021 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <signal.h>
24
25 // For open
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29
30 #include <thread>
31 #include <string>
32
33 #ifndef WIN32
34   #include <unistd.h>
35   #include <endian.h>
36 #endif
37
38 #include "defines.h"
39
40 #ifdef HANDLE_VT_SWITCHING
41   #include <sys/ioctl.h>
42   #include <linux/vt.h>
43 #endif
44
45 #include "config.h"
46 #include "log.h"
47 #include "util.h"
48 #include "control.h"
49
50 #ifdef VOMP_PLATTFORM_NMT
51   #include "lednmt.h"
52   #include "osddirectfb.h"
53   #include "audionmt.h"
54   #include "videonmt.h"
55 #endif
56
57
58 #ifndef WIN32 // FIXME do we need any if WIN32 stuff in here? windows has own winmain file
59 void threadSignalReceiverFunction();
60 #endif
61
62 [[ noreturn ]] void shutdown(int code);
63
64 Config* config;
65 LogNT* loggerNT;
66 Control* control;
67
68 #ifdef HANDLE_VT_SWITCHING
69 int fdtty;
70 struct vt_mode old_vtmode;
71 #endif
72
73 static const char* TAG = "Main";
74
75 // Linux main function and sighandler
76 #ifndef WIN32
77 int main(int argc, char** argv)
78 {
79   bool crashed = false;
80
81   config = new Config();
82   if (!config->loadFile())
83   {
84     printf("Parse error in config.json\n");
85     shutdown(1);
86   }
87
88   int c;
89   while ((c = getopt(argc, argv, "clf:ns:")) != -1)
90   {
91     switch (c)
92     {
93       case 'c':
94         crashed = true;
95         break;
96       case 'l':
97         config->set("log", "enabled", true);
98         break;
99       case 'f':
100         config->set("log", "filename", optarg);
101         break;
102       case 'n':
103         config->set("main", "daemonize", false);
104         break;
105       case 's':
106         config->set("server", "address", optarg);
107         break;
108       case '?':
109         printf("Vompclient\n\n");
110         printf("Usage:\n");
111         printf("  -l     Enable logging\n");
112         printf("  -f F   Log to file F instead of stdout\n");
113         printf("  -n     Disable daemonize\n");
114         printf("  -s S   Connect to server S\n");
115         return 1;
116       default:
117         printf("Option error\n");
118         return 1;
119     }
120   }
121
122   // Start Log --------------------------------------------------------------------------------------------------
123
124   loggerNT = new LogNT();
125   if (!loggerNT)
126   {
127     printf("Failed to create LogNT object\n");
128     shutdown(1);
129   }
130
131   std::string logFileName;
132   config->getString("log", "filename", logFileName);
133   bool logEnabled;
134   config->getBool("log", "enabled", logEnabled);
135   bool daemonize;
136   config->getBool("main", "daemonize", daemonize);
137
138   if (logEnabled && daemonize && !logFileName.compare("stdout"))
139   {
140     printf("Cannot daemonize and log to stdout\n");
141     shutdown(1);
142   }
143
144   if (!loggerNT->init(logFileName, logEnabled))
145   {
146     printf("Could not initialise log object. Aborting.\n");
147     shutdown(1);
148   }
149
150   loggerNT->info(TAG, "Starting up...");
151
152   // Daemonize --------------------------------------------------------------------------------------------------
153
154   // Would read config for daemonize here, but actually it's just above in the log section
155   // to detect attempts to log to stdout while daemonized
156   if (daemonize)
157   {
158     // Fork away
159     pid_t forkTest = fork();
160     if (forkTest == -1)
161     { printf("Cannot fork (1).\n"); exit(1); }
162     if (forkTest != 0) _exit(0); // PID returned, I am the parent
163     // otherwise, I am the child
164     setsid();
165     forkTest = fork();
166     if (forkTest == -1)
167     { printf("Cannot fork (2).\n"); exit(1); }
168     if (forkTest != 0) _exit(0); // PID returned, I am the parent
169     // otherwise, I am the child
170     close(0);
171     close(1);
172     close(2);
173   }
174
175   // Set up signal handling ------------------------------------------------------------------------------------------
176
177   // Block all signals
178   sigset_t set;
179   sigfillset(&set);
180   int sigBlockResult = pthread_sigmask(SIG_SETMASK, &set, NULL);
181   if (sigBlockResult)
182   {
183     //logger->log("Main", Log::EMERG, "Could not block signals: %i", sigBlockResult);
184     loggerNT->crit(TAG, "Could not block signals: {}", sigBlockResult);
185     shutdown(1);
186   }
187
188   // Start signal receiver thread
189   std::thread threadSignalReceiver(threadSignalReceiverFunction);
190   threadSignalReceiver.detach();
191
192   loggerNT->info(TAG, "Signal handlers set up successfully");
193
194   // VT Switching -----------------------------------------------------------------------------------------------
195
196 #ifdef HANDLE_VT_SWITCHING
197   if (
198
199
200     (fdtty = open("/dev/tty", O_WRONLY),0) == -1   // FIXME. Why the ,0 ? Surely this kills the log line below
201
202
203   )
204   {
205     loggerNT->warn(TAG, "Could not open /dev/tty. Please change permissions");
206   }
207   else
208   {
209     int free_vt;
210     if (ioctl(fdtty, VT_OPENQRY, &free_vt) == -1 || free_vt == -1)
211     {
212       loggerNT->crit(TAG, "Could not retrieve free virtual console, please change permissions");
213     }
214     else
215     {
216       ioctl(fdtty, VT_ACTIVATE, free_vt);
217       ioctl(fdtty, VT_WAITACTIVE, free_vt);
218       ioctl(fdtty, VT_LOCKSWITCH, 1);
219     }
220   }
221 #endif
222
223   // Test area ------------------------------------------------------------------------------------------------------
224
225   //shutdown(0);
226
227   // Run control ----------------------------------------------------------------------------------------------------
228
229   control = new Control();
230   if (!control)
231   {
232     loggerNT->crit(TAG, "Control module failed to create");
233     shutdown(1);
234   }
235
236   if (!control->init(crashed))
237   {
238     loggerNT->crit(TAG, "Control module failed to initialise");
239     delete control;
240     control = NULL;
241     shutdown(1);
242   }
243
244   control->run();
245   control->shutdown();
246
247   shutdown(0);
248 }
249
250 // -------------------------------------------------------------------------------------------------------------------
251
252 void threadSignalReceiverFunction()
253 {
254   int sig;
255   sigset_t set;
256   sigfillset(&set);
257   while(1)
258   {
259     if(sigwait(&set, &sig))
260     {
261       loggerNT->crit(TAG, "Sigwait returned fail - signal handler exiting");
262       return;
263     }
264
265     loggerNT->info(TAG, "Signal received: {}", sig);
266
267     if ((sig == SIGINT) || (sig == SIGTERM)) control->stop();
268   }
269 }
270
271 #endif
272
273 // -------------------------------------------------------------------------------------------------------------------
274
275 [[ noreturn ]] void shutdown(int code)
276 {
277   // FIXME, send a del all to boxstack first, then get rid of it after control?
278   if (control) // shut down control here in case views have posted messages
279   {
280     delete control;
281     control = NULL;
282     loggerNT->info(TAG, "Control module shut down");
283   }
284
285 #ifdef HANDLE_VT_SWITCHING
286   ioctl(fdtty, VT_UNLOCKSWITCH, 1);
287   close(fdtty);
288 #endif
289
290   if (loggerNT)
291   {
292     loggerNT->info(TAG, "Log module shutting down... bye!\n\n");
293 #warning loggerNT has no shutdown
294     //loggerNT->shutdown();
295     delete loggerNT;
296   }
297
298   if (config)
299   {
300     delete config;
301   }
302
303   exit(code);
304 }
305
306 // -------------------------------------------------------------------------------------------------------------------
307
308 long long getTimeMS()
309 {
310   struct timespec ts;
311   clock_gettime(VOMP_LINUX_CLOCK, &ts);
312   return ts.tv_sec * 1000 + ts.tv_nsec / 1000000LL;
313 }
314
315 int getClockRealTime(struct timespec *tp) // FIXME - del if all goes chrono
316 {
317   return clock_gettime(CLOCK_REALTIME, tp);
318 }
319