Line data Source code
1 : /*
2 : * SPDX license identifier: MPL-2.0
3 : *
4 : * Copyright (C) 2011-2015, BMW AG
5 : *
6 : * This file is part of COVESA Project DLT - Diagnostic Log and Trace.
7 : *
8 : * This Source Code Form is subject to the terms of the
9 : * Mozilla Public License (MPL), v. 2.0.
10 : * If a copy of the MPL was not distributed with this file,
11 : * You can obtain one at http://mozilla.org/MPL/2.0/.
12 : *
13 : * For further information see http://www.covesa.org/.
14 : */
15 :
16 : /*!
17 : * \author
18 : * Alexander Wenzel <alexander.aw.wenzel@bmw.de>
19 : * Markus Klein <Markus.Klein@esk.fraunhofer.de>
20 : * Mikko Rapeli <mikko.rapeli@bmw.de>
21 : *
22 : * \copyright Copyright © 2011-2015 BMW AG. \n
23 : * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
24 : *
25 : * \file dlt-daemon.c
26 : */
27 :
28 : #include <netdb.h>
29 : #include <ctype.h>
30 : #include <stdio.h> /* for printf() and fprintf() */
31 : #include <sys/socket.h> /* for socket(), connect(), (), and recv() */
32 : #include <sys/un.h>
33 : #include <arpa/inet.h> /* for sockaddr_in and inet_addr() */
34 : #include <stdlib.h> /* for atoi() and exit() */
35 : #include <string.h> /* for memset() */
36 : #include <unistd.h> /* for close() and access */
37 : #include <fcntl.h>
38 : #include <signal.h>
39 : #include <syslog.h>
40 : #include <errno.h>
41 : #include <pthread.h>
42 : #include <grp.h>
43 :
44 : #ifdef linux
45 : # include <sys/timerfd.h>
46 : #endif
47 : #include <sys/stat.h>
48 : #include <sys/time.h>
49 : #include <libgen.h>
50 :
51 : #if defined(linux) && defined(__NR_statx)
52 : # include <linux/stat.h>
53 : #endif
54 :
55 : #ifdef DLT_DAEMON_VSOCK_IPC_ENABLE
56 : # ifdef linux
57 : # include <linux/vm_sockets.h>
58 : # endif
59 : # ifdef __QNX__
60 : # include <vm_sockets.h>
61 : # endif
62 : #endif
63 :
64 : #include "dlt_types.h"
65 : #include "dlt-daemon.h"
66 : #include "dlt-daemon_cfg.h"
67 : #include "dlt_daemon_common_cfg.h"
68 :
69 : #include "dlt_daemon_socket.h"
70 : #include "dlt_daemon_unix_socket.h"
71 : #include "dlt_daemon_serial.h"
72 :
73 : #include "dlt_daemon_client.h"
74 : #include "dlt_daemon_connection.h"
75 : #include "dlt_daemon_event_handler.h"
76 : #include "dlt_daemon_offline_logstorage.h"
77 : #include "dlt_gateway.h"
78 :
79 : #ifdef UDP_CONNECTION_SUPPORT
80 : # include "dlt_daemon_udp_socket.h"
81 : #endif
82 : #if defined(DLT_SYSTEMD_WATCHDOG_ENABLE) || defined(DLT_SYSTEMD_ENABLE)
83 : # include "sd-daemon.h"
84 : #endif
85 :
86 : /**
87 : * \defgroup daemon DLT Daemon
88 : * \addtogroup daemon
89 : \{
90 : */
91 :
92 : #define DLT_DAEMON_APP_ID "DLTD"
93 : #define DLT_DAEMON_CTX_ID "INTM"
94 :
95 :
96 : static int dlt_daemon_log_internal(DltDaemon *daemon,
97 : DltDaemonLocal *daemon_local, char *str,
98 : DltLogLevelType level, const char *app_id,
99 : const char *ctx_id, int verbose);
100 :
101 : static int dlt_daemon_check_numeric_setting(char *token,
102 : char *value,
103 : unsigned long *data);
104 :
105 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
106 :
107 : struct DltTraceLoadLogParams {
108 : DltDaemon *daemon;
109 : DltDaemonLocal *daemon_local;
110 : int verbose;
111 : char *app_id;
112 : };
113 :
114 : static DltReturnValue dlt_daemon_output_internal_msg(DltLogLevelType loglevel, const char *text, void *params);
115 :
116 : pthread_rwlock_t trace_load_rw_lock;
117 : #endif
118 :
119 : /* used in main event loop and signal handler */
120 : int g_exit = 0;
121 :
122 : int g_signo = 0;
123 :
124 : /* used for value from conf file */
125 : static int value_length = 1024;
126 :
127 : static char dlt_timer_conn_types[DLT_TIMER_UNKNOWN + 1] = {
128 : [DLT_TIMER_PACKET] = DLT_CONNECTION_ONE_S_TIMER,
129 : [DLT_TIMER_ECU] = DLT_CONNECTION_SIXTY_S_TIMER,
130 : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
131 : [DLT_TIMER_SYSTEMD] = DLT_CONNECTION_SYSTEMD_TIMER,
132 : #endif
133 : [DLT_TIMER_GATEWAY] = DLT_CONNECTION_GATEWAY_TIMER,
134 : [DLT_TIMER_UNKNOWN] = DLT_CONNECTION_TYPE_MAX
135 : };
136 :
137 : static char dlt_timer_names[DLT_TIMER_UNKNOWN + 1][32] = {
138 : [DLT_TIMER_PACKET] = "Timing packet",
139 : [DLT_TIMER_ECU] = "ECU version",
140 : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
141 : [DLT_TIMER_SYSTEMD] = "Systemd watchdog",
142 : #endif
143 : [DLT_TIMER_GATEWAY] = "Gateway",
144 : [DLT_TIMER_UNKNOWN] = "Unknown timer"
145 : };
146 :
147 : #ifdef __QNX__
148 : static int dlt_timer_pipes[DLT_TIMER_UNKNOWN][2] = {
149 : /* [timer_id] = {read_pipe, write_pipe} */
150 : [DLT_TIMER_PACKET] = {DLT_FD_INIT, DLT_FD_INIT},
151 : [DLT_TIMER_ECU] = {DLT_FD_INIT, DLT_FD_INIT},
152 : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
153 : [DLT_TIMER_SYSTEMD] = {DLT_FD_INIT, DLT_FD_INIT},
154 : #endif
155 : [DLT_TIMER_GATEWAY] = {DLT_FD_INIT, DLT_FD_INIT}
156 : };
157 :
158 : static pthread_t timer_threads[DLT_TIMER_UNKNOWN] = {
159 : [DLT_TIMER_PACKET] = 0,
160 : [DLT_TIMER_ECU] = 0,
161 : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
162 : [DLT_TIMER_SYSTEMD] = 0,
163 : #endif
164 : [DLT_TIMER_GATEWAY] = 0
165 : };
166 :
167 : static DltDaemonPeriodicData *timer_data[DLT_TIMER_UNKNOWN] = {
168 : [DLT_TIMER_PACKET] = NULL,
169 : [DLT_TIMER_ECU] = NULL,
170 : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
171 : [DLT_TIMER_SYSTEMD] = NULL,
172 : #endif
173 : [DLT_TIMER_GATEWAY] = NULL
174 : };
175 :
176 : void close_pipes(int fds[2])
177 : {
178 : if (fds[0] > 0) {
179 : close(fds[0]);
180 : fds[0] = DLT_FD_INIT;
181 : }
182 :
183 : if (fds[1] > 0) {
184 : close(fds[1]);
185 : fds[1] = DLT_FD_INIT;
186 : }
187 : }
188 :
189 : #endif // __QNX__
190 :
191 : /**
192 : * Print usage information of tool.
193 : */
194 0 : void usage()
195 : {
196 : char version[DLT_DAEMON_TEXTBUFSIZE];
197 0 : dlt_get_version(version, DLT_DAEMON_TEXTBUFSIZE);
198 :
199 : /*printf("DLT logging daemon %s %s\n", _DLT_PACKAGE_VERSION, _DLT_PACKAGE_VERSION_STATE); */
200 : /*printf("Compile options: %s %s %s %s",_DLT_SYSTEMD_ENABLE, _DLT_SYSTEMD_WATCHDOG_ENABLE, _DLT_TEST_ENABLE, _DLT_SHM_ENABLE); */
201 : printf("%s", version);
202 : printf("Usage: dlt-daemon [options]\n");
203 : printf("Options:\n");
204 : printf(" -d Daemonize\n");
205 : printf(" -h Usage\n");
206 : printf(" -c filename DLT daemon configuration file (Default: " CONFIGURATION_FILES_DIR "/dlt.conf)\n");
207 :
208 : #ifdef DLT_DAEMON_USE_FIFO_IPC
209 : printf(" -t directory Directory for local fifo and user-pipes (Default: /tmp)\n");
210 : printf(" (Applications wanting to connect to a daemon using a\n");
211 : printf(" custom directory need to be started with the environment \n");
212 : printf(" variable DLT_PIPE_DIR set appropriately)\n");
213 : #endif
214 :
215 : #ifdef DLT_SHM_ENABLE
216 : printf(" -s filename The file name to create the share memory (Default: /dlt-shm)\n");
217 : printf(" (Applications wanting to connect to a daemon using a\n");
218 : printf(" custom shm name need to be started with the environment \n");
219 : printf(" variable DLT_SHM_NAME set appropriately)\n");
220 : #endif
221 : printf(" -p port port to monitor for incoming requests (Default: 3490)\n");
222 : printf(" (Applications wanting to connect to a daemon using a custom\n");
223 : printf(" port need to be started with the environment variable\n");
224 : printf(" DLT_DAEMON_TCP_PORT set appropriately)\n");
225 : #ifdef DLT_LOG_LEVEL_APP_CONFIG
226 : printf(" -a filename The filename for load default app id log levels (Default: " CONFIGURATION_FILES_DIR "/dlt-log-levels.conf)\n");
227 : #endif
228 :
229 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
230 : printf(" -l filename The filename for load limits (Default: " CONFIGURATION_FILES_DIR "/dlt-trace-load.conf)\n");
231 : #endif
232 :
233 : #
234 0 : } /* usage() */
235 :
236 : /**
237 : * Option handling
238 : */
239 9 : int option_handling(DltDaemonLocal *daemon_local, int argc, char *argv[])
240 : {
241 : int c;
242 : char options[255];
243 : memset(options, 0, sizeof options);
244 : const char *const default_options = "hdc:t:p:";
245 : strcpy(options, default_options);
246 :
247 9 : if (daemon_local == 0) {
248 0 : fprintf (stderr, "Invalid parameter passed to option_handling()\n");
249 0 : return -1;
250 : }
251 :
252 : /* Initialize flags */
253 : memset(daemon_local, 0, sizeof(DltDaemonLocal));
254 :
255 : /* default values */
256 9 : daemon_local->flags.port = DLT_DAEMON_TCP_PORT;
257 :
258 : #ifdef DLT_DAEMON_USE_FIFO_IPC
259 9 : dlt_log_set_fifo_basedir(DLT_USER_IPC_PATH);
260 : #endif
261 :
262 : #ifdef DLT_SHM_ENABLE
263 : strncpy(dltShmName, "/dlt-shm", NAME_MAX);
264 : #endif
265 :
266 9 : opterr = 0;
267 :
268 : #ifdef DLT_SHM_ENABLE
269 : strcpy(options + strlen(options), "s:");
270 : #endif
271 : #ifdef DLT_LOG_LEVEL_APP_CONFIG
272 : strcpy(options + strlen(options), "a:");
273 : #endif
274 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
275 : strcpy(options + strlen(options), "l:");
276 : #endif
277 20 : while ((c = getopt(argc, argv, options)) != -1)
278 11 : switch (c) {
279 2 : case 'd':
280 : {
281 2 : daemon_local->flags.dflag = 1;
282 2 : break;
283 : }
284 8 : case 'c':
285 : {
286 8 : strncpy(daemon_local->flags.cvalue, optarg, NAME_MAX);
287 : break;
288 : }
289 : #ifdef DLT_LOG_LEVEL_APP_CONFIG
290 : case 'a':
291 : {
292 : strncpy(daemon_local->flags.avalue, optarg, NAME_MAX);
293 : break;
294 : }
295 : #endif
296 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
297 : case 'l':
298 : {
299 : strncpy(daemon_local->flags.lvalue, optarg, NAME_MAX);
300 : break;
301 : }
302 : #endif
303 : #ifdef DLT_DAEMON_USE_FIFO_IPC
304 0 : case 't':
305 : {
306 0 : dlt_log_set_fifo_basedir(optarg);
307 0 : break;
308 : }
309 : #endif
310 :
311 : #ifdef DLT_SHM_ENABLE
312 : case 's':
313 : {
314 : strncpy(dltShmName, optarg, NAME_MAX);
315 : break;
316 : }
317 : #endif
318 1 : case 'p':
319 : {
320 1 : daemon_local->flags.port = (unsigned int) atoi(optarg);
321 :
322 1 : if (daemon_local->flags.port == 0) {
323 0 : fprintf (stderr, "Invalid port `%s' specified.\n", optarg);
324 0 : return -1;
325 : }
326 :
327 : break;
328 : }
329 0 : case 'h':
330 : {
331 0 : usage();
332 0 : return -2; /* return no error */
333 : }
334 :
335 0 : case '?':
336 : {
337 0 : if ((optopt == 'c') || (optopt == 't') || (optopt == 'p')
338 : #ifdef DLT_LOG_LEVEL_APP_CONFIG
339 : || (optopt == 'a')
340 : #endif
341 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
342 : || (optopt == 'l')
343 : #endif
344 : )
345 0 : fprintf (stderr, "Option -%c requires an argument.\n", optopt);
346 0 : else if (isprint (optopt))
347 0 : fprintf (stderr, "Unknown option `-%c'.\n", optopt);
348 : else
349 0 : fprintf (stderr, "Unknown option character `\\x%x'.\n", (uint32_t)optopt);
350 :
351 : /* unknown or wrong option used, show usage information and terminate */
352 0 : usage();
353 0 : return -1;
354 : }
355 0 : default:
356 : {
357 0 : fprintf (stderr, "Invalid option, this should never occur!\n");
358 0 : return -1;
359 : }
360 : }
361 :
362 : /* switch() */
363 :
364 : #ifdef DLT_DAEMON_USE_FIFO_IPC
365 9 : snprintf(daemon_local->flags.userPipesDir, DLT_PATH_MAX,
366 : "%s/dltpipes", dltFifoBaseDir);
367 9 : snprintf(daemon_local->flags.daemonFifoName, DLT_PATH_MAX,
368 : "%s/dlt", dltFifoBaseDir);
369 : #endif
370 :
371 : #ifdef DLT_SHM_ENABLE
372 : strncpy(daemon_local->flags.dltShmName, dltShmName, NAME_MAX);
373 : #endif
374 :
375 9 : return 0;
376 :
377 : } /* option_handling() */
378 :
379 : /**
380 : * Option file parser
381 : */
382 9 : int option_file_parser(DltDaemonLocal *daemon_local)
383 9 : {
384 : FILE *pFile;
385 9 : char line[value_length - 1];
386 9 : char token[value_length];
387 9 : char value[value_length];
388 : char *pch;
389 : const char *filename;
390 : ssize_t n;
391 :
392 : /* set default values for configuration */
393 9 : daemon_local->flags.sharedMemorySize = DLT_SHM_SIZE;
394 9 : daemon_local->flags.sendMessageTime = 0;
395 9 : daemon_local->flags.offlineTraceDirectory[0] = 0;
396 9 : daemon_local->flags.offlineTraceFileSize = 1000000;
397 9 : daemon_local->flags.offlineTraceMaxSize = 4000000;
398 9 : daemon_local->flags.offlineTraceFilenameTimestampBased = true;
399 9 : daemon_local->flags.loggingMode = DLT_LOG_TO_CONSOLE;
400 9 : daemon_local->flags.loggingLevel = LOG_INFO;
401 :
402 : #ifdef DLT_DAEMON_USE_UNIX_SOCKET_IPC
403 : n = snprintf(daemon_local->flags.loggingFilename,
404 : sizeof(daemon_local->flags.loggingFilename),
405 : "%s/dlt.log", DLT_USER_IPC_PATH);
406 : #else /* DLT_DAEMON_USE_FIFO_IPC */
407 9 : n = snprintf(daemon_local->flags.loggingFilename,
408 : sizeof(daemon_local->flags.loggingFilename),
409 : "%s/dlt.log", dltFifoBaseDir);
410 : #endif
411 :
412 9 : if (n < 0 || (size_t)n > sizeof(daemon_local->flags.loggingFilename)) {
413 0 : dlt_vlog(LOG_WARNING, "%s: snprintf truncation/error(%ld) %s\n",
414 : __func__, n, daemon_local->flags.loggingFilename);
415 : }
416 9 : daemon_local->flags.enableLoggingFileLimit = false;
417 9 : daemon_local->flags.loggingFileSize = 250000;
418 9 : daemon_local->flags.loggingFileMaxSize = 1000000;
419 :
420 9 : daemon_local->timeoutOnSend = 4;
421 9 : daemon_local->RingbufferMinSize = DLT_DAEMON_RINGBUFFER_MIN_SIZE;
422 9 : daemon_local->RingbufferMaxSize = DLT_DAEMON_RINGBUFFER_MAX_SIZE;
423 9 : daemon_local->RingbufferStepSize = DLT_DAEMON_RINGBUFFER_STEP_SIZE;
424 9 : daemon_local->daemonFifoSize = 0;
425 9 : daemon_local->flags.sendECUSoftwareVersion = 0;
426 9 : memset(daemon_local->flags.pathToECUSoftwareVersion, 0, sizeof(daemon_local->flags.pathToECUSoftwareVersion));
427 9 : memset(daemon_local->flags.ecuSoftwareVersionFileField, 0, sizeof(daemon_local->flags.ecuSoftwareVersionFileField));
428 9 : daemon_local->flags.sendTimezone = 0;
429 9 : daemon_local->flags.offlineLogstorageMaxDevices = 0;
430 9 : daemon_local->flags.offlineLogstorageDirPath[0] = 0;
431 9 : daemon_local->flags.offlineLogstorageTimestamp = 1;
432 9 : daemon_local->flags.offlineLogstorageDelimiter = '_';
433 9 : daemon_local->flags.offlineLogstorageMaxCounter = UINT_MAX;
434 9 : daemon_local->flags.offlineLogstorageMaxCounterIdx = 0;
435 9 : daemon_local->flags.offlineLogstorageOptionalCounter = false;
436 9 : daemon_local->flags.offlineLogstorageCacheSize = 30000; /* 30MB */
437 9 : dlt_daemon_logstorage_set_logstorage_cache_size(
438 : daemon_local->flags.offlineLogstorageCacheSize);
439 9 : strncpy(daemon_local->flags.ctrlSockPath,
440 : DLT_DAEMON_DEFAULT_CTRL_SOCK_PATH,
441 : sizeof(daemon_local->flags.ctrlSockPath));
442 : #ifdef DLT_DAEMON_USE_UNIX_SOCKET_IPC
443 : snprintf(daemon_local->flags.appSockPath, DLT_IPC_PATH_MAX, "%s/dlt", DLT_USER_IPC_PATH);
444 :
445 : if (strlen(DLT_USER_IPC_PATH) > DLT_IPC_PATH_MAX)
446 : fprintf(stderr, "Provided path too long...trimming it to path[%s]\n",
447 : daemon_local->flags.appSockPath);
448 :
449 : #else /* DLT_DAEMON_USE_FIFO_IPC */
450 9 : memset(daemon_local->flags.daemonFifoGroup, 0, sizeof(daemon_local->flags.daemonFifoGroup));
451 : #endif
452 9 : daemon_local->flags.gatewayMode = 0;
453 9 : strncpy(daemon_local->flags.gatewayConfigFile,
454 : DLT_GATEWAY_CONFIG_PATH,
455 : DLT_DAEMON_FLAG_MAX);
456 9 : daemon_local->flags.autoResponseGetLogInfoOption = 7;
457 9 : daemon_local->flags.contextLogLevel = DLT_LOG_INFO;
458 9 : daemon_local->flags.contextTraceStatus = DLT_TRACE_STATUS_OFF;
459 9 : daemon_local->flags.enforceContextLLAndTS = 0; /* default is off */
460 : #ifdef UDP_CONNECTION_SUPPORT
461 : daemon_local->UDPConnectionSetup = MULTICAST_CONNECTION_ENABLED;
462 : strncpy(daemon_local->UDPMulticastIPAddress, MULTICASTIPADDRESS, MULTICASTIP_MAX_SIZE - 1);
463 : daemon_local->UDPMulticastIPPort = MULTICASTIPPORT;
464 : #endif
465 9 : daemon_local->flags.ipNodes = NULL;
466 9 : daemon_local->flags.injectionMode = 1;
467 :
468 : /* open configuration file */
469 9 : if (daemon_local->flags.cvalue[0])
470 8 : filename = daemon_local->flags.cvalue;
471 : else
472 : filename = CONFIGURATION_FILES_DIR "/dlt.conf";
473 :
474 : /*printf("Load configuration from file: %s\n",filename); */
475 9 : pFile = fopen (filename, "r");
476 :
477 9 : if (pFile != NULL) {
478 : while (1) {
479 : /* fetch line from configuration file */
480 112 : if (fgets (line, value_length - 1, pFile) != NULL) {
481 49 : pch = strtok (line, " =\r\n");
482 49 : token[0] = 0;
483 49 : value[0] = 0;
484 :
485 92 : while (pch != NULL) {
486 86 : if (strcmp(pch, "#") == 0)
487 : break;
488 :
489 86 : if (token[0] == 0) {
490 43 : strncpy(token, pch, sizeof(token) - 1);
491 43 : token[sizeof(token) - 1] = 0;
492 : }
493 : else {
494 43 : strncpy(value, pch, sizeof(value) - 1);
495 43 : value[sizeof(value) - 1] = 0;
496 43 : break;
497 : }
498 :
499 43 : pch = strtok (NULL, " =\r\n");
500 : }
501 :
502 49 : if (token[0] && value[0]) {
503 : /* parse arguments here */
504 43 : if (strcmp(token, "Verbose") == 0) {
505 0 : daemon_local->flags.vflag = atoi(value);
506 : /*printf("Option: %s=%s\n",token,value); */
507 : }
508 43 : else if (strcmp(token, "PrintASCII") == 0)
509 : {
510 0 : daemon_local->flags.aflag = atoi(value);
511 : /*printf("Option: %s=%s\n",token,value); */
512 : }
513 43 : else if (strcmp(token, "PrintHex") == 0)
514 : {
515 0 : daemon_local->flags.xflag = atoi(value);
516 : /*printf("Option: %s=%s\n",token,value); */
517 : }
518 43 : else if (strcmp(token, "PrintHeadersOnly") == 0)
519 : {
520 0 : daemon_local->flags.sflag = atoi(value);
521 : /*printf("Option: %s=%s\n",token,value); */
522 : }
523 43 : else if (strcmp(token, "SendSerialHeader") == 0)
524 : {
525 0 : daemon_local->flags.lflag = atoi(value);
526 : /*printf("Option: %s=%s\n",token,value); */
527 : }
528 43 : else if (strcmp(token, "SendContextRegistration") == 0)
529 : {
530 1 : daemon_local->flags.rflag = atoi(value);
531 : /*printf("Option: %s=%s\n",token,value); */
532 : }
533 42 : else if (strcmp(token, "SendContextRegistrationOption") == 0)
534 : {
535 0 : daemon_local->flags.autoResponseGetLogInfoOption = atoi(value);
536 : /*printf("Option: %s=%s\n",token,value); */
537 : }
538 42 : else if (strcmp(token, "SendMessageTime") == 0)
539 : {
540 0 : daemon_local->flags.sendMessageTime = atoi(value);
541 : /*printf("Option: %s=%s\n",token,value); */
542 : }
543 42 : else if (strcmp(token, "RS232SyncSerialHeader") == 0)
544 : {
545 0 : daemon_local->flags.mflag = atoi(value);
546 : /*printf("Option: %s=%s\n",token,value); */
547 : }
548 42 : else if (strcmp(token, "TCPSyncSerialHeader") == 0)
549 : {
550 0 : daemon_local->flags.nflag = atoi(value);
551 : /*printf("Option: %s=%s\n",token,value); */
552 : }
553 42 : else if (strcmp(token, "RS232DeviceName") == 0)
554 : {
555 0 : strncpy(daemon_local->flags.yvalue, value, NAME_MAX);
556 0 : daemon_local->flags.yvalue[NAME_MAX] = 0;
557 : /*printf("Option: %s=%s\n",token,value); */
558 : }
559 42 : else if (strcmp(token, "RS232Baudrate") == 0)
560 : {
561 0 : strncpy(daemon_local->flags.bvalue, value, NAME_MAX);
562 0 : daemon_local->flags.bvalue[NAME_MAX] = 0;
563 : /*printf("Option: %s=%s\n",token,value); */
564 : }
565 42 : else if (strcmp(token, "ECUId") == 0)
566 : {
567 1 : strncpy(daemon_local->flags.evalue, value, NAME_MAX);
568 1 : daemon_local->flags.evalue[NAME_MAX] = 0;
569 : /*printf("Option: %s=%s\n",token,value); */
570 : }
571 41 : else if (strcmp(token, "PersistanceStoragePath") == 0)
572 : {
573 0 : strncpy(daemon_local->flags.ivalue, value, NAME_MAX);
574 0 : daemon_local->flags.ivalue[NAME_MAX] = 0;
575 : /*printf("Option: %s=%s\n",token,value); */
576 : }
577 41 : else if (strcmp(token, "LoggingMode") == 0)
578 : {
579 1 : daemon_local->flags.loggingMode = (DltLoggingMode)atoi(value);
580 : /*printf("Option: %s=%s\n",token,value); */
581 : }
582 40 : else if (strcmp(token, "LoggingLevel") == 0)
583 : {
584 1 : daemon_local->flags.loggingLevel = atoi(value);
585 : /*printf("Option: %s=%s\n",token,value); */
586 : }
587 39 : else if (strcmp(token, "LoggingFilename") == 0)
588 : {
589 : strncpy(daemon_local->flags.loggingFilename,
590 : value,
591 : sizeof(daemon_local->flags.loggingFilename) - 1);
592 1 : daemon_local->flags.loggingFilename[sizeof(daemon_local->flags.loggingFilename) - 1] = 0;
593 : /*printf("Option: %s=%s\n",token,value); */
594 : }
595 38 : else if (strcmp(token, "EnableLoggingFileLimit") == 0)
596 : {
597 0 : daemon_local->flags.enableLoggingFileLimit = (bool)atoi(value);
598 : }
599 38 : else if (strcmp(token, "LoggingFileSize") == 0)
600 : {
601 0 : daemon_local->flags.loggingFileSize = atoi(value);
602 : }
603 38 : else if (strcmp(token, "LoggingFileMaxSize") == 0)
604 : {
605 0 : daemon_local->flags.loggingFileMaxSize = atoi(value);
606 : }
607 38 : else if (strcmp(token, "TimeOutOnSend") == 0)
608 : {
609 1 : daemon_local->timeoutOnSend = atoi(value);
610 : /*printf("Option: %s=%s\n",token,value); */
611 : }
612 37 : else if (strcmp(token, "RingbufferMinSize") == 0)
613 : {
614 1 : if (dlt_daemon_check_numeric_setting(token,
615 : value, &(daemon_local->RingbufferMinSize)) < 0) {
616 0 : fclose (pFile);
617 0 : return -1;
618 : }
619 : }
620 36 : else if (strcmp(token, "RingbufferMaxSize") == 0)
621 : {
622 1 : if (dlt_daemon_check_numeric_setting(token,
623 : value, &(daemon_local->RingbufferMaxSize)) < 0) {
624 0 : fclose (pFile);
625 0 : return -1;
626 : }
627 : }
628 35 : else if (strcmp(token, "RingbufferStepSize") == 0)
629 : {
630 1 : if (dlt_daemon_check_numeric_setting(token,
631 : value, &(daemon_local->RingbufferStepSize)) < 0) {
632 0 : fclose (pFile);
633 0 : return -1;
634 : }
635 : }
636 34 : else if (strcmp(token, "SharedMemorySize") == 0)
637 : {
638 1 : daemon_local->flags.sharedMemorySize = atoi(value);
639 : /*printf("Option: %s=%s\n",token,value); */
640 : }
641 33 : else if (strcmp(token, "OfflineTraceDirectory") == 0)
642 : {
643 0 : strncpy(daemon_local->flags.offlineTraceDirectory, value,
644 : sizeof(daemon_local->flags.offlineTraceDirectory) - 1);
645 : daemon_local->flags.offlineTraceDirectory[sizeof(daemon_local->flags.offlineTraceDirectory) -
646 0 : 1] = 0;
647 : /*printf("Option: %s=%s\n",token,value); */
648 : }
649 33 : else if (strcmp(token, "OfflineTraceFileSize") == 0)
650 : {
651 0 : daemon_local->flags.offlineTraceFileSize = atoi(value);
652 : /*printf("Option: %s=%s\n",token,value); */
653 : }
654 33 : else if (strcmp(token, "OfflineTraceMaxSize") == 0)
655 : {
656 0 : daemon_local->flags.offlineTraceMaxSize = atoi(value);
657 : /*printf("Option: %s=%s\n",token,value); */
658 : }
659 33 : else if (strcmp(token, "OfflineTraceFileNameTimestampBased") == 0)
660 : {
661 0 : daemon_local->flags.offlineTraceFilenameTimestampBased = (bool)atoi(value);
662 : /*printf("Option: %s=%s\n",token,value); */
663 : }
664 33 : else if (strcmp(token, "SendECUSoftwareVersion") == 0)
665 : {
666 0 : daemon_local->flags.sendECUSoftwareVersion = atoi(value);
667 : /*printf("Option: %s=%s\n",token,value); */
668 : }
669 33 : else if (strcmp(token, "PathToECUSoftwareVersion") == 0)
670 : {
671 : strncpy(daemon_local->flags.pathToECUSoftwareVersion, value,
672 : sizeof(daemon_local->flags.pathToECUSoftwareVersion) - 1);
673 : daemon_local->flags.pathToECUSoftwareVersion[sizeof(daemon_local->flags.pathToECUSoftwareVersion)
674 0 : - 1] = 0;
675 : /*printf("Option: %s=%s\n",token,value); */
676 : }
677 33 : else if (strcmp(token, "ECUSoftwareVersionFileField") == 0) {
678 : strncpy(daemon_local->flags.ecuSoftwareVersionFileField, value,
679 : sizeof(daemon_local->flags.ecuSoftwareVersionFileField) - 1);
680 : daemon_local->flags.ecuSoftwareVersionFileField[sizeof(daemon_local->flags.ecuSoftwareVersionFileField)
681 0 : - 1] = 0;
682 : /*printf("Option: %s=%s\n",token,value); */
683 : }
684 33 : else if (strcmp(token, "SendTimezone") == 0)
685 : {
686 0 : daemon_local->flags.sendTimezone = atoi(value);
687 : /*printf("Option: %s=%s\n",token,value); */
688 : }
689 33 : else if (strcmp(token, "OfflineLogstorageMaxDevices") == 0)
690 : {
691 6 : daemon_local->flags.offlineLogstorageMaxDevices = (uint32_t) atoi(value);
692 : }
693 27 : else if (strcmp(token, "OfflineLogstorageDirPath") == 0)
694 : {
695 6 : strncpy(daemon_local->flags.offlineLogstorageDirPath,
696 : value,
697 : sizeof(daemon_local->flags.offlineLogstorageDirPath) - 1);
698 : }
699 21 : else if (strcmp(token, "OfflineLogstorageTimestamp") == 0)
700 : {
701 : /* Check if set to 0, default otherwise */
702 6 : if (atoi(value) == 0)
703 6 : daemon_local->flags.offlineLogstorageTimestamp = 0;
704 : }
705 15 : else if (strcmp(token, "OfflineLogstorageDelimiter") == 0)
706 : {
707 : /* Check if valid punctuation, default otherwise*/
708 0 : if (ispunct((char)value[0]))
709 0 : daemon_local->flags.offlineLogstorageDelimiter = (char)value[0];
710 : }
711 15 : else if (strcmp(token, "OfflineLogstorageMaxCounter") == 0)
712 : {
713 0 : daemon_local->flags.offlineLogstorageMaxCounter = (unsigned int) atoi(value);
714 0 : daemon_local->flags.offlineLogstorageMaxCounterIdx = (unsigned int) strlen(value);
715 15 : } else if (strcmp(token, "OfflineLogstorageOptionalIndex") == 0) {
716 6 : daemon_local->flags.offlineLogstorageOptionalCounter = atoi(value);
717 : }
718 9 : else if (strcmp(token, "OfflineLogstorageCacheSize") == 0)
719 : {
720 0 : daemon_local->flags.offlineLogstorageCacheSize =
721 0 : (unsigned int)atoi(value);
722 0 : dlt_daemon_logstorage_set_logstorage_cache_size(
723 : daemon_local->flags.offlineLogstorageCacheSize);
724 : }
725 9 : else if (strcmp(token, "ControlSocketPath") == 0)
726 : {
727 : memset(
728 : daemon_local->flags.ctrlSockPath,
729 : 0,
730 : DLT_DAEMON_FLAG_MAX);
731 : strncpy(
732 : daemon_local->flags.ctrlSockPath,
733 : value,
734 : DLT_DAEMON_FLAG_MAX - 1);
735 : }
736 2 : else if (strcmp(token, "GatewayMode") == 0)
737 : {
738 1 : daemon_local->flags.gatewayMode = atoi(value);
739 : /*printf("Option: %s=%s\n",token,value); */
740 : }
741 1 : else if (strcmp(token, "GatewayConfigFile") == 0)
742 : {
743 : memset(
744 : daemon_local->flags.gatewayConfigFile,
745 : 0,
746 : DLT_DAEMON_FLAG_MAX);
747 : strncpy(
748 : daemon_local->flags.gatewayConfigFile,
749 : value,
750 : DLT_DAEMON_FLAG_MAX - 1);
751 : }
752 0 : else if (strcmp(token, "ContextLogLevel") == 0)
753 : {
754 : int const intval = atoi(value);
755 :
756 0 : if ((intval >= DLT_LOG_OFF) && (intval <= DLT_LOG_VERBOSE)) {
757 0 : daemon_local->flags.contextLogLevel = intval;
758 : printf("Option: %s=%s\n", token, value);
759 : }
760 : else {
761 0 : fprintf(stderr,
762 : "Invalid value for ContextLogLevel: %i. Must be in range [%i..%i]\n",
763 : intval,
764 : DLT_LOG_OFF,
765 : DLT_LOG_VERBOSE);
766 : }
767 : }
768 0 : else if (strcmp(token, "ContextTraceStatus") == 0)
769 : {
770 : int const intval = atoi(value);
771 :
772 0 : if ((intval >= DLT_TRACE_STATUS_OFF) && (intval <= DLT_TRACE_STATUS_ON)) {
773 0 : daemon_local->flags.contextTraceStatus = intval;
774 : printf("Option: %s=%s\n", token, value);
775 : }
776 : else {
777 0 : fprintf(stderr,
778 : "Invalid value for ContextTraceStatus: %i. Must be in range [%i..%i]\n",
779 : intval,
780 : DLT_TRACE_STATUS_OFF,
781 : DLT_TRACE_STATUS_ON);
782 : }
783 : }
784 0 : else if (strcmp(token, "ForceContextLogLevelAndTraceStatus") == 0)
785 : {
786 : int const intval = atoi(value);
787 :
788 0 : if ((intval >= 0) && (intval <= 1)) {
789 0 : daemon_local->flags.enforceContextLLAndTS = intval;
790 : printf("Option: %s=%s\n", token, value);
791 : }
792 : else {
793 0 : fprintf(stderr,
794 : "Invalid value for ForceContextLogLevelAndTraceStatus: %i. Must be 0, 1\n",
795 : intval);
796 : }
797 : }
798 :
799 : #ifdef DLT_DAEMON_USE_FIFO_IPC
800 0 : else if (strcmp(token, "DaemonFIFOSize") == 0)
801 : {
802 0 : if (dlt_daemon_check_numeric_setting(token,
803 : value, &(daemon_local->daemonFifoSize)) < 0) {
804 0 : fclose (pFile);
805 0 : return -1;
806 : }
807 : #ifndef __linux__
808 : printf("Option DaemonFIFOSize is set but only supported on Linux. Ignored.\n");
809 : #endif
810 : }
811 0 : else if (strcmp(token, "DaemonFifoGroup") == 0)
812 : {
813 : strncpy(daemon_local->flags.daemonFifoGroup, value, NAME_MAX);
814 0 : daemon_local->flags.daemonFifoGroup[NAME_MAX] = 0;
815 : }
816 : #endif
817 : #ifdef UDP_CONNECTION_SUPPORT
818 : else if (strcmp(token, "UDPConnectionSetup") == 0)
819 : {
820 : const long longval = strtol(value, NULL, 10);
821 :
822 : if ((longval == MULTICAST_CONNECTION_DISABLED)
823 : || (longval == MULTICAST_CONNECTION_ENABLED)) {
824 : daemon_local->UDPConnectionSetup = longval;
825 : printf("Option: %s=%s\n", token, value);
826 : }
827 : else {
828 : daemon_local->UDPConnectionSetup = MULTICAST_CONNECTION_DISABLED;
829 : fprintf(stderr,
830 : "Invalid value for UDPConnectionSetup set to default %ld\n",
831 : longval);
832 : }
833 : }
834 : else if (strcmp(token, "UDPMulticastIPAddress") == 0)
835 : {
836 : strncpy(daemon_local->UDPMulticastIPAddress, value,
837 : MULTICASTIP_MAX_SIZE - 1);
838 : }
839 : else if (strcmp(token, "UDPMulticastIPPort") == 0)
840 : {
841 : daemon_local->UDPMulticastIPPort = strtol(value, NULL, 10);
842 : }
843 : #endif
844 0 : else if (strcmp(token, "BindAddress") == 0)
845 : {
846 : DltBindAddress_t *newNode = NULL;
847 : DltBindAddress_t *temp = NULL;
848 :
849 0 : char *tok = strtok(value, ",;");
850 :
851 0 : if (tok != NULL) {
852 0 : daemon_local->flags.ipNodes = calloc(1, sizeof(DltBindAddress_t));
853 :
854 0 : if (daemon_local->flags.ipNodes == NULL) {
855 0 : dlt_vlog(LOG_ERR, "Could not allocate for IP list\n");
856 0 : fclose(pFile);
857 0 : return -1;
858 : }
859 : else {
860 0 : strncpy(daemon_local->flags.ipNodes->ip,
861 : tok,
862 : sizeof(daemon_local->flags.ipNodes->ip) - 1);
863 0 : daemon_local->flags.ipNodes->next = NULL;
864 : temp = daemon_local->flags.ipNodes;
865 :
866 0 : tok = strtok(NULL, ",;");
867 :
868 0 : while (tok != NULL) {
869 0 : newNode = calloc(1, sizeof(DltBindAddress_t));
870 :
871 0 : if (newNode == NULL) {
872 0 : dlt_vlog(LOG_ERR, "Could not allocate for IP list\n");
873 0 : fclose(pFile);
874 0 : return -1;
875 : }
876 : else {
877 0 : strncpy(newNode->ip, tok, sizeof(newNode->ip) - 1);
878 : }
879 :
880 0 : temp->next = newNode;
881 : temp = temp->next;
882 0 : tok = strtok(NULL, ",;");
883 : }
884 : }
885 : }
886 : else {
887 0 : dlt_vlog(LOG_WARNING, "BindAddress option is empty\n");
888 : }
889 : }
890 0 : else if (strcmp(token, "InjectionMode") == 0) {
891 0 : daemon_local->flags.injectionMode = atoi(value);
892 : }
893 : else {
894 0 : fprintf(stderr, "Unknown option: %s=%s\n", token, value);
895 : }
896 : }
897 : }
898 : else {
899 : break;
900 : }
901 : }
902 :
903 7 : fclose (pFile);
904 : }
905 : else {
906 2 : fprintf(stderr, "Cannot open configuration file: %s\n", filename);
907 : }
908 :
909 : return 0;
910 : }
911 :
912 : #ifdef DLT_LOG_LEVEL_APP_CONFIG
913 : /**
914 : * Load configuration file parser
915 : */
916 :
917 : static int compare_app_id_conf(const void *lhs, const void *rhs)
918 : {
919 : return strncmp(((DltDaemonContextLogSettings *)lhs)->apid,
920 : ((DltDaemonContextLogSettings *)rhs)->apid, DLT_ID_SIZE);
921 : }
922 :
923 : int app_id_default_log_level_config_parser(DltDaemon *daemon,
924 : DltDaemonLocal *daemon_local) {
925 : FILE *pFile;
926 : char line[value_length - 1];
927 : char app_id_value[value_length];
928 : char ctx_id_value[value_length];
929 : DltLogLevelType log_level_value;
930 :
931 : char *pch;
932 : const char *filename;
933 :
934 : /* open configuration file */
935 : filename = daemon_local->flags.avalue[0]
936 : ? daemon_local->flags.avalue
937 : : CONFIGURATION_FILES_DIR "/dlt-log-levels.conf";
938 :
939 : pFile = fopen(filename, "r");
940 : if (pFile == NULL) {
941 : dlt_vlog(LOG_WARNING, "Cannot open app log level configuration%s\n", filename);
942 : return -errno;
943 : }
944 :
945 : /* fetch lines from configuration file */
946 : while (fgets(line, value_length - 1, pFile) != NULL) {
947 : pch = strtok(line, " \t");
948 : memset(app_id_value, 0, value_length);
949 : memset(ctx_id_value, 0, value_length);
950 : log_level_value = DLT_LOG_MAX;
951 :
952 : /* ignore comments and new lines*/
953 : if (strncmp(pch, "#", 1) == 0 || strncmp(pch, "\n", 1) == 0
954 : || strlen(pch) < 1)
955 : continue;
956 :
957 : strncpy(app_id_value, pch, sizeof(app_id_value) - 1);
958 : app_id_value[sizeof(app_id_value) - 1] = 0;
959 : if (strlen(app_id_value) == 0 || strlen(app_id_value) > DLT_ID_SIZE) {
960 : if (app_id_value[strlen(app_id_value) - 1] == '\n') {
961 : dlt_vlog(LOG_WARNING, "Missing log level for apid %s in log settings\n",
962 : app_id_value);
963 : } else {
964 : dlt_vlog(LOG_WARNING,
965 : "Invalid apid for log settings settings: app id: %s\n",
966 : app_id_value);
967 : }
968 :
969 : continue;
970 : }
971 :
972 : char *pch_next1 = strtok(NULL, " \t");
973 : char *pch_next2 = strtok(NULL, " \t");
974 : char *log_level;
975 : /* no context id given, log level is next token */
976 : if (pch_next2 == NULL || pch_next2[0] == '#') {
977 : log_level = pch_next1;
978 : } else {
979 : /* context id is given, log level is second to next token */
980 : log_level = pch_next2;
981 :
982 : /* next token is token id */
983 : strncpy(ctx_id_value, pch_next1, sizeof(ctx_id_value) - 1);
984 : if (strlen(ctx_id_value) == 0 || strlen(app_id_value) > DLT_ID_SIZE) {
985 : dlt_vlog(LOG_WARNING,
986 : "Invalid ctxid for log settings: app id: %s "
987 : "(skipping line)\n",
988 : app_id_value);
989 : continue;
990 : }
991 :
992 : ctx_id_value[sizeof(ctx_id_value) - 1] = 0;
993 : }
994 :
995 : errno = 0;
996 : log_level_value = strtol(log_level, NULL, 10);
997 : if (errno != 0 || log_level_value >= DLT_LOG_MAX ||
998 : log_level_value <= DLT_LOG_DEFAULT) {
999 : dlt_vlog(LOG_WARNING,
1000 : "Invalid log level (%i), app id %s, conversion error: %s\n",
1001 : log_level_value, app_id_value, strerror(errno));
1002 : continue;
1003 : }
1004 :
1005 : DltDaemonContextLogSettings *settings =
1006 : dlt_daemon_find_configured_app_id_ctx_id_settings(
1007 : daemon, app_id_value, NULL);
1008 :
1009 : if (settings != NULL &&
1010 : strncmp(settings->ctid, ctx_id_value, DLT_ID_SIZE) == 0) {
1011 : if (strlen(ctx_id_value) > 0) {
1012 : dlt_vlog(LOG_WARNING,
1013 : "Appid %s with ctxid %s is already configured, skipping "
1014 : "duplicated entry\n",
1015 : app_id_value, ctx_id_value);
1016 : } else {
1017 : dlt_vlog(LOG_WARNING,
1018 : "Appid %s is already configured, skipping duplicated entry\n",
1019 : app_id_value);
1020 : }
1021 :
1022 : continue;
1023 : }
1024 :
1025 : /* allocate one more element in the trace load settings */
1026 : DltDaemonContextLogSettings *tmp =
1027 : realloc(daemon->app_id_log_level_settings,
1028 : (++daemon->num_app_id_log_level_settings) *
1029 : sizeof(DltDaemonContextLogSettings));
1030 :
1031 : if (tmp == NULL) {
1032 : dlt_log(LOG_CRIT, "Failed to allocate memory for app load settings\n");
1033 : continue;
1034 : }
1035 :
1036 : daemon->app_id_log_level_settings = tmp;
1037 :
1038 : /* update newly created entry */
1039 : settings = &daemon->app_id_log_level_settings
1040 : [daemon->num_app_id_log_level_settings -1];
1041 :
1042 : memset(settings, 0, sizeof(DltDaemonContextLogSettings));
1043 : memcpy(settings->apid, app_id_value, DLT_ID_SIZE);
1044 : memcpy(settings->ctid, ctx_id_value, DLT_ID_SIZE);
1045 : settings->log_level = log_level_value;
1046 :
1047 : /* make sure ids are 0 terminated for printing */
1048 : char apid_buf[DLT_ID_SIZE + 1] = {0};
1049 : char ctid_buf[DLT_ID_SIZE + 1] = {0};
1050 : memcpy(apid_buf, app_id_value, DLT_ID_SIZE);
1051 : memcpy(ctid_buf, ctx_id_value, DLT_ID_SIZE);
1052 :
1053 : /* log with or without context id */
1054 : if (strlen(ctid_buf) > 0) {
1055 : dlt_vlog(
1056 : LOG_INFO,
1057 : "Configured trace limits for app id %s, context id %s, level %u\n",
1058 : apid_buf, ctid_buf, log_level_value);
1059 : } else {
1060 : dlt_vlog(LOG_INFO, "Configured trace limits for app id %s, level %u\n",
1061 : apid_buf, log_level_value);
1062 : }
1063 :
1064 : } /* while */
1065 : fclose(pFile);
1066 :
1067 : /* list must be sorted to speed up dlt_daemon_find_configured_app_id_ctx_id_settings */
1068 : qsort(daemon->app_id_log_level_settings,
1069 : daemon->num_app_id_log_level_settings,
1070 : sizeof(DltDaemonContextLogSettings), compare_app_id_conf);
1071 :
1072 : return 0;
1073 : }
1074 : #endif
1075 :
1076 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
1077 : static bool is_ascii_only(const char *str) {
1078 : while (*str) {
1079 : if ((unsigned char)*str > 127) {
1080 : return false;
1081 : }
1082 : str++;
1083 : }
1084 : return true;
1085 : }
1086 :
1087 : /**
1088 : * Load configuration file parser
1089 : */
1090 : int trace_load_config_file_parser(DltDaemon *daemon, DltDaemonLocal *daemon_local)
1091 : {
1092 : FILE *pFile;
1093 : const int max_tokens = 4;
1094 : const int min_tokens = 3;
1095 : char tokens[max_tokens][value_length];
1096 : char line[value_length - 1];
1097 : char app_id_value[value_length];
1098 : char ctx_id_value[value_length];
1099 : char soft_limit_value[value_length];
1100 : char hard_limit_value[value_length];
1101 : int i;
1102 : uint32_t soft_limit;
1103 : uint32_t hard_limit;
1104 :
1105 : char *pch;
1106 : const char *filename;
1107 :
1108 : bool skipped;
1109 :
1110 : if (daemon->preconfigured_trace_load_settings != NULL) {
1111 : free(daemon->preconfigured_trace_load_settings);
1112 : daemon->preconfigured_trace_load_settings = NULL;
1113 : daemon->preconfigured_trace_load_settings_count = 0;
1114 : }
1115 : daemon->preconfigured_trace_load_settings = malloc(sizeof(DltTraceLoadSettings));
1116 : if (daemon->preconfigured_trace_load_settings == NULL) {
1117 : dlt_log(LOG_CRIT, "Failed to allocate memory for trace load settings\n");
1118 : return DLT_RETURN_ERROR;
1119 : }
1120 :
1121 : /* open configuration file */
1122 : filename = daemon_local->flags.lvalue[0]
1123 : ? daemon_local->flags.lvalue
1124 : : CONFIGURATION_FILES_DIR "/dlt-trace-load.conf";
1125 :
1126 : pFile = fopen (filename, "r");
1127 : if (pFile == NULL) {
1128 : dlt_vlog(LOG_WARNING, "Cannot open trace load configuration file: %s\n",
1129 : filename);
1130 : return -errno;
1131 : }
1132 :
1133 : while (1) {
1134 : /* fetch line from configuration file */
1135 : if (fgets(line, value_length - 1, pFile) == NULL) {
1136 : break;
1137 : }
1138 :
1139 : pch = strtok(line, " ");
1140 : app_id_value[0] = 0;
1141 : ctx_id_value[0] = 0;
1142 : soft_limit_value[0] = 0;
1143 : hard_limit_value[0] = 0;
1144 : soft_limit = 0U;
1145 : hard_limit = 0U;
1146 : memset(tokens, 0, sizeof(tokens));
1147 : i = 0;
1148 :
1149 : skipped = false;
1150 : while (pch != NULL && i < max_tokens) {
1151 : /* ignore comments, empty lines and new lines */
1152 : if (strncmp(pch, "#", 1) == 0 || strncmp(pch, "\n", 1) == 0 ||
1153 : strncmp(pch, "\r", 1) == 0 || strncmp(pch, " ", 1) == 0) {
1154 : skipped = true;
1155 : break;
1156 : }
1157 : strncpy(tokens[i], pch, sizeof(tokens[i]) - 1);
1158 : pch = strtok(NULL, " ");
1159 : ++i;
1160 : }
1161 :
1162 : if (skipped && i < min_tokens)
1163 : continue;
1164 :
1165 : if (pch != NULL
1166 : && (pch[0] != '\n')
1167 : && (pch[0] != '\t')
1168 : && (pch[0] != ' ')
1169 : && (pch[0] != '#')) {
1170 : dlt_vlog(LOG_WARNING,
1171 : "Invalid trace load settings: too many tokens in line '%s'\n", line);
1172 : continue;
1173 : }
1174 :
1175 : bool has_ctx_id = i == max_tokens;
1176 : int soft_limit_idx = has_ctx_id ? 2 : 1;
1177 : int hard_limit_idx = has_ctx_id ? 3 : 2;
1178 :
1179 : strncpy(app_id_value, tokens[0], sizeof(app_id_value) - 1);
1180 : if ((strlen(app_id_value) == 0)
1181 : || (strlen(app_id_value) > DLT_ID_SIZE)
1182 : || (!is_ascii_only(app_id_value))) {
1183 : dlt_vlog(LOG_WARNING,
1184 : "Invalid apid for trace load settings: app id: '%s'\n", app_id_value);
1185 : continue;
1186 : }
1187 :
1188 : if (has_ctx_id) {
1189 : strncpy(ctx_id_value, tokens[1], sizeof(ctx_id_value) - 1);
1190 : if ((strlen(ctx_id_value) == 0)
1191 : || (strlen(ctx_id_value) > DLT_ID_SIZE)
1192 : || (!is_ascii_only(ctx_id_value))) {
1193 : dlt_vlog(LOG_WARNING,
1194 : "Invalid ctid for trace load settings: context id: '%s'\n", ctx_id_value);
1195 : continue;
1196 : }
1197 : }
1198 :
1199 : if (strlen(tokens[soft_limit_idx]) == 0) {
1200 : dlt_vlog(LOG_WARNING,
1201 : "Invalid soft_limit for trace load settings: app id: '%.4s', '%s'\n",
1202 : app_id_value, tokens[soft_limit_idx]);
1203 : continue;
1204 : }
1205 :
1206 : if (strlen(tokens[hard_limit_idx]) == 0) {
1207 : dlt_vlog(LOG_WARNING,
1208 : "Invalid hard_limit for trace load settings: app id: '%.4s', '%s'\n",
1209 : app_id_value, tokens[hard_limit_idx]);
1210 : continue;
1211 : }
1212 :
1213 : strncpy(soft_limit_value, tokens[soft_limit_idx],
1214 : sizeof(soft_limit_value) - 1);
1215 : strncpy(hard_limit_value, tokens[hard_limit_idx],
1216 : sizeof(hard_limit_value) - 1);
1217 :
1218 : errno = 0;
1219 : char *endptr;
1220 : endptr = NULL;
1221 : soft_limit = strtoul(soft_limit_value, &endptr, 10);
1222 : if ((errno != 0)
1223 : || ((soft_limit == 0) && (soft_limit_value[0] != '0'))
1224 : || (soft_limit_value[0] == '-')
1225 : || ((*endptr != '\n') && (*endptr != '\0'))) {
1226 : dlt_vlog(LOG_WARNING,
1227 : "Invalid soft_limit for trace load settings: app id: '%.4s', soft_limit '%s'\n",
1228 : app_id_value, soft_limit_value);
1229 : continue;
1230 : }
1231 :
1232 : errno = 0;
1233 : endptr = NULL;
1234 : hard_limit = strtoul(hard_limit_value, &endptr, 10);
1235 : if ((errno != 0)
1236 : || ((hard_limit == 0) && (hard_limit_value[0] != '0'))
1237 : || (hard_limit_value[0] == '-')
1238 : || ((*endptr != '\n') && (*endptr != '\0'))) {
1239 : dlt_vlog(LOG_WARNING,
1240 : "Invalid hard_limit for trace load settings: app id: '%.4s', hard_limit '%s'\n",
1241 : app_id_value, hard_limit_value);
1242 : continue;
1243 : }
1244 :
1245 : if (soft_limit > hard_limit) {
1246 : dlt_vlog(LOG_WARNING,
1247 : "Invalid trace load settings: app id: '%.4s', soft limit %u is greater than hard limit %u\n",
1248 : app_id_value, soft_limit, hard_limit);
1249 : continue;
1250 : }
1251 :
1252 : DltTraceLoadSettings *settings = NULL;
1253 : int num_settings = 0;
1254 : DltReturnValue find_trace_settings_return_value = dlt_daemon_find_preconfigured_trace_load_settings(
1255 : daemon, app_id_value, ctx_id_value, &settings, &num_settings,
1256 : 0);
1257 : if (find_trace_settings_return_value != DLT_RETURN_OK || num_settings != 0) {
1258 : dlt_vlog(LOG_WARNING,
1259 : "App id '%.4s' is already configured, or an error occurred, skipping entry\n",
1260 : app_id_value);
1261 : if (settings != NULL) {
1262 : free(settings);
1263 : }
1264 : continue;
1265 : }
1266 :
1267 : /* allocate one more element in the trace load settings */
1268 : DltTraceLoadSettings *tmp =
1269 : realloc(daemon->preconfigured_trace_load_settings,
1270 : (++daemon->preconfigured_trace_load_settings_count) *
1271 : sizeof(DltTraceLoadSettings));
1272 :
1273 : if (tmp == NULL) {
1274 : dlt_log(LOG_CRIT,
1275 : "Failed to allocate memory for trace load settings\n");
1276 : return DLT_RETURN_ERROR;
1277 : }
1278 :
1279 : daemon->preconfigured_trace_load_settings = tmp;
1280 : settings = &daemon->preconfigured_trace_load_settings
1281 : [daemon->preconfigured_trace_load_settings_count - 1];
1282 : memset(settings, 0, sizeof(DltTraceLoadSettings));
1283 : settings->soft_limit = soft_limit;
1284 : settings->hard_limit = hard_limit;
1285 :
1286 : memcpy(settings->apid, app_id_value, DLT_ID_SIZE);
1287 : if (has_ctx_id) {
1288 : memcpy(settings->ctid, ctx_id_value, DLT_ID_SIZE);
1289 : dlt_vlog(LOG_INFO,
1290 : "Configured trace limits for app id '%.4s', ctx id '%.4s', soft limit: %u, hard_limit: %u\n",
1291 : app_id_value, ctx_id_value, soft_limit, hard_limit);
1292 : } else {
1293 : dlt_vlog(LOG_INFO,
1294 : "Configured trace limits for app id '%.4s', soft limit: %u, hard_limit: %u\n",
1295 : app_id_value, soft_limit, hard_limit);
1296 : }
1297 :
1298 :
1299 :
1300 : } /* while */
1301 : fclose(pFile);
1302 :
1303 : // sort limits to improve search performance
1304 : qsort(daemon->preconfigured_trace_load_settings, daemon->preconfigured_trace_load_settings_count,
1305 : sizeof(DltTraceLoadSettings),
1306 : dlt_daemon_compare_trace_load_settings);
1307 : return 0;
1308 : }
1309 : #endif
1310 :
1311 9 : static int dlt_mkdir_recursive(const char *dir)
1312 : {
1313 : int ret = 0;
1314 : char tmp[PATH_MAX + 1];
1315 : char *p = NULL;
1316 : char *end = NULL;
1317 : size_t len;
1318 :
1319 : strncpy(tmp, dir, PATH_MAX);
1320 9 : len = strlen(tmp);
1321 :
1322 9 : if (tmp[len - 1] == '/')
1323 0 : tmp[len - 1] = 0;
1324 :
1325 9 : end = tmp + len;
1326 :
1327 36 : for (p = tmp + 1; ((*p) && (ret == 0)) || ((ret == -1 && errno == EEXIST) && (p != end)); p++)
1328 27 : if (*p == '/') {
1329 0 : *p = 0;
1330 :
1331 0 : if (access(tmp, F_OK) != 0 && errno == ENOENT) {
1332 0 : ret = mkdir(tmp,
1333 : #ifdef DLT_DAEMON_USE_FIFO_IPC
1334 : S_IRWXU);
1335 : #else
1336 : S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH /*S_IRWXU*/);
1337 : #endif
1338 : }
1339 :
1340 0 : *p = '/';
1341 : }
1342 :
1343 :
1344 :
1345 9 : if ((ret == 0) || ((ret == -1) && (errno == EEXIST)))
1346 9 : ret = mkdir(tmp,
1347 : #ifdef DLT_DAEMON_USE_FIFO_IPC
1348 : S_IRWXU);
1349 : #else
1350 : S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH /*S_IRWXU*/);
1351 : #endif
1352 :
1353 9 : if ((ret == -1) && (errno == EEXIST))
1354 : ret = 0;
1355 :
1356 9 : return ret;
1357 : }
1358 :
1359 : #ifdef DLT_DAEMON_USE_FIFO_IPC
1360 9 : static DltReturnValue dlt_daemon_create_pipes_dir(char *dir)
1361 : {
1362 : int ret = DLT_RETURN_OK;
1363 :
1364 9 : if (dir == NULL) {
1365 0 : dlt_vlog(LOG_ERR, "%s: Invalid parameter\n", __func__);
1366 0 : return DLT_RETURN_WRONG_PARAMETER;
1367 : }
1368 :
1369 : /* create dlt pipes directory */
1370 9 : ret = mkdir(dir,
1371 : S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH | S_ISVTX);
1372 :
1373 9 : if ((ret == -1) && (errno != EEXIST)) {
1374 0 : dlt_vlog(LOG_ERR,
1375 : "FIFO user dir %s cannot be created (%s)!\n",
1376 : dir,
1377 : strerror(errno));
1378 :
1379 0 : return DLT_RETURN_ERROR;
1380 : }
1381 :
1382 : /* S_ISGID cannot be set by mkdir, let's reassign right bits */
1383 9 : ret = chmod(dir,
1384 : S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH | S_ISGID |
1385 : S_ISVTX);
1386 :
1387 9 : if (ret == -1) {
1388 0 : dlt_vlog(LOG_ERR,
1389 : "FIFO user dir %s cannot be chmoded (%s)!\n",
1390 : dir,
1391 0 : strerror(errno));
1392 :
1393 0 : return DLT_RETURN_ERROR;
1394 : }
1395 :
1396 : return ret;
1397 : }
1398 : #endif
1399 : // This will be defined when unit testing, so functions
1400 : // from this file can be tested without defining main twice
1401 : #ifndef DLT_DAEMON_UNIT_TESTS_NO_MAIN
1402 : /**
1403 : * Main function of tool.
1404 : */
1405 9 : int main(int argc, char *argv[])
1406 : {
1407 : char version[DLT_DAEMON_TEXTBUFSIZE];
1408 : char local_str[DLT_DAEMON_TEXTBUFSIZE];
1409 : DltDaemonLocal daemon_local;
1410 : DltDaemon daemon;
1411 : int back = 0;
1412 :
1413 : memset(&daemon_local, 0, sizeof(DltDaemonLocal));
1414 : memset(&daemon, 0, sizeof(DltDaemon));
1415 :
1416 : /* Command line option handling */
1417 9 : if ((back = option_handling(&daemon_local, argc, argv)) < 0) {
1418 0 : if (back != -2)
1419 0 : fprintf (stderr, "option_handling() failed!\n");
1420 :
1421 0 : return -1;
1422 : }
1423 :
1424 : /* Configuration file option handling */
1425 9 : if ((back = option_file_parser(&daemon_local)) < 0) {
1426 0 : if (back != -2)
1427 0 : fprintf (stderr, "option_file_parser() failed!\n");
1428 :
1429 0 : return -1;
1430 : }
1431 :
1432 : /* Initialize internal logging facility */
1433 9 : dlt_log_set_filename(daemon_local.flags.loggingFilename);
1434 9 : dlt_log_set_level(daemon_local.flags.loggingLevel);
1435 : DltReturnValue log_init_result =
1436 9 : dlt_log_init_multiple_logfiles_support(daemon_local.flags.loggingMode,
1437 9 : daemon_local.flags.enableLoggingFileLimit,
1438 : daemon_local.flags.loggingFileSize,
1439 : daemon_local.flags.loggingFileMaxSize);
1440 :
1441 9 : if (log_init_result != DLT_RETURN_OK) {
1442 0 : fprintf(stderr, "Failed to init internal logging\n");
1443 :
1444 : #if WITH_DLT_FILE_LOGGING_SYSLOG_FALLBACK
1445 : if (daemon_local.flags.loggingMode == DLT_LOG_TO_FILE) {
1446 : fprintf(stderr, "Falling back to syslog mode\n");
1447 :
1448 : daemon_local.flags.loggingMode = DLT_LOG_TO_SYSLOG;
1449 : log_init_result = dlt_log_init(daemon_local.flags.loggingMode);
1450 : if (log_init_result != DLT_RETURN_OK) {
1451 : fprintf(stderr, "Failed to setup syslog logging, internal logs will "
1452 : "not be available\n");
1453 : }
1454 : }
1455 : #endif
1456 : }
1457 :
1458 : /* Print version information */
1459 9 : dlt_get_version(version, DLT_DAEMON_TEXTBUFSIZE);
1460 :
1461 9 : dlt_vlog(LOG_NOTICE, "Starting DLT Daemon; %s\n", version);
1462 :
1463 9 : PRINT_FUNCTION_VERBOSE(daemon_local.flags.vflag);
1464 :
1465 : /* Make sure the parent user directory is created */
1466 : #ifdef DLT_DAEMON_USE_FIFO_IPC
1467 :
1468 9 : if (dlt_mkdir_recursive(dltFifoBaseDir) != 0) {
1469 0 : dlt_vlog(LOG_ERR, "Base dir %s cannot be created!\n", dltFifoBaseDir);
1470 0 : return -1;
1471 : }
1472 :
1473 : #else
1474 : if (dlt_mkdir_recursive(DLT_USER_IPC_PATH) != 0) {
1475 : dlt_vlog(LOG_ERR, "Base dir %s cannot be created!\n", daemon_local.flags.appSockPath);
1476 : return -1;
1477 : }
1478 :
1479 : #endif
1480 :
1481 : /* --- Daemon init phase 1 begin --- */
1482 9 : if (dlt_daemon_local_init_p1(&daemon, &daemon_local, daemon_local.flags.vflag) == -1) {
1483 0 : dlt_log(LOG_CRIT, "Initialization of phase 1 failed!\n");
1484 0 : return -1;
1485 : }
1486 :
1487 : /* --- Daemon init phase 1 end --- */
1488 :
1489 9 : if (dlt_daemon_prepare_event_handling(&daemon_local.pEvent)) {
1490 : /* TODO: Perform clean-up */
1491 0 : dlt_log(LOG_CRIT, "Initialization of event handling failed!\n");
1492 0 : return -1;
1493 : }
1494 :
1495 : /* --- Daemon connection init begin */
1496 9 : if (dlt_daemon_local_connection_init(&daemon, &daemon_local, daemon_local.flags.vflag) == -1) {
1497 0 : dlt_log(LOG_CRIT, "Initialization of local connections failed!\n");
1498 0 : return -1;
1499 : }
1500 :
1501 : /* --- Daemon connection init end */
1502 :
1503 9 : if (dlt_daemon_init_runtime_configuration(&daemon, daemon_local.flags.ivalue, daemon_local.flags.vflag) == -1) {
1504 0 : dlt_log(LOG_ERR, "Could not load runtime config\n");
1505 0 : return -1;
1506 : }
1507 :
1508 : /*
1509 : * Load dlt-runtime.cfg if available.
1510 : * This must be loaded before offline setup
1511 : */
1512 9 : dlt_daemon_configuration_load(&daemon, daemon.runtime_configuration, daemon_local.flags.vflag);
1513 :
1514 : /* --- Daemon init phase 2 begin --- */
1515 9 : if (dlt_daemon_local_init_p2(&daemon, &daemon_local, daemon_local.flags.vflag) == -1) {
1516 0 : dlt_log(LOG_CRIT, "Initialization of phase 2 failed!\n");
1517 0 : return -1;
1518 : }
1519 :
1520 : #ifdef DLT_LOG_LEVEL_APP_CONFIG
1521 : /* Load control app id level configuration file without setting `back` to
1522 : * prevent exit if file is missing */
1523 : if (app_id_default_log_level_config_parser(&daemon, &daemon_local) < 0) {
1524 : dlt_vlog(LOG_WARNING, "app_id_default_log_level_config_parser() failed, "
1525 : "no app specific log levels will be configured\n");
1526 : }
1527 : #endif
1528 :
1529 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
1530 : /* Load control trace load configuration file without setting `back` to prevent exit if file is missing */
1531 : pthread_rwlock_init(&trace_load_rw_lock, NULL);
1532 : if (trace_load_config_file_parser(&daemon, &daemon_local) < 0) {
1533 : dlt_vlog(LOG_WARNING, "trace_load_config_file_parser() failed, using defaults for all app ids!\n");
1534 : }
1535 : #endif
1536 :
1537 : /* --- Daemon init phase 2 end --- */
1538 :
1539 9 : if (daemon_local.flags.offlineLogstorageDirPath[0])
1540 6 : if (dlt_daemon_logstorage_setup_internal_storage(
1541 : &daemon,
1542 : &daemon_local,
1543 : daemon_local.flags.offlineLogstorageDirPath,
1544 : daemon_local.flags.vflag) == -1)
1545 0 : dlt_log(LOG_INFO,
1546 : "Setting up internal offline log storage failed!\n");
1547 :
1548 : /* create fd for watchdog */
1549 : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
1550 : {
1551 : char *watchdogUSec = getenv("WATCHDOG_USEC");
1552 : // set a sensible default, in case the environment variable is not set
1553 : int watchdogTimeoutSeconds = 30;
1554 :
1555 : dlt_log(LOG_DEBUG, "Systemd watchdog initialization\n");
1556 :
1557 : if (watchdogUSec) {
1558 : // WATCHDOG_USEC is the timeout in micrsoseconds
1559 : // divide this by 2*10^6 to get the interval in seconds
1560 : // 2 * because we notify systemd after half the timeout
1561 : watchdogTimeoutSeconds = atoi(watchdogUSec) / 2000000;
1562 : }
1563 :
1564 : if (watchdogTimeoutSeconds == 0) {
1565 : dlt_log(LOG_WARNING, "Watchdog timeout is too small, need at least 1s, setting 30s timeout\n");
1566 : watchdogTimeoutSeconds = 30;
1567 : }
1568 :
1569 : daemon.watchdog_trigger_interval = watchdogTimeoutSeconds;
1570 : daemon.watchdog_last_trigger_time = 0U;
1571 : create_timer_fd(&daemon_local,
1572 : watchdogTimeoutSeconds,
1573 : watchdogTimeoutSeconds,
1574 : DLT_TIMER_SYSTEMD);
1575 : }
1576 : #endif
1577 :
1578 : /* create fd for timer timing packets */
1579 9 : create_timer_fd(&daemon_local, 1, 1, DLT_TIMER_PACKET);
1580 :
1581 : /* create fd for timer ecu version */
1582 9 : if ((daemon_local.flags.sendECUSoftwareVersion > 0) ||
1583 9 : (daemon_local.flags.sendTimezone > 0))
1584 0 : create_timer_fd(&daemon_local, 60, 60, DLT_TIMER_ECU);
1585 :
1586 : /* initiate gateway */
1587 9 : if (daemon_local.flags.gatewayMode == 1) {
1588 1 : if (dlt_gateway_init(&daemon_local, daemon_local.flags.vflag) == -1) {
1589 0 : dlt_log(LOG_CRIT, "Failed to create gateway\n");
1590 0 : return -1;
1591 : }
1592 :
1593 : /* create gateway timer */
1594 1 : create_timer_fd(&daemon_local,
1595 : daemon_local.pGateway.interval,
1596 : daemon_local.pGateway.interval,
1597 : DLT_TIMER_GATEWAY);
1598 : }
1599 :
1600 : /* For offline tracing we still can use the same states */
1601 : /* as for socket sending. Using this trick we see the traces */
1602 : /* In the offline trace AND in the socket stream. */
1603 9 : if (daemon_local.flags.yvalue[0])
1604 0 : dlt_daemon_change_state(&daemon, DLT_DAEMON_STATE_SEND_DIRECT);
1605 : else
1606 9 : dlt_daemon_change_state(&daemon, DLT_DAEMON_STATE_BUFFER);
1607 :
1608 9 : dlt_daemon_init_user_information(&daemon,
1609 : &daemon_local.pGateway,
1610 : daemon_local.flags.gatewayMode,
1611 : daemon_local.flags.vflag);
1612 :
1613 : /*
1614 : * Check for app and ctx runtime cfg.
1615 : * These cfg must be loaded after ecuId and num_user_lists are available
1616 : */
1617 9 : if ((dlt_daemon_applications_load(&daemon, daemon.runtime_application_cfg,
1618 0 : daemon_local.flags.vflag) == 0) &&
1619 0 : (dlt_daemon_contexts_load(&daemon, daemon.runtime_context_cfg,
1620 : daemon_local.flags.vflag) == 0))
1621 0 : daemon.runtime_context_cfg_loaded = 1;
1622 :
1623 9 : dlt_daemon_log_internal(&daemon, &daemon_local,
1624 : "Daemon launched. Starting to output traces...",
1625 : DLT_LOG_INFO, DLT_DAEMON_APP_ID, DLT_DAEMON_CTX_ID,
1626 : daemon_local.flags.vflag);
1627 :
1628 : /* Even handling loop. */
1629 1415 : while ((back >= 0) && (g_exit >= 0))
1630 1406 : back = dlt_daemon_handle_event(&daemon_local.pEvent,
1631 : &daemon,
1632 : &daemon_local);
1633 :
1634 9 : snprintf(local_str, DLT_DAEMON_TEXTBUFSIZE, "Exiting DLT daemon... [%d]",
1635 : g_signo);
1636 9 : dlt_daemon_log_internal(&daemon, &daemon_local, local_str, DLT_LOG_INFO,
1637 : DLT_DAEMON_APP_ID, DLT_DAEMON_CTX_ID,
1638 : daemon_local.flags.vflag);
1639 9 : dlt_vlog(LOG_NOTICE, "%s%s", local_str, "\n");
1640 :
1641 9 : dlt_daemon_local_cleanup(&daemon, &daemon_local, daemon_local.flags.vflag);
1642 :
1643 : #ifdef UDP_CONNECTION_SUPPORT
1644 : dlt_daemon_udp_close_connection();
1645 : #endif
1646 :
1647 9 : dlt_gateway_deinit(&daemon_local.pGateway, daemon_local.flags.vflag);
1648 :
1649 9 : dlt_daemon_free(&daemon, daemon_local.flags.vflag);
1650 :
1651 9 : dlt_log(LOG_NOTICE, "Leaving DLT daemon\n");
1652 :
1653 9 : dlt_log_free();
1654 :
1655 9 : return 0;
1656 :
1657 : } /* main() */
1658 : #endif
1659 :
1660 9 : int dlt_daemon_local_init_p1(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose)
1661 : {
1662 9 : PRINT_FUNCTION_VERBOSE(verbose);
1663 : int ret = DLT_RETURN_OK;
1664 :
1665 9 : if ((daemon == 0) || (daemon_local == 0)) {
1666 0 : dlt_log(LOG_ERR, "Invalid function parameters used for function dlt_daemon_local_init_p1()\n");
1667 0 : return -1;
1668 : }
1669 :
1670 : #if defined(DLT_SYSTEMD_WATCHDOG_ENABLE) || defined(DLT_SYSTEMD_ENABLE)
1671 : ret = sd_booted();
1672 :
1673 : if (ret == 0) {
1674 : dlt_log(LOG_CRIT, "System not booted with systemd!\n");
1675 : }
1676 : else if (ret < 0)
1677 : {
1678 : dlt_log(LOG_CRIT, "sd_booted failed!\n");
1679 : return -1;
1680 : }
1681 : else {
1682 : dlt_log(LOG_INFO, "System booted with systemd\n");
1683 : }
1684 :
1685 : #endif
1686 :
1687 : #ifdef DLT_DAEMON_USE_FIFO_IPC
1688 :
1689 9 : if (dlt_daemon_create_pipes_dir(daemon_local->flags.userPipesDir) == DLT_RETURN_ERROR)
1690 : return DLT_RETURN_ERROR;
1691 :
1692 : #endif
1693 :
1694 : /* Check for daemon mode */
1695 9 : if (daemon_local->flags.dflag)
1696 2 : dlt_daemon_daemonize(daemon_local->flags.vflag);
1697 :
1698 : /* initialise structure to use DLT file */
1699 9 : ret = dlt_file_init(&(daemon_local->file), daemon_local->flags.vflag);
1700 :
1701 9 : if (ret == DLT_RETURN_ERROR) {
1702 0 : dlt_log(LOG_ERR, "Could not initialize file structure\n");
1703 : /* Return value ignored, dlt daemon will exit */
1704 0 : dlt_file_free(&(daemon_local->file), daemon_local->flags.vflag);
1705 0 : return ret;
1706 : }
1707 :
1708 9 : signal(SIGPIPE, SIG_IGN);
1709 :
1710 9 : signal(SIGTERM, dlt_daemon_signal_handler); /* software termination signal from kill */
1711 9 : signal(SIGHUP, dlt_daemon_signal_handler); /* hangup signal */
1712 9 : signal(SIGQUIT, dlt_daemon_signal_handler);
1713 9 : signal(SIGINT, dlt_daemon_signal_handler);
1714 : #ifdef __QNX__
1715 : signal(SIGUSR1, dlt_daemon_signal_handler); /* for timer threads */
1716 : #endif
1717 :
1718 9 : return DLT_RETURN_OK;
1719 : }
1720 :
1721 9 : int dlt_daemon_local_init_p2(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose)
1722 : {
1723 9 : PRINT_FUNCTION_VERBOSE(verbose);
1724 :
1725 9 : if ((daemon == 0) || (daemon_local == 0)) {
1726 0 : dlt_log(LOG_ERR, "Invalid function parameters used for function dlt_daemon_local_init_p2()\n");
1727 0 : return -1;
1728 : }
1729 :
1730 : /* Daemon data */
1731 9 : if (dlt_daemon_init(daemon, daemon_local->RingbufferMinSize, daemon_local->RingbufferMaxSize,
1732 9 : daemon_local->RingbufferStepSize, daemon_local->flags.ivalue,
1733 : daemon_local->flags.contextLogLevel,
1734 : daemon_local->flags.contextTraceStatus, daemon_local->flags.enforceContextLLAndTS,
1735 : daemon_local->flags.vflag) == -1) {
1736 0 : dlt_log(LOG_ERR, "Could not initialize daemon data\n");
1737 0 : return -1;
1738 : }
1739 :
1740 : /* init offline trace */
1741 9 : if (((daemon->mode == DLT_USER_MODE_INTERNAL) || (daemon->mode == DLT_USER_MODE_BOTH)) &&
1742 0 : daemon_local->flags.offlineTraceDirectory[0]) {
1743 0 : if (multiple_files_buffer_init(&(daemon_local->offlineTrace),
1744 0 : daemon_local->flags.offlineTraceDirectory,
1745 : daemon_local->flags.offlineTraceFileSize,
1746 : daemon_local->flags.offlineTraceMaxSize,
1747 0 : daemon_local->flags.offlineTraceFilenameTimestampBased,
1748 : false,
1749 : DLT_OFFLINETRACE_FILENAME_BASE,
1750 : DLT_OFFLINETRACE_FILENAME_EXT) == -1) {
1751 0 : dlt_log(LOG_ERR, "Could not initialize offline trace\n");
1752 0 : return -1;
1753 : }
1754 : }
1755 :
1756 : /* Init offline logstorage for MAX devices */
1757 9 : if (daemon_local->flags.offlineLogstorageMaxDevices > 0) {
1758 6 : daemon->storage_handle = malloc(sizeof(DltLogStorage) * daemon_local->flags.offlineLogstorageMaxDevices);
1759 :
1760 6 : if (daemon->storage_handle == NULL) {
1761 0 : dlt_log(LOG_ERR, "Could not initialize offline logstorage\n");
1762 0 : return -1;
1763 : }
1764 :
1765 : memset(daemon->storage_handle, 0, (sizeof(DltLogStorage) * daemon_local->flags.offlineLogstorageMaxDevices));
1766 : }
1767 :
1768 : /* Set ECU id of daemon */
1769 9 : if (daemon_local->flags.evalue[0])
1770 1 : dlt_set_id(daemon->ecuid, daemon_local->flags.evalue);
1771 : else
1772 8 : dlt_set_id(daemon->ecuid, DLT_DAEMON_ECU_ID);
1773 :
1774 : /* Set flag for optional sending of serial header */
1775 9 : daemon->sendserialheader = daemon_local->flags.lflag;
1776 :
1777 : #ifdef DLT_SHM_ENABLE
1778 :
1779 : /* init shared memory */
1780 : if (dlt_shm_init_server(&(daemon_local->dlt_shm), daemon_local->flags.dltShmName,
1781 : daemon_local->flags.sharedMemorySize) == DLT_RETURN_ERROR) {
1782 : dlt_log(LOG_ERR, "Could not initialize shared memory\n");
1783 : return -1;
1784 : }
1785 :
1786 : daemon_local->recv_buf_shm = (unsigned char *)calloc(1, DLT_SHM_RCV_BUFFER_SIZE);
1787 :
1788 : if (NULL == daemon_local->recv_buf_shm) {
1789 : dlt_log(LOG_ERR, "failed to allocated the buffer to receive shm data\n");
1790 : return -1;
1791 : }
1792 :
1793 : #endif
1794 :
1795 : /* prepare main loop */
1796 9 : if (dlt_message_init(&(daemon_local->msg), daemon_local->flags.vflag) == DLT_RETURN_ERROR) {
1797 0 : dlt_log(LOG_ERR, "Could not initialize message\n");
1798 0 : return -1;
1799 : }
1800 :
1801 : /* configure sending timing packets */
1802 9 : if (daemon_local->flags.sendMessageTime)
1803 0 : daemon->timingpackets = 1;
1804 :
1805 : /* Get ECU version info from a file. If it fails, use dlt_version as fallback. */
1806 9 : if (dlt_daemon_local_ecu_version_init(daemon, daemon_local, daemon_local->flags.vflag) < 0) {
1807 9 : daemon->ECUVersionString = malloc(DLT_DAEMON_TEXTBUFSIZE);
1808 :
1809 9 : if (daemon->ECUVersionString == 0) {
1810 0 : dlt_log(LOG_WARNING, "Could not allocate memory for version string\n");
1811 0 : return -1;
1812 : }
1813 :
1814 9 : dlt_get_version(daemon->ECUVersionString, DLT_DAEMON_TEXTBUFSIZE);
1815 : }
1816 :
1817 : /* Set to allows to maintain logstorage loglevel as default */
1818 9 : daemon->maintain_logstorage_loglevel = DLT_MAINTAIN_LOGSTORAGE_LOGLEVEL_ON;
1819 :
1820 9 : return 0;
1821 : }
1822 :
1823 9 : static int dlt_daemon_init_serial(DltDaemonLocal *daemon_local)
1824 : {
1825 : /* create and open serial connection from/to client */
1826 : /* open serial connection */
1827 : int fd = -1;
1828 :
1829 9 : if (daemon_local->flags.yvalue[0] == '\0')
1830 : return 0;
1831 :
1832 0 : fd = open(daemon_local->flags.yvalue, O_RDWR);
1833 :
1834 0 : if (fd < 0) {
1835 0 : dlt_vlog(LOG_ERR, "Failed to open serial device %s\n",
1836 : daemon_local->flags.yvalue);
1837 :
1838 0 : daemon_local->flags.yvalue[0] = 0;
1839 0 : return -1;
1840 : }
1841 :
1842 0 : if (isatty(fd)) {
1843 : int speed = DLT_DAEMON_SERIAL_DEFAULT_BAUDRATE;
1844 :
1845 0 : if (daemon_local->flags.bvalue[0])
1846 0 : speed = atoi(daemon_local->flags.bvalue);
1847 :
1848 0 : daemon_local->baudrate = dlt_convert_serial_speed(speed);
1849 :
1850 0 : if (dlt_setup_serial(fd, (speed_t) daemon_local->baudrate) < 0) {
1851 0 : close(fd);
1852 0 : daemon_local->flags.yvalue[0] = 0;
1853 :
1854 0 : dlt_vlog(LOG_ERR, "Failed to configure serial device %s (%s) \n",
1855 0 : daemon_local->flags.yvalue, strerror(errno));
1856 :
1857 0 : return -1;
1858 : }
1859 :
1860 0 : if (daemon_local->flags.vflag)
1861 0 : dlt_log(LOG_DEBUG, "Serial init done\n");
1862 : }
1863 : else {
1864 0 : close(fd);
1865 0 : fprintf(stderr,
1866 : "Device is not a serial device, device = %s (%s) \n",
1867 : daemon_local->flags.yvalue,
1868 0 : strerror(errno));
1869 0 : daemon_local->flags.yvalue[0] = 0;
1870 0 : return -1;
1871 : }
1872 :
1873 0 : return dlt_connection_create(daemon_local,
1874 : &daemon_local->pEvent,
1875 : fd,
1876 : POLLIN,
1877 : DLT_CONNECTION_CLIENT_MSG_SERIAL);
1878 : }
1879 :
1880 : #ifdef DLT_DAEMON_USE_FIFO_IPC
1881 9 : static int dlt_daemon_init_fifo(DltDaemonLocal *daemon_local)
1882 : {
1883 : int ret;
1884 : int fd = -1;
1885 : int fifo_size;
1886 :
1887 : /* open named pipe(FIFO) to receive DLT messages from users */
1888 9 : umask(0);
1889 :
1890 : /* Try to delete existing pipe, ignore result of unlink */
1891 9 : const char *tmpFifo = daemon_local->flags.daemonFifoName;
1892 9 : unlink(tmpFifo);
1893 :
1894 9 : ret = mkfifo(tmpFifo, S_IRUSR | S_IWUSR | S_IWGRP);
1895 :
1896 9 : if (ret == -1) {
1897 0 : dlt_vlog(LOG_WARNING, "FIFO user %s cannot be created (%s)!\n",
1898 0 : tmpFifo, strerror(errno));
1899 0 : return -1;
1900 : } /* if */
1901 :
1902 : /* Set group of daemon FIFO */
1903 9 : if (daemon_local->flags.daemonFifoGroup[0] != 0) {
1904 0 : errno = 0;
1905 0 : struct group *group_dlt = getgrnam(daemon_local->flags.daemonFifoGroup);
1906 :
1907 0 : if (group_dlt) {
1908 0 : ret = chown(tmpFifo, -1, group_dlt->gr_gid);
1909 :
1910 0 : if (ret == -1)
1911 0 : dlt_vlog(LOG_ERR, "FIFO user %s cannot be chowned to group %s (%s)\n",
1912 : tmpFifo, daemon_local->flags.daemonFifoGroup,
1913 : strerror(errno));
1914 : }
1915 0 : else if ((errno == 0) || (errno == ENOENT) || (errno == EBADF) || (errno == EPERM))
1916 : {
1917 0 : dlt_vlog(LOG_ERR, "Group name %s is not found (%s)\n",
1918 : daemon_local->flags.daemonFifoGroup,
1919 : strerror(errno));
1920 : }
1921 : else {
1922 0 : dlt_vlog(LOG_ERR, "Failed to get group id of %s (%s)\n",
1923 : daemon_local->flags.daemonFifoGroup,
1924 : strerror(errno));
1925 : }
1926 : }
1927 :
1928 : fd = open(tmpFifo, O_RDWR);
1929 :
1930 9 : if (fd == -1) {
1931 0 : dlt_vlog(LOG_WARNING, "FIFO user %s cannot be opened (%s)!\n",
1932 0 : tmpFifo, strerror(errno));
1933 0 : return -1;
1934 : } /* if */
1935 :
1936 : #ifdef __linux__
1937 : /* F_SETPIPE_SZ and F_GETPIPE_SZ are only supported for Linux.
1938 : * For other OSes it depends on its system e.g. pipe manager.
1939 : */
1940 9 : if (daemon_local->daemonFifoSize != 0) {
1941 : /* Set Daemon FIFO size */
1942 0 : if (fcntl(fd, F_SETPIPE_SZ, daemon_local->daemonFifoSize) == -1)
1943 0 : dlt_vlog(LOG_ERR, "set FIFO size error: %s\n", strerror(errno));
1944 : }
1945 :
1946 : /* Get Daemon FIFO size */
1947 9 : if ((fifo_size = fcntl(fd, F_GETPIPE_SZ, 0)) == -1)
1948 0 : dlt_vlog(LOG_ERR, "get FIFO size error: %s\n", strerror(errno));
1949 : else
1950 9 : dlt_vlog(LOG_INFO, "FIFO size: %d\n", fifo_size);
1951 : #endif
1952 :
1953 : /* Early init, to be able to catch client (app) connections
1954 : * as soon as possible. This registration is automatically ignored
1955 : * during next execution.
1956 : */
1957 9 : return dlt_connection_create(daemon_local,
1958 : &daemon_local->pEvent,
1959 : fd,
1960 : POLLIN,
1961 : DLT_CONNECTION_APP_MSG);
1962 : }
1963 : #endif
1964 :
1965 : #ifdef DLT_DAEMON_VSOCK_IPC_ENABLE
1966 : static int dlt_daemon_init_vsock(DltDaemonLocal *daemon_local)
1967 : {
1968 : int fd;
1969 : struct sockaddr_vm addr;
1970 :
1971 : fd = socket(AF_VSOCK, SOCK_STREAM, 0);
1972 : if (fd == -1) {
1973 : dlt_vlog(LOG_ERR, "Failed to create VSOCK socket: %s\n", strerror(errno));
1974 : return -1;
1975 : }
1976 :
1977 : memset(&addr, 0, sizeof(addr));
1978 : addr.svm_family = AF_VSOCK;
1979 : addr.svm_port = DLT_VSOCK_PORT;
1980 : addr.svm_cid = VMADDR_CID_ANY;
1981 :
1982 : if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) {
1983 : dlt_vlog(LOG_ERR, "Failed to bind VSOCK socket: %s\n", strerror(errno));
1984 : close(fd);
1985 : return -1;
1986 : }
1987 :
1988 : if (listen(fd, 1) != 0) {
1989 : dlt_vlog(LOG_ERR, "Failed to listen on VSOCK socket: %s\n", strerror(errno));
1990 : close(fd);
1991 : return -1;
1992 : }
1993 :
1994 : return dlt_connection_create(daemon_local,
1995 : &daemon_local->pEvent,
1996 : fd,
1997 : POLLIN,
1998 : DLT_CONNECTION_APP_CONNECT);
1999 : }
2000 : #endif
2001 :
2002 : #ifdef DLT_DAEMON_USE_UNIX_SOCKET_IPC
2003 : static DltReturnValue dlt_daemon_init_app_socket(DltDaemonLocal *daemon_local)
2004 : {
2005 : /* socket access permission set to srw-rw-rw- (666) */
2006 : int mask = S_IXUSR | S_IXGRP | S_IXOTH;
2007 : DltReturnValue ret = DLT_RETURN_OK;
2008 : int fd = -1;
2009 :
2010 : if (daemon_local == NULL) {
2011 : dlt_vlog(LOG_ERR, "%s: Invalid function parameters\n", __func__);
2012 : return DLT_RETURN_ERROR;
2013 : }
2014 :
2015 : #ifdef ANDROID
2016 : /* on android if we want to use security contexts on Unix sockets,
2017 : * they should be created by init (see dlt-daemon.rc in src/daemon)
2018 : * and recovered through the below API */
2019 : ret = dlt_daemon_unix_android_get_socket(&fd, daemon_local->flags.appSockPath);
2020 : if (ret < DLT_RETURN_OK) {
2021 : /* we failed to get app socket created by init.
2022 : * To avoid blocking users to launch dlt-daemon only through
2023 : * init on android (e.g: by hand for debugging purpose), try to
2024 : * create app socket by ourselves */
2025 : ret = dlt_daemon_unix_socket_open(&fd,
2026 : daemon_local->flags.appSockPath,
2027 : SOCK_STREAM,
2028 : mask);
2029 : }
2030 : #else
2031 : ret = dlt_daemon_unix_socket_open(&fd,
2032 : daemon_local->flags.appSockPath,
2033 : SOCK_STREAM,
2034 : mask);
2035 : #endif
2036 : if (ret == DLT_RETURN_OK) {
2037 : if (dlt_connection_create(daemon_local,
2038 : &daemon_local->pEvent,
2039 : fd,
2040 : POLLIN,
2041 : DLT_CONNECTION_APP_CONNECT)) {
2042 : dlt_log(LOG_CRIT, "Could not create connection for app socket.\n");
2043 : return DLT_RETURN_ERROR;
2044 : }
2045 : }
2046 : else {
2047 : dlt_log(LOG_CRIT, "Could not create and open app socket.\n");
2048 : return DLT_RETURN_ERROR;
2049 : }
2050 :
2051 : return ret;
2052 : }
2053 : #endif
2054 :
2055 9 : static DltReturnValue dlt_daemon_initialize_control_socket(DltDaemonLocal *daemon_local)
2056 : {
2057 : /* socket access permission set to srw-rw---- (660) */
2058 : int mask = S_IXUSR | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
2059 : DltReturnValue ret = DLT_RETURN_OK;
2060 9 : int fd = -1;
2061 :
2062 9 : if (daemon_local == NULL) {
2063 0 : dlt_vlog(LOG_ERR, "%s: Invalid function parameters\n", __func__);
2064 0 : return -1;
2065 : }
2066 :
2067 : #ifdef ANDROID
2068 : /* on android if we want to use security contexts on Unix sockets,
2069 : * they should be created by init (see dlt-daemon.rc in src/daemon)
2070 : * and recovered through the below API */
2071 : ret = dlt_daemon_unix_android_get_socket(&fd, daemon_local->flags.ctrlSockPath);
2072 : if (ret < DLT_RETURN_OK) {
2073 : /* we failed to get app socket created by init.
2074 : * To avoid blocking users to launch dlt-daemon only through
2075 : * init on android (e.g by hand for debugging purpose), try to
2076 : * create app socket by ourselves */
2077 : ret = dlt_daemon_unix_socket_open(&fd,
2078 : daemon_local->flags.ctrlSockPath,
2079 : SOCK_STREAM,
2080 : mask);
2081 : }
2082 : #else
2083 9 : ret = dlt_daemon_unix_socket_open(&fd,
2084 9 : daemon_local->flags.ctrlSockPath,
2085 : SOCK_STREAM,
2086 : mask);
2087 : #endif
2088 9 : if (ret == DLT_RETURN_OK) {
2089 9 : if (dlt_connection_create(daemon_local,
2090 : &daemon_local->pEvent,
2091 : fd,
2092 : POLLIN,
2093 : DLT_CONNECTION_CONTROL_CONNECT) < DLT_RETURN_OK) {
2094 0 : dlt_log(LOG_ERR, "Could not initialize control socket.\n");
2095 : ret = DLT_RETURN_ERROR;
2096 : }
2097 : }
2098 :
2099 : return ret;
2100 : }
2101 :
2102 9 : int dlt_daemon_local_connection_init(DltDaemon *daemon,
2103 : DltDaemonLocal *daemon_local,
2104 : int verbose)
2105 : {
2106 9 : int fd = -1;
2107 :
2108 9 : PRINT_FUNCTION_VERBOSE(verbose);
2109 :
2110 9 : if ((daemon == NULL) || (daemon_local == NULL)) {
2111 0 : dlt_vlog(LOG_ERR, "%s: Invalid function parameters\n", __func__);
2112 0 : return -1;
2113 : }
2114 :
2115 9 : DltBindAddress_t *head = daemon_local->flags.ipNodes;
2116 :
2117 : #ifdef DLT_DAEMON_USE_UNIX_SOCKET_IPC
2118 : /* create and open socket to receive incoming connections from user application */
2119 : if (dlt_daemon_init_app_socket(daemon_local) < DLT_RETURN_OK) {
2120 : dlt_log(LOG_ERR, "Unable to initialize app socket.\n");
2121 : return DLT_RETURN_ERROR;
2122 : }
2123 :
2124 : #else /* DLT_DAEMON_USE_FIFO_IPC */
2125 :
2126 9 : if (dlt_daemon_init_fifo(daemon_local)) {
2127 0 : dlt_log(LOG_ERR, "Unable to initialize fifo.\n");
2128 0 : return DLT_RETURN_ERROR;
2129 : }
2130 :
2131 : #endif
2132 :
2133 : #ifdef DLT_DAEMON_VSOCK_IPC_ENABLE
2134 : if (dlt_daemon_init_vsock(daemon_local) != 0) {
2135 : dlt_log(LOG_ERR, "Unable to initialize app VSOCK socket.\n");
2136 : return DLT_RETURN_ERROR;
2137 : }
2138 : #endif
2139 :
2140 : /* create and open socket to receive incoming connections from client */
2141 9 : daemon_local->client_connections = 0;
2142 :
2143 9 : if (head == NULL) { /* no IP set in BindAddress option, will use "0.0.0.0" as default */
2144 :
2145 9 : if (dlt_daemon_socket_open(&fd, daemon_local->flags.port, "0.0.0.0") == DLT_RETURN_OK) {
2146 9 : if (dlt_connection_create(daemon_local,
2147 : &daemon_local->pEvent,
2148 : fd,
2149 : POLLIN,
2150 : DLT_CONNECTION_CLIENT_CONNECT)) {
2151 0 : dlt_log(LOG_ERR, "Could not initialize main socket.\n");
2152 0 : return DLT_RETURN_ERROR;
2153 : }
2154 : }
2155 : else {
2156 0 : dlt_log(LOG_ERR, "Could not initialize main socket.\n");
2157 0 : return DLT_RETURN_ERROR;
2158 : }
2159 : }
2160 : else {
2161 : bool any_open = false;
2162 0 : while (head != NULL) { /* open socket for each IP in the bindAddress list */
2163 :
2164 0 : if (dlt_daemon_socket_open(&fd, daemon_local->flags.port, head->ip) == DLT_RETURN_OK) {
2165 0 : if (dlt_connection_create(daemon_local,
2166 : &daemon_local->pEvent,
2167 : fd,
2168 : POLLIN,
2169 : DLT_CONNECTION_CLIENT_CONNECT)) {
2170 0 : dlt_vlog(LOG_ERR, "Could not create connection, for binding %s\n", head->ip);
2171 : } else {
2172 : any_open = true;
2173 : }
2174 : }
2175 : else {
2176 0 : dlt_vlog(LOG_ERR, "Could not open main socket, for binding %s\n", head->ip);
2177 : }
2178 :
2179 0 : head = head->next;
2180 : }
2181 :
2182 0 : if (!any_open) {
2183 0 : dlt_vlog(LOG_ERR, "Failed create main socket for any configured binding\n");
2184 0 : return DLT_RETURN_ERROR;
2185 : }
2186 : }
2187 :
2188 : #ifdef UDP_CONNECTION_SUPPORT
2189 :
2190 : if (daemon_local->UDPConnectionSetup == MULTICAST_CONNECTION_ENABLED) {
2191 : if (dlt_daemon_udp_connection_setup(daemon_local) < 0) {
2192 : dlt_log(LOG_ERR, "UDP fd creation failed\n");
2193 : return DLT_RETURN_ERROR;
2194 : }
2195 : else {
2196 : dlt_log(LOG_INFO, "UDP fd creation success\n");
2197 : }
2198 : }
2199 :
2200 : #endif
2201 :
2202 : /* create and open unix socket to receive incoming connections from
2203 : * control application */
2204 9 : if (dlt_daemon_initialize_control_socket(daemon_local) < DLT_RETURN_OK) {
2205 0 : dlt_log(LOG_ERR, "Could not initialize control socket.\n");
2206 0 : return DLT_RETURN_ERROR;
2207 : }
2208 :
2209 : /* Init serial */
2210 9 : if (dlt_daemon_init_serial(daemon_local) < 0) {
2211 0 : dlt_log(LOG_ERR, "Could not initialize daemon data\n");
2212 0 : return DLT_RETURN_ERROR;
2213 : }
2214 :
2215 : return 0;
2216 : }
2217 :
2218 0 : static char* file_read_everything(FILE* const file, const size_t sizeLimit)
2219 : {
2220 0 : if (!file) {
2221 : return NULL;
2222 : }
2223 :
2224 : /* Get the file size. Bail out if stat fails. */
2225 0 : const int fd = fileno(file);
2226 0 : struct stat s_buf = {0};
2227 0 : if (fstat(fd, &s_buf) < 0) {
2228 0 : dlt_log(LOG_WARNING, "failed to stat file size\n");
2229 0 : fclose(file);
2230 0 : return NULL;
2231 : }
2232 :
2233 : /* Size limit includes NULL terminator. */
2234 0 : const off_t size = s_buf.st_size;
2235 0 : if (size < 0 || (size_t)size >= sizeLimit) {
2236 0 : dlt_log(LOG_WARNING, "file size invalid\n");
2237 0 : fclose(file);
2238 0 : return NULL;
2239 : }
2240 :
2241 0 : char* const string = malloc((size_t)size + 1);
2242 0 : if (!string) {
2243 0 : dlt_log(LOG_WARNING, "failed to allocate string for file contents\n");
2244 0 : fclose(file);
2245 0 : return NULL;
2246 : }
2247 :
2248 : off_t offset = 0;
2249 0 : while (!feof(file)) {
2250 0 : offset += (off_t)fread(string + offset, 1, (size_t)size, file);
2251 :
2252 0 : if (ferror(file)) {
2253 0 : dlt_log(LOG_WARNING, "failed to read file\n");
2254 0 : free(string);
2255 0 : fclose(file);
2256 0 : return NULL;
2257 : }
2258 :
2259 0 : if (offset > size) {
2260 0 : dlt_log(LOG_WARNING, "file too long for buffer\n");
2261 0 : free(string);
2262 0 : fclose(file);
2263 0 : return NULL;
2264 : }
2265 : }
2266 :
2267 0 : string[offset] = '\0'; /* append null termination at end of string */
2268 :
2269 0 : return string;
2270 : }
2271 :
2272 0 : static char* file_read_field(FILE* const file, const char* const fieldName)
2273 : {
2274 0 : if (!file) {
2275 : return NULL;
2276 : }
2277 :
2278 : const char* const kDelimiters = "\r\n\"\'=";
2279 0 : const size_t fieldNameLen = strlen(fieldName);
2280 :
2281 : char* result = NULL;
2282 :
2283 0 : char* buffer = NULL;
2284 0 : size_t bufferSize = 0;
2285 :
2286 : while (true) {
2287 : ssize_t lineSize = getline(&buffer, &bufferSize, file);
2288 0 : if (lineSize < 0 || !buffer) {
2289 : /* end of file */
2290 : break;
2291 : }
2292 :
2293 : char* line = buffer;
2294 :
2295 : /* trim trailing delimiters */
2296 0 : while (lineSize >= 1 && strchr(kDelimiters, line[lineSize - 1]) != NULL) {
2297 0 : line[lineSize - 1] = '\0';
2298 0 : --lineSize;
2299 : }
2300 :
2301 : /* check fieldName */
2302 0 : if (strncmp(line, fieldName, fieldNameLen) == 0 &&
2303 0 : (size_t)lineSize >= (fieldNameLen + 1) &&
2304 0 : strchr(kDelimiters, line[fieldNameLen]) != NULL) {
2305 : /* trim fieldName */
2306 : line += fieldNameLen;
2307 :
2308 : /* trim delimiter */
2309 0 : ++line;
2310 :
2311 : /* trim leading delimiters */
2312 0 : while (*line != '\0' && strchr(kDelimiters, *line) != NULL) {
2313 0 : ++line;
2314 : --lineSize;
2315 : }
2316 :
2317 0 : result = strdup(line);
2318 0 : break;
2319 : }
2320 : }
2321 :
2322 0 : free(buffer);
2323 :
2324 0 : return result;
2325 : }
2326 :
2327 9 : int dlt_daemon_local_ecu_version_init(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose)
2328 : {
2329 : FILE *f = NULL;
2330 :
2331 9 : PRINT_FUNCTION_VERBOSE(verbose);
2332 :
2333 : /* By default, version string is null. */
2334 9 : daemon->ECUVersionString = NULL;
2335 :
2336 : /* Open the file. Bail out if error occurs */
2337 9 : f = fopen(daemon_local->flags.pathToECUSoftwareVersion, "r");
2338 :
2339 9 : if (f == NULL) {
2340 : /* Error level notice, because this might be deliberate choice */
2341 9 : dlt_log(LOG_NOTICE, "Failed to open ECU Software version file.\n");
2342 9 : return -1;
2343 : }
2344 :
2345 0 : if (daemon_local->flags.ecuSoftwareVersionFileField[0] != '\0') {
2346 0 : daemon->ECUVersionString = file_read_field(f, daemon_local->flags.ecuSoftwareVersionFileField);
2347 : } else {
2348 0 : daemon->ECUVersionString = file_read_everything(f, DLT_DAEMON_TEXTBUFSIZE);
2349 : }
2350 :
2351 0 : fclose(f);
2352 :
2353 0 : return (daemon->ECUVersionString != NULL) ? 0 : -1;
2354 : }
2355 :
2356 9 : void dlt_daemon_local_cleanup(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose)
2357 : {
2358 9 : PRINT_FUNCTION_VERBOSE(verbose);
2359 :
2360 9 : if ((daemon == 0) || (daemon_local == 0)) {
2361 0 : dlt_log(LOG_ERR, "Invalid function parameters used for function dlt_daemon_local_cleanup()\n");
2362 0 : return;
2363 : }
2364 :
2365 : /* Don't receive event anymore */
2366 9 : dlt_event_handler_cleanup_connections(&daemon_local->pEvent);
2367 :
2368 9 : dlt_message_free(&(daemon_local->msg), daemon_local->flags.vflag);
2369 :
2370 : /* free shared memory */
2371 9 : if (daemon_local->flags.offlineTraceDirectory[0])
2372 0 : multiple_files_buffer_free(&(daemon_local->offlineTrace));
2373 :
2374 : /* Ignore result */
2375 9 : dlt_file_free(&(daemon_local->file), daemon_local->flags.vflag);
2376 :
2377 : #ifdef DLT_DAEMON_USE_FIFO_IPC
2378 : /* Try to delete existing pipe, ignore result of unlink() */
2379 9 : unlink(daemon_local->flags.daemonFifoName);
2380 : #else /* DLT_DAEMON_USE_UNIX_SOCKET_IPC */
2381 : /* Try to delete existing pipe, ignore result of unlink() */
2382 : if (unlink(daemon_local->flags.appSockPath) != 0) {
2383 : dlt_vlog(LOG_WARNING, "%s: unlink() failed: %s\n",
2384 : __func__, strerror(errno));
2385 : }
2386 : #endif
2387 :
2388 : #ifdef DLT_SHM_ENABLE
2389 : /* free shared memory */
2390 : dlt_shm_free_server(&(daemon_local->dlt_shm), daemon_local->flags.dltShmName);
2391 : free(daemon_local->recv_buf_shm);
2392 : daemon_local->recv_buf_shm = NULL;
2393 : #endif
2394 :
2395 9 : if (daemon_local->flags.offlineLogstorageMaxDevices > 0) {
2396 : /* disconnect all logstorage devices */
2397 6 : dlt_daemon_logstorage_cleanup(daemon,
2398 : daemon_local,
2399 : daemon_local->flags.vflag);
2400 :
2401 6 : free(daemon->storage_handle);
2402 : }
2403 :
2404 9 : if (daemon->ECUVersionString != NULL)
2405 9 : free(daemon->ECUVersionString);
2406 :
2407 9 : if (unlink(daemon_local->flags.ctrlSockPath) != 0) {
2408 1 : dlt_vlog(LOG_WARNING, "%s: unlink() failed: %s\n",
2409 1 : __func__, strerror(errno));
2410 : }
2411 :
2412 : /* free IP list */
2413 9 : free(daemon_local->flags.ipNodes);
2414 : }
2415 :
2416 9 : void dlt_daemon_exit_trigger()
2417 : {
2418 : /* stop event loop */
2419 9 : g_exit = -1;
2420 :
2421 : #ifdef DLT_DAEMON_USE_FIFO_IPC
2422 9 : char tmp[DLT_PATH_MAX] = { 0 };
2423 :
2424 : ssize_t n;
2425 9 : n = snprintf(tmp, DLT_PATH_MAX, "%s/dlt", dltFifoBaseDir);
2426 9 : if (n < 0 || (size_t)n > DLT_PATH_MAX) {
2427 0 : dlt_vlog(LOG_WARNING, "%s: snprintf truncation/error(%ld) %s\n",
2428 : __func__, n, tmp);
2429 : }
2430 :
2431 9 : (void)unlink(tmp);
2432 : #endif
2433 :
2434 : #ifdef __QNX__
2435 : dlt_daemon_cleanup_timers();
2436 : #endif
2437 :
2438 9 : }
2439 :
2440 9 : void dlt_daemon_signal_handler(int sig)
2441 : {
2442 9 : g_signo = sig;
2443 :
2444 9 : switch (sig) {
2445 9 : case SIGHUP:
2446 : case SIGTERM:
2447 : case SIGINT:
2448 : case SIGQUIT:
2449 : {
2450 : /* finalize the server */
2451 9 : dlt_vlog(LOG_NOTICE, "Exiting DLT daemon due to signal: %s\n",
2452 : strsignal(sig));
2453 9 : dlt_daemon_exit_trigger();
2454 9 : break;
2455 : }
2456 : default:
2457 : {
2458 : /* This case should never happen! */
2459 : break;
2460 : }
2461 : } /* switch */
2462 :
2463 9 : } /* dlt_daemon_signal_handler() */
2464 :
2465 : #ifdef __QNX__
2466 : void dlt_daemon_cleanup_timers()
2467 : {
2468 : int i = 0;
2469 : while (i < DLT_TIMER_UNKNOWN) {
2470 : /* Remove FIFO of every timer and kill timer thread */
2471 : if (0 != timer_threads[i]) {
2472 : pthread_kill(timer_threads[i], SIGUSR1);
2473 : pthread_join(timer_threads[i], NULL);
2474 : timer_threads[i] = 0;
2475 :
2476 : close_pipes(dlt_timer_pipes[i]);
2477 :
2478 : /* Free data of every timer */
2479 : if (NULL != timer_data[i]) {
2480 : free(timer_data[i]);
2481 : timer_data[i] = NULL;
2482 : }
2483 : }
2484 : i++;
2485 : }
2486 : }
2487 : #endif
2488 :
2489 2 : void dlt_daemon_daemonize(int verbose)
2490 : {
2491 : int i;
2492 : int fd;
2493 :
2494 2 : PRINT_FUNCTION_VERBOSE(verbose);
2495 :
2496 2 : dlt_log(LOG_NOTICE, "Daemon mode\n");
2497 :
2498 : /* Daemonize */
2499 2 : i = fork();
2500 :
2501 4 : if (i < 0) {
2502 0 : dlt_log(LOG_CRIT, "Unable to fork(), exiting DLT daemon\n");
2503 0 : exit(-1); /* fork error */
2504 : }
2505 :
2506 4 : if (i > 0)
2507 2 : exit(0); /* parent exits */
2508 :
2509 : /* child (daemon) continues */
2510 :
2511 : /* Process independency */
2512 :
2513 : /* obtain a new process group */
2514 2 : if (setsid() == -1) {
2515 0 : dlt_log(LOG_CRIT, "setsid() failed, exiting DLT daemon\n");
2516 0 : exit(-1); /* fork error */
2517 : }
2518 :
2519 : /* Open standard descriptors stdin, stdout, stderr */
2520 : fd = open("/dev/null", O_RDWR);
2521 :
2522 2 : if (fd != -1) {
2523 : /* Redirect STDOUT to /dev/null */
2524 2 : if (dup2(fd, STDOUT_FILENO) < 0)
2525 0 : dlt_vlog(LOG_WARNING, "Failed to direct stdout to /dev/null. Error: %s\n", strerror(errno));
2526 :
2527 : /* Redirect STDERR to /dev/null */
2528 2 : if (dup2(fd, STDERR_FILENO) < 0)
2529 0 : dlt_vlog(LOG_WARNING, "Failed to direct stderr to /dev/null. Error: %s\n", strerror(errno));
2530 :
2531 2 : close(fd);
2532 : }
2533 : else {
2534 0 : dlt_log(LOG_CRIT, "Error opening /dev/null, exiting DLT daemon\n");
2535 0 : exit(-1); /* fork error */
2536 : }
2537 :
2538 : /* Set umask */
2539 2 : umask(DLT_DAEMON_UMASK);
2540 :
2541 : /* Change to root directory */
2542 2 : if (chdir("/") < 0)
2543 0 : dlt_log(LOG_WARNING, "Failed to chdir to root\n");
2544 :
2545 : /* Catch signals */
2546 2 : signal(SIGCHLD, SIG_IGN); /* ignore child */
2547 2 : signal(SIGTSTP, SIG_IGN); /* ignore tty signals */
2548 2 : signal(SIGTTOU, SIG_IGN);
2549 2 : signal(SIGTTIN, SIG_IGN);
2550 :
2551 2 : } /* dlt_daemon_daemonize() */
2552 :
2553 : /* This function logs str to the configured output sink (socket, serial, offline trace).
2554 : * To avoid recursion this function must be called only from DLT highlevel functions.
2555 : * E. g. calling it to output a failure when the open of the offline trace file fails
2556 : * would cause an endless loop because dlt_daemon_log_internal() would itself again try
2557 : * to open the offline trace file.
2558 : * This is a dlt-daemon only function. The libdlt has no equivalent function available. */
2559 40 : int dlt_daemon_log_internal(DltDaemon *daemon, DltDaemonLocal *daemon_local,
2560 : char *str, DltLogLevelType level,
2561 : const char *app_id, const char *ctx_id, int verbose)
2562 : {
2563 40 : DltMessage msg = { 0 };
2564 : static uint8_t uiMsgCount = 0;
2565 : DltStandardHeaderExtra *pStandardExtra = NULL;
2566 : uint32_t uiType;
2567 : uint16_t uiSize;
2568 : uint32_t uiExtraSize;
2569 :
2570 40 : PRINT_FUNCTION_VERBOSE(verbose);
2571 :
2572 : /* Set storageheader */
2573 40 : msg.storageheader = (DltStorageHeader *)(msg.headerbuffer);
2574 40 : dlt_set_storageheader(msg.storageheader, daemon->ecuid);
2575 :
2576 : /* Set standardheader */
2577 40 : msg.standardheader = (DltStandardHeader *)(msg.headerbuffer + sizeof(DltStorageHeader));
2578 40 : msg.standardheader->htyp = DLT_HTYP_UEH | DLT_HTYP_WEID | DLT_HTYP_WSID | DLT_HTYP_WTMS |
2579 : DLT_HTYP_PROTOCOL_VERSION1;
2580 40 : msg.standardheader->mcnt = uiMsgCount++;
2581 :
2582 : uiExtraSize = (uint32_t) (DLT_STANDARD_HEADER_EXTRA_SIZE(msg.standardheader->htyp) +
2583 : (DLT_IS_HTYP_UEH(msg.standardheader->htyp) ? sizeof(DltExtendedHeader) : 0));
2584 40 : msg.headersize = (uint32_t) sizeof(DltStorageHeader) + (uint32_t) sizeof(DltStandardHeader) + uiExtraSize;
2585 :
2586 : /* Set extraheader */
2587 : pStandardExtra =
2588 : (DltStandardHeaderExtra *)(msg.headerbuffer + sizeof(DltStorageHeader) + sizeof(DltStandardHeader));
2589 40 : dlt_set_id(pStandardExtra->ecu, daemon->ecuid);
2590 40 : pStandardExtra->tmsp = DLT_HTOBE_32(dlt_uptime());
2591 40 : pStandardExtra->seid = (unsigned int) DLT_HTOBE_32(getpid());
2592 :
2593 : /* Set extendedheader */
2594 40 : msg.extendedheader =
2595 40 : (DltExtendedHeader *)(msg.headerbuffer + sizeof(DltStorageHeader) + sizeof(DltStandardHeader) +
2596 40 : DLT_STANDARD_HEADER_EXTRA_SIZE(msg.standardheader->htyp));
2597 40 : msg.extendedheader->msin = DLT_MSIN_VERB | (DLT_TYPE_LOG << DLT_MSIN_MSTP_SHIFT) |
2598 : ((level << DLT_MSIN_MTIN_SHIFT) & DLT_MSIN_MTIN);
2599 40 : msg.extendedheader->noar = 1;
2600 40 : dlt_set_id(msg.extendedheader->apid, app_id);
2601 40 : dlt_set_id(msg.extendedheader->ctid, ctx_id);
2602 :
2603 : /* Set payload data... */
2604 40 : uiType = DLT_TYPE_INFO_STRG;
2605 40 : uiSize = (uint16_t) (strlen(str) + 1);
2606 40 : msg.datasize = (uint32_t) (sizeof(uint32_t) + sizeof(uint16_t) + uiSize);
2607 :
2608 40 : msg.databuffer = (uint8_t *)malloc((size_t) msg.datasize);
2609 40 : msg.databuffersize = msg.datasize;
2610 :
2611 40 : if (msg.databuffer == 0) {
2612 0 : dlt_log(LOG_WARNING, "Can't allocate buffer for get log info message\n");
2613 0 : return -1;
2614 : }
2615 :
2616 40 : msg.datasize = 0;
2617 : memcpy((uint8_t *)(msg.databuffer + msg.datasize), (uint8_t *)(&uiType), sizeof(uint32_t));
2618 40 : msg.datasize += (uint32_t) sizeof(uint32_t);
2619 40 : memcpy((uint8_t *)(msg.databuffer + msg.datasize), (uint8_t *)(&uiSize), sizeof(uint16_t));
2620 40 : msg.datasize += (uint32_t) sizeof(uint16_t);
2621 40 : memcpy((uint8_t *)(msg.databuffer + msg.datasize), str, uiSize);
2622 40 : msg.datasize += uiSize;
2623 :
2624 : /* Calc length */
2625 40 : msg.standardheader->len = DLT_HTOBE_16(msg.headersize - sizeof(DltStorageHeader) + msg.datasize);
2626 :
2627 40 : dlt_daemon_client_send(DLT_DAEMON_SEND_TO_ALL, daemon,daemon_local,
2628 : msg.headerbuffer, sizeof(DltStorageHeader),
2629 : msg.headerbuffer + sizeof(DltStorageHeader),
2630 40 : (int) (msg.headersize - sizeof(DltStorageHeader)),
2631 40 : msg.databuffer, (int) msg.datasize, verbose);
2632 :
2633 40 : free(msg.databuffer);
2634 :
2635 40 : return 0;
2636 : }
2637 :
2638 3 : int dlt_daemon_check_numeric_setting(char *token,
2639 : char *value,
2640 : unsigned long *data)
2641 3 : {
2642 3 : char value_check[value_length];
2643 3 : value_check[0] = 0;
2644 3 : sscanf(value, "%lu%s", data, value_check);
2645 3 : if (value_check[0] || !isdigit(value[0])) {
2646 0 : fprintf(stderr, "Invalid input [%s] detected in option %s\n",
2647 : value,
2648 : token);
2649 0 : return -1;
2650 : }
2651 : return 0;
2652 : }
2653 :
2654 4 : int dlt_daemon_process_client_connect(DltDaemon *daemon,
2655 : DltDaemonLocal *daemon_local,
2656 : DltReceiver *receiver,
2657 : int verbose)
2658 : {
2659 : socklen_t cli_size;
2660 : struct sockaddr_un cli;
2661 :
2662 : int in_sock = -1;
2663 4 : char local_str[DLT_DAEMON_TEXTBUFSIZE] = { '\0' };
2664 :
2665 4 : PRINT_FUNCTION_VERBOSE(verbose);
2666 :
2667 4 : if ((daemon == NULL) || (daemon_local == NULL) || (receiver == NULL)) {
2668 0 : dlt_log(LOG_ERR,
2669 : "Invalid function parameters used for function "
2670 : "dlt_daemon_process_client_connect()\n");
2671 0 : return -1;
2672 : }
2673 :
2674 : /* event from TCP server socket, new connection */
2675 4 : cli_size = sizeof(cli);
2676 :
2677 4 : if ((in_sock = accept(receiver->fd, (struct sockaddr *)&cli, &cli_size)) < 0) {
2678 0 : if (errno == ECONNABORTED) // Caused by nmap -v -p 3490 -Pn <IP of dlt-daemon>
2679 : return 0;
2680 0 : dlt_vlog(LOG_ERR, "accept() for socket %d failed: %s\n", receiver->fd, strerror(errno));
2681 0 : return -1;
2682 : }
2683 :
2684 : /* check if file file descriptor was already used, and make it invalid if it
2685 : * is reused. */
2686 : /* This prevents sending messages to wrong file descriptor */
2687 4 : dlt_daemon_applications_invalidate_fd(daemon, daemon->ecuid, in_sock, verbose);
2688 4 : dlt_daemon_contexts_invalidate_fd(daemon, daemon->ecuid, in_sock, verbose);
2689 :
2690 : /* Set socket timeout in reception */
2691 : struct timeval timeout_send;
2692 4 : timeout_send.tv_sec = daemon_local->timeoutOnSend;
2693 4 : timeout_send.tv_usec = 0;
2694 :
2695 4 : if (setsockopt (in_sock,
2696 : SOL_SOCKET,
2697 : SO_SNDTIMEO,
2698 : (char *)&timeout_send,
2699 : sizeof(timeout_send)) < 0)
2700 0 : dlt_log(LOG_WARNING, "setsockopt failed\n");
2701 :
2702 4 : if (dlt_connection_create(daemon_local,
2703 : &daemon_local->pEvent,
2704 : in_sock,
2705 : POLLIN,
2706 : DLT_CONNECTION_CLIENT_MSG_TCP)) {
2707 0 : dlt_log(LOG_ERR, "Failed to register new client. \n");
2708 0 : close(in_sock);
2709 0 : return -1;
2710 : }
2711 :
2712 : /* send connection info about connected */
2713 4 : dlt_daemon_control_message_connection_info(in_sock,
2714 : daemon,
2715 : daemon_local,
2716 : DLT_CONNECTION_STATUS_CONNECTED,
2717 : "",
2718 : verbose);
2719 :
2720 : /* send ecu version string */
2721 4 : if (daemon_local->flags.sendECUSoftwareVersion > 0) {
2722 : if (daemon_local->flags.sendECUSoftwareVersion > 0)
2723 0 : dlt_daemon_control_get_software_version(DLT_DAEMON_SEND_TO_ALL,
2724 : daemon,
2725 : daemon_local,
2726 : daemon_local->flags.vflag);
2727 :
2728 0 : if (daemon_local->flags.sendTimezone > 0)
2729 0 : dlt_daemon_control_message_timezone(DLT_DAEMON_SEND_TO_ALL,
2730 : daemon,
2731 : daemon_local,
2732 : daemon_local->flags.vflag);
2733 : }
2734 :
2735 4 : snprintf(local_str, DLT_DAEMON_TEXTBUFSIZE,
2736 : "New client connection #%d established, Total Clients : %d",
2737 : in_sock, daemon_local->client_connections);
2738 :
2739 4 : dlt_daemon_log_internal(daemon, daemon_local, local_str, DLT_LOG_INFO,
2740 : DLT_DAEMON_APP_ID, DLT_DAEMON_CTX_ID,
2741 : daemon_local->flags.vflag);
2742 4 : dlt_vlog(LOG_DEBUG, "%s%s", local_str, "\n");
2743 :
2744 4 : if (daemon_local->client_connections == 1) {
2745 2 : if (daemon_local->flags.vflag)
2746 0 : dlt_log(LOG_DEBUG, "Send ring-buffer to client\n");
2747 :
2748 2 : dlt_daemon_change_state(daemon, DLT_DAEMON_STATE_SEND_BUFFER);
2749 :
2750 2 : if (dlt_daemon_send_ringbuffer_to_client(daemon, daemon_local, verbose) == -1) {
2751 0 : dlt_log(LOG_WARNING, "Can't send contents of ringbuffer to clients\n");
2752 0 : close(in_sock);
2753 : in_sock = -1;
2754 0 : return -1;
2755 : }
2756 :
2757 : /* send new log state to all applications */
2758 2 : daemon->connectionState = 1;
2759 2 : dlt_daemon_user_send_all_log_state(daemon, verbose);
2760 :
2761 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
2762 : /* Reset number of received bytes from FIFO */
2763 : daemon->bytes_recv = 0;
2764 : #endif
2765 : }
2766 :
2767 : return 0;
2768 : }
2769 :
2770 6 : int dlt_daemon_process_client_messages(DltDaemon *daemon,
2771 : DltDaemonLocal *daemon_local,
2772 : DltReceiver *receiver,
2773 : int verbose)
2774 : {
2775 : int bytes_to_be_removed = 0;
2776 : int must_close_socket = -1;
2777 :
2778 6 : PRINT_FUNCTION_VERBOSE(verbose);
2779 :
2780 6 : if ((daemon == NULL) || (daemon_local == NULL) || (receiver == NULL)) {
2781 0 : dlt_log(LOG_ERR,
2782 : "Invalid function parameters used for function "
2783 : "dlt_daemon_process_client_messages()\n");
2784 0 : return -1;
2785 : }
2786 :
2787 6 : must_close_socket = dlt_receiver_receive(receiver);
2788 :
2789 6 : if (must_close_socket < 0) {
2790 0 : dlt_daemon_close_socket(receiver->fd,
2791 : daemon,
2792 : daemon_local,
2793 : verbose);
2794 0 : return -1;
2795 : }
2796 :
2797 : /* Process all received messages */
2798 16 : while (dlt_message_read(&(daemon_local->msg),
2799 16 : (uint8_t *)receiver->buf,
2800 16 : (unsigned int) receiver->bytesRcvd,
2801 : daemon_local->flags.nflag,
2802 16 : daemon_local->flags.vflag) == DLT_MESSAGE_ERROR_OK) {
2803 : /* Check for control message */
2804 10 : if ((0 < receiver->fd) &&
2805 10 : DLT_MSG_IS_CONTROL_REQUEST(&(daemon_local->msg)))
2806 10 : dlt_daemon_client_process_control(receiver->fd,
2807 : daemon,
2808 : daemon_local,
2809 : &(daemon_local->msg),
2810 : daemon_local->flags.vflag);
2811 :
2812 10 : bytes_to_be_removed = (int) (daemon_local->msg.headersize +
2813 10 : daemon_local->msg.datasize -
2814 : sizeof(DltStorageHeader));
2815 :
2816 10 : if (daemon_local->msg.found_serialheader)
2817 : bytes_to_be_removed += (int) sizeof(dltSerialHeader);
2818 :
2819 10 : if (daemon_local->msg.resync_offset)
2820 0 : bytes_to_be_removed += daemon_local->msg.resync_offset;
2821 :
2822 10 : if (dlt_receiver_remove(receiver, bytes_to_be_removed) == -1) {
2823 0 : dlt_log(LOG_WARNING,
2824 : "Can't remove bytes from receiver for sockets\n");
2825 0 : return -1;
2826 : }
2827 : } /* while */
2828 :
2829 6 : if (dlt_receiver_move_to_begin(receiver) == -1) {
2830 0 : dlt_log(LOG_WARNING,
2831 : "Can't move bytes to beginning of receiver buffer for sockets\n");
2832 0 : return -1;
2833 : }
2834 :
2835 6 : if (must_close_socket == 0)
2836 : /* FIXME: Why the hell do we need to close the socket
2837 : * on control message reception ??
2838 : */
2839 1 : dlt_daemon_close_socket(receiver->fd,
2840 : daemon,
2841 : daemon_local,
2842 : verbose);
2843 :
2844 : return 0;
2845 : }
2846 :
2847 0 : int dlt_daemon_process_client_messages_serial(DltDaemon *daemon,
2848 : DltDaemonLocal *daemon_local,
2849 : DltReceiver *receiver,
2850 : int verbose)
2851 : {
2852 : int bytes_to_be_removed = 0;
2853 :
2854 0 : PRINT_FUNCTION_VERBOSE(verbose);
2855 :
2856 0 : if ((daemon == NULL) || (daemon_local == NULL) || (receiver == NULL)) {
2857 0 : dlt_log(LOG_ERR,
2858 : "Invalid function parameters used for function "
2859 : "dlt_daemon_process_client_messages_serial()\n");
2860 0 : return -1;
2861 : }
2862 :
2863 0 : if (dlt_receiver_receive(receiver) <= 0) {
2864 0 : dlt_log(LOG_WARNING,
2865 : "dlt_receiver_receive_fd() for messages from serial interface "
2866 : "failed!\n");
2867 0 : return -1;
2868 : }
2869 :
2870 : /* Process all received messages */
2871 0 : while (dlt_message_read(&(daemon_local->msg),
2872 0 : (uint8_t *)receiver->buf,
2873 0 : (unsigned int) receiver->bytesRcvd,
2874 : daemon_local->flags.mflag,
2875 0 : daemon_local->flags.vflag) == DLT_MESSAGE_ERROR_OK) {
2876 : /* Check for control message */
2877 0 : if (DLT_MSG_IS_CONTROL_REQUEST(&(daemon_local->msg))) {
2878 0 : if (dlt_daemon_client_process_control(receiver->fd,
2879 : daemon,
2880 : daemon_local,
2881 : &(daemon_local->msg),
2882 : daemon_local->flags.vflag)
2883 : == -1) {
2884 0 : dlt_log(LOG_WARNING, "Can't process control messages\n");
2885 0 : return -1;
2886 : }
2887 : }
2888 :
2889 0 : bytes_to_be_removed = (int) (daemon_local->msg.headersize +
2890 0 : daemon_local->msg.datasize -
2891 : sizeof(DltStorageHeader));
2892 :
2893 0 : if (daemon_local->msg.found_serialheader)
2894 : bytes_to_be_removed += (int) sizeof(dltSerialHeader);
2895 :
2896 0 : if (daemon_local->msg.resync_offset)
2897 0 : bytes_to_be_removed += daemon_local->msg.resync_offset;
2898 :
2899 0 : if (dlt_receiver_remove(receiver, bytes_to_be_removed) == -1) {
2900 0 : dlt_log(LOG_WARNING,
2901 : "Can't remove bytes from receiver for serial connection\n");
2902 0 : return -1;
2903 : }
2904 : } /* while */
2905 :
2906 0 : if (dlt_receiver_move_to_begin(receiver) == -1) {
2907 0 : dlt_log(LOG_WARNING,
2908 : "Can't move bytes to beginning of receiver buffer for serial "
2909 : "connection\n");
2910 0 : return -1;
2911 : }
2912 :
2913 : return 0;
2914 : }
2915 :
2916 2 : int dlt_daemon_process_control_connect(
2917 : DltDaemon *daemon,
2918 : DltDaemonLocal *daemon_local,
2919 : DltReceiver *receiver,
2920 : int verbose)
2921 : {
2922 : socklen_t ctrl_size;
2923 : struct sockaddr_un ctrl;
2924 : int in_sock = -1;
2925 :
2926 2 : PRINT_FUNCTION_VERBOSE(verbose);
2927 :
2928 2 : if ((daemon == NULL) || (daemon_local == NULL) || (receiver == NULL)) {
2929 0 : dlt_log(LOG_ERR,
2930 : "Invalid function parameters used for function "
2931 : "dlt_daemon_process_control_connect()\n");
2932 0 : return -1;
2933 : }
2934 :
2935 : /* event from UNIX server socket, new connection */
2936 2 : ctrl_size = sizeof(ctrl);
2937 :
2938 2 : if ((in_sock = accept(receiver->fd, (struct sockaddr *)&ctrl, &ctrl_size)) < 0) {
2939 0 : dlt_vlog(LOG_ERR, "accept() on UNIX control socket %d failed: %s\n", receiver->fd, strerror(errno));
2940 0 : return -1;
2941 : }
2942 :
2943 : /* check if file file descriptor was already used, and make it invalid if it
2944 : * is reused */
2945 : /* This prevents sending messages to wrong file descriptor */
2946 2 : dlt_daemon_applications_invalidate_fd(daemon, daemon->ecuid, in_sock, verbose);
2947 2 : dlt_daemon_contexts_invalidate_fd(daemon, daemon->ecuid, in_sock, verbose);
2948 :
2949 2 : if (dlt_connection_create(daemon_local,
2950 : &daemon_local->pEvent,
2951 : in_sock,
2952 : POLLIN,
2953 : DLT_CONNECTION_CONTROL_MSG)) {
2954 0 : dlt_log(LOG_ERR, "Failed to register new client. \n");
2955 : /* TODO: Perform clean-up */
2956 0 : return -1;
2957 : }
2958 :
2959 2 : if (verbose)
2960 0 : dlt_vlog(LOG_INFO, "New connection to control client established\n");
2961 :
2962 : return 0;
2963 : }
2964 :
2965 : #if defined DLT_DAEMON_USE_UNIX_SOCKET_IPC || defined DLT_DAEMON_VSOCK_IPC_ENABLE
2966 : int dlt_daemon_process_app_connect(
2967 : DltDaemon *daemon,
2968 : DltDaemonLocal *daemon_local,
2969 : DltReceiver *receiver,
2970 : int verbose)
2971 : {
2972 : int in_sock = -1;
2973 :
2974 : PRINT_FUNCTION_VERBOSE(verbose);
2975 :
2976 : if ((daemon == NULL) || (daemon_local == NULL) || (receiver == NULL)) {
2977 : dlt_vlog(LOG_ERR,
2978 : "%s: Invalid parameters\n",
2979 : __func__);
2980 : return DLT_RETURN_WRONG_PARAMETER;
2981 : }
2982 :
2983 : /* event from server socket, new connection */
2984 :
2985 : if ((in_sock = accept(receiver->fd, NULL, NULL)) < 0) {
2986 : dlt_vlog(LOG_ERR, "accept() on UNIX socket %d failed: %s\n", receiver->fd, strerror(errno));
2987 : return -1;
2988 : }
2989 :
2990 : /* check if file file descriptor was already used, and make it invalid if it
2991 : * is reused. This prevents sending messages to wrong file descriptor */
2992 : dlt_daemon_applications_invalidate_fd(daemon, daemon->ecuid, in_sock, verbose);
2993 : dlt_daemon_contexts_invalidate_fd(daemon, daemon->ecuid, in_sock, verbose);
2994 :
2995 : if (dlt_connection_create(daemon_local,
2996 : &daemon_local->pEvent,
2997 : in_sock,
2998 : POLLIN,
2999 : DLT_CONNECTION_APP_MSG)) {
3000 : dlt_log(LOG_ERR, "Failed to register new application. \n");
3001 : close(in_sock);
3002 : return -1;
3003 : }
3004 :
3005 : if (verbose)
3006 : dlt_vlog(LOG_INFO, "New connection to application established\n");
3007 :
3008 : return 0;
3009 : }
3010 : #endif
3011 :
3012 4 : int dlt_daemon_process_control_messages(
3013 : DltDaemon *daemon,
3014 : DltDaemonLocal *daemon_local,
3015 : DltReceiver *receiver,
3016 : int verbose)
3017 : {
3018 : int bytes_to_be_removed = 0;
3019 :
3020 4 : PRINT_FUNCTION_VERBOSE(verbose);
3021 :
3022 4 : if ((daemon == NULL) || (daemon_local == NULL) || (receiver == NULL)) {
3023 0 : dlt_log(LOG_ERR,
3024 : "Invalid function parameters used for function "
3025 : "dlt_daemon_process_control_messages()\n");
3026 0 : return -1;
3027 : }
3028 :
3029 4 : if (dlt_receiver_receive(receiver) <= 0) {
3030 2 : dlt_daemon_close_socket(receiver->fd,
3031 : daemon,
3032 : daemon_local,
3033 : verbose);
3034 : /* FIXME: Why the hell do we need to close the socket
3035 : * on control message reception ??
3036 : */
3037 2 : return 0;
3038 : }
3039 :
3040 : /* Process all received messages */
3041 4 : while (dlt_message_read(
3042 : &(daemon_local->msg),
3043 4 : (uint8_t *)receiver->buf,
3044 4 : (unsigned int) receiver->bytesRcvd,
3045 : daemon_local->flags.nflag,
3046 4 : daemon_local->flags.vflag) == DLT_MESSAGE_ERROR_OK) {
3047 : /* Check for control message */
3048 2 : if ((receiver->fd > 0) &&
3049 2 : DLT_MSG_IS_CONTROL_REQUEST(&(daemon_local->msg)))
3050 2 : dlt_daemon_client_process_control(receiver->fd,
3051 : daemon, daemon_local,
3052 : &(daemon_local->msg),
3053 : daemon_local->flags.vflag);
3054 :
3055 2 : bytes_to_be_removed = (int) (daemon_local->msg.headersize +
3056 2 : daemon_local->msg.datasize -
3057 : sizeof(DltStorageHeader));
3058 :
3059 2 : if (daemon_local->msg.found_serialheader)
3060 : bytes_to_be_removed += (int) sizeof(dltSerialHeader);
3061 :
3062 2 : if (daemon_local->msg.resync_offset)
3063 0 : bytes_to_be_removed += daemon_local->msg.resync_offset;
3064 :
3065 2 : if (dlt_receiver_remove(receiver, bytes_to_be_removed) == -1) {
3066 0 : dlt_log(LOG_WARNING,
3067 : "Can't remove bytes from receiver for sockets\n");
3068 0 : return -1;
3069 : }
3070 : } /* while */
3071 :
3072 2 : if (dlt_receiver_move_to_begin(receiver) == -1) {
3073 0 : dlt_log(LOG_WARNING, "Can't move bytes to beginning of receiver buffer for sockets\n");
3074 0 : return -1;
3075 : }
3076 :
3077 : return 0;
3078 : }
3079 :
3080 0 : static int dlt_daemon_process_user_message_not_sup(DltDaemon *daemon,
3081 : DltDaemonLocal *daemon_local,
3082 : DltReceiver *receiver,
3083 : int verbose)
3084 : {
3085 0 : DltUserHeader *userheader = (DltUserHeader *)(receiver->buf);
3086 : (void)daemon;
3087 : (void)daemon_local;
3088 :
3089 0 : PRINT_FUNCTION_VERBOSE(verbose);
3090 :
3091 0 : dlt_vlog(LOG_ERR, "Invalid user message type received: %u!\n",
3092 : userheader->message);
3093 :
3094 : /* remove user header */
3095 0 : if (dlt_receiver_remove(receiver, sizeof(DltUserHeader)) == -1)
3096 0 : dlt_log(LOG_WARNING,
3097 : "Can't remove bytes from receiver for user messages\n");
3098 :
3099 0 : return -1;
3100 : }
3101 :
3102 : static dlt_daemon_process_user_message_func process_user_func[DLT_USER_MESSAGE_NOT_SUPPORTED] = {
3103 : dlt_daemon_process_user_message_not_sup,
3104 : dlt_daemon_process_user_message_log,
3105 : dlt_daemon_process_user_message_register_application,
3106 : dlt_daemon_process_user_message_unregister_application,
3107 : dlt_daemon_process_user_message_register_context,
3108 : dlt_daemon_process_user_message_unregister_context,
3109 : dlt_daemon_process_user_message_not_sup,
3110 : dlt_daemon_process_user_message_not_sup,
3111 : dlt_daemon_process_user_message_overflow,
3112 : dlt_daemon_process_user_message_set_app_ll_ts,
3113 : dlt_daemon_process_user_message_not_sup,
3114 : dlt_daemon_process_user_message_not_sup,
3115 : dlt_daemon_process_user_message_not_sup,
3116 : dlt_daemon_process_user_message_marker,
3117 : dlt_daemon_process_user_message_not_sup,
3118 : dlt_daemon_process_user_message_not_sup
3119 : };
3120 :
3121 1367 : int dlt_daemon_process_user_messages(DltDaemon *daemon,
3122 : DltDaemonLocal *daemon_local,
3123 : DltReceiver *receiver,
3124 : int verbose)
3125 : {
3126 : int offset = 0;
3127 : int run_loop = 1;
3128 : int32_t min_size = (int32_t) sizeof(DltUserHeader);
3129 : DltUserHeader *userheader;
3130 : int recv;
3131 :
3132 1367 : PRINT_FUNCTION_VERBOSE(verbose);
3133 :
3134 1367 : if ((daemon == NULL) || (daemon_local == NULL) || (receiver == NULL)) {
3135 0 : dlt_log(LOG_ERR,
3136 : "Invalid function parameters used for function "
3137 : "dlt_daemon_process_user_messages()\n");
3138 0 : return -1;
3139 : }
3140 :
3141 1367 : recv = dlt_receiver_receive(receiver);
3142 :
3143 1367 : if (recv <= 0 && receiver->type == DLT_RECEIVE_SOCKET) {
3144 0 : dlt_daemon_close_socket(receiver->fd,
3145 : daemon,
3146 : daemon_local,
3147 : verbose);
3148 0 : return 0;
3149 : }
3150 1367 : else if (recv < 0) {
3151 0 : dlt_log(LOG_WARNING,
3152 : "dlt_receiver_receive_fd() for user messages failed!\n");
3153 0 : return -1;
3154 : }
3155 :
3156 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
3157 : /* Count up number of received bytes from FIFO */
3158 : if (receiver->bytesRcvd > receiver->lastBytesRcvd)
3159 : {
3160 : daemon->bytes_recv += receiver->bytesRcvd - receiver->lastBytesRcvd;
3161 : }
3162 : #endif
3163 :
3164 : /* look through buffer as long as data is in there */
3165 7266 : while ((receiver->bytesRcvd >= min_size) && run_loop) {
3166 : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
3167 : /* this loop may be running long, so we have to exit it at some point to be able to
3168 : * to process other events, like feeding the watchdog
3169 : */
3170 : bool watchdog_triggered= dlt_daemon_trigger_systemd_watchdog_if_necessary(daemon);
3171 : if (watchdog_triggered) {
3172 : dlt_vlog(LOG_WARNING, "%s yields due to watchdog.\n", __func__);
3173 : run_loop = 0; // exit loop in next iteration
3174 : }
3175 : #endif
3176 :
3177 : dlt_daemon_process_user_message_func func = NULL;
3178 :
3179 : offset = 0;
3180 5899 : userheader = (DltUserHeader *)(receiver->buf + offset);
3181 :
3182 5899 : while (!dlt_user_check_userheader(userheader) &&
3183 0 : (offset + min_size <= receiver->bytesRcvd)) {
3184 : /* resync if necessary */
3185 0 : offset++;
3186 0 : userheader = (DltUserHeader *)(receiver->buf + offset);
3187 : }
3188 :
3189 : /* Check for user header pattern */
3190 5899 : if (!dlt_user_check_userheader(userheader))
3191 : break;
3192 :
3193 : /* Set new start offset */
3194 5899 : if (offset > 0) {
3195 0 : if (dlt_receiver_remove(receiver, offset) == -1) {
3196 0 : dlt_log(LOG_WARNING,
3197 : "Can't remove offset from receiver\n");
3198 0 : return -1;
3199 : }
3200 : }
3201 :
3202 5899 : if (userheader->message >= DLT_USER_MESSAGE_NOT_SUPPORTED)
3203 : func = dlt_daemon_process_user_message_not_sup;
3204 : else
3205 5899 : func = process_user_func[userheader->message];
3206 :
3207 5899 : if (func(daemon,
3208 : daemon_local,
3209 : receiver,
3210 : daemon_local->flags.vflag) == -1)
3211 : run_loop = 0;
3212 : }
3213 :
3214 : /* keep not read data in buffer */
3215 1367 : if (dlt_receiver_move_to_begin(receiver) == -1) {
3216 0 : dlt_log(LOG_WARNING,
3217 : "Can't move bytes to beginning of receiver buffer for user "
3218 : "messages\n");
3219 0 : return -1;
3220 : }
3221 :
3222 : return 0;
3223 : }
3224 :
3225 0 : int dlt_daemon_process_user_message_overflow(DltDaemon *daemon,
3226 : DltDaemonLocal *daemon_local,
3227 : DltReceiver *rec,
3228 : int verbose)
3229 : {
3230 : uint32_t len = sizeof(DltUserControlMsgBufferOverflow);
3231 : DltUserControlMsgBufferOverflow userpayload;
3232 :
3233 0 : PRINT_FUNCTION_VERBOSE(verbose);
3234 :
3235 0 : if ((daemon == NULL) || (daemon_local == NULL) || (rec == NULL)) {
3236 0 : dlt_vlog(LOG_ERR, "Invalid function parameters used for %s\n",
3237 : __func__);
3238 0 : return -1;
3239 : }
3240 :
3241 0 : if (dlt_receiver_check_and_get(rec,
3242 : &userpayload,
3243 : len,
3244 : DLT_RCV_SKIP_HEADER | DLT_RCV_REMOVE) < 0)
3245 : /* Not enough bytes received */
3246 : return -1;
3247 :
3248 : /* Store in daemon, that a message buffer overflow has occured */
3249 : /* look if TCP connection to client is available or it least message can be put into buffer */
3250 0 : if (dlt_daemon_control_message_buffer_overflow(DLT_DAEMON_SEND_TO_ALL,
3251 : daemon,
3252 : daemon_local,
3253 : userpayload.overflow_counter,
3254 : userpayload.apid,
3255 : verbose))
3256 : /* there was an error when storing message */
3257 : /* add the counter of lost messages to the daemon counter */
3258 0 : daemon->overflow_counter += userpayload.overflow_counter;
3259 :
3260 : return 0;
3261 : }
3262 :
3263 0 : int dlt_daemon_send_message_overflow(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose)
3264 : {
3265 : int ret;
3266 0 : PRINT_FUNCTION_VERBOSE(verbose);
3267 :
3268 0 : if ((daemon == 0) || (daemon_local == 0)) {
3269 0 : dlt_log(LOG_ERR, "Invalid function parameters used for function dlt_daemon_process_user_message_overflow()\n");
3270 0 : return DLT_DAEMON_ERROR_UNKNOWN;
3271 : }
3272 :
3273 : /* Store in daemon, that a message buffer overflow has occured */
3274 : if ((ret =
3275 0 : dlt_daemon_control_message_buffer_overflow(DLT_DAEMON_SEND_TO_ALL, daemon, daemon_local,
3276 : daemon->overflow_counter,
3277 : "", verbose)))
3278 : return ret;
3279 :
3280 : return DLT_DAEMON_ERROR_OK;
3281 : }
3282 :
3283 7 : int dlt_daemon_process_user_message_register_application(DltDaemon *daemon,
3284 : DltDaemonLocal *daemon_local,
3285 : DltReceiver *rec,
3286 : int verbose)
3287 : {
3288 : uint32_t len = sizeof(DltUserControlMsgRegisterApplication);
3289 : uint32_t to_remove = 0;
3290 : DltDaemonApplication *application = NULL;
3291 : DltDaemonApplication *old_application = NULL;
3292 : pid_t old_pid = 0;
3293 7 : char description[DLT_DAEMON_DESCSIZE + 1] = { '\0' };
3294 : DltUserControlMsgRegisterApplication userapp;
3295 : char *origin;
3296 : int fd = -1;
3297 :
3298 7 : PRINT_FUNCTION_VERBOSE(verbose);
3299 :
3300 7 : if ((daemon == NULL) || (daemon_local == NULL) || (rec == NULL)) {
3301 0 : dlt_vlog(LOG_ERR, "Invalid function parameters used for %s\n",
3302 : __func__);
3303 0 : return -1;
3304 : }
3305 :
3306 : memset(&userapp, 0, sizeof(DltUserControlMsgRegisterApplication));
3307 7 : origin = rec->buf;
3308 :
3309 : /* Adding temp variable to check the return value */
3310 : int temp = 0;
3311 :
3312 : /* We shall not remove data before checking that everything is there. */
3313 7 : temp = dlt_receiver_check_and_get(rec,
3314 : &userapp,
3315 : len,
3316 : DLT_RCV_SKIP_HEADER);
3317 :
3318 7 : if (temp < 0)
3319 : /* Not enough bytes received */
3320 : return -1;
3321 : else {
3322 7 : to_remove = (uint32_t) temp;
3323 : }
3324 :
3325 7 : len = userapp.description_length;
3326 :
3327 7 : if (len > DLT_DAEMON_DESCSIZE) {
3328 : len = DLT_DAEMON_DESCSIZE;
3329 0 : dlt_log(LOG_WARNING, "Application description exceeds limit\n");
3330 : }
3331 :
3332 : /* adjust buffer pointer */
3333 7 : rec->buf += to_remove + sizeof(DltUserHeader);
3334 :
3335 7 : if (dlt_receiver_check_and_get(rec, description, len, DLT_RCV_NONE) < 0) {
3336 0 : dlt_log(LOG_ERR, "Unable to get application description\n");
3337 : /* in case description was not readable, set dummy description */
3338 : memcpy(description, "Unknown", sizeof("Unknown"));
3339 :
3340 : /* unknown len of original description, set to 0 to not remove in next
3341 : * step. Because message buffer is re-adjusted the corrupted description
3342 : * is ignored. */
3343 : len = 0;
3344 : }
3345 :
3346 : /* adjust to_remove */
3347 7 : to_remove += (uint32_t) sizeof(DltUserHeader) + len;
3348 : /* point to begin of message */
3349 7 : rec->buf = origin;
3350 :
3351 : /* We can now remove data. */
3352 7 : if (dlt_receiver_remove(rec, (int) to_remove) != DLT_RETURN_OK) {
3353 0 : dlt_log(LOG_WARNING, "Can't remove bytes from receiver\n");
3354 0 : return -1;
3355 : }
3356 :
3357 7 : old_application = dlt_daemon_application_find(daemon, userapp.apid, daemon->ecuid, verbose);
3358 :
3359 7 : if (old_application != NULL)
3360 0 : old_pid = old_application->pid;
3361 :
3362 7 : if (rec->type == DLT_RECEIVE_SOCKET)
3363 0 : fd = rec->fd; /* For sockets, an app specific fd has already been created with accept(). */
3364 :
3365 7 : application = dlt_daemon_application_add(daemon,
3366 : userapp.apid,
3367 : userapp.pid,
3368 : description,
3369 : fd,
3370 : daemon->ecuid,
3371 : verbose);
3372 :
3373 : /* send log state to new application */
3374 7 : dlt_daemon_user_send_log_state(daemon, application, verbose);
3375 :
3376 7 : if (application == NULL) {
3377 0 : dlt_vlog(LOG_WARNING, "Can't add ApplicationID '%.4s' for PID %d\n",
3378 : userapp.apid, userapp.pid);
3379 0 : return -1;
3380 : }
3381 7 : else if (old_pid != application->pid)
3382 : {
3383 7 : char local_str[DLT_DAEMON_TEXTBUFSIZE] = { '\0' };
3384 :
3385 7 : snprintf(local_str,
3386 : DLT_DAEMON_TEXTBUFSIZE,
3387 : "ApplicationID '%.4s' registered for PID %d, Description=%s",
3388 7 : application->apid,
3389 : application->pid,
3390 : application->application_description);
3391 7 : dlt_daemon_log_internal(daemon, daemon_local, local_str, DLT_LOG_INFO,
3392 : DLT_DAEMON_APP_ID, DLT_DAEMON_CTX_ID,
3393 : daemon_local->flags.vflag);
3394 7 : dlt_vlog(LOG_DEBUG, "%s%s", local_str, "\n");
3395 : }
3396 :
3397 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
3398 : if (dlt_daemon_user_send_trace_load_config(daemon, application, verbose) != DLT_RETURN_OK)
3399 : dlt_vlog(LOG_WARNING, "Cannot send trace config to Apid: %.4s, PID: %d\n",
3400 : application->apid, application->pid);
3401 : #endif
3402 :
3403 : return 0;
3404 : }
3405 :
3406 38 : int dlt_daemon_process_user_message_register_context(DltDaemon *daemon,
3407 : DltDaemonLocal *daemon_local,
3408 : DltReceiver *rec,
3409 : int verbose)
3410 : {
3411 : uint32_t to_remove = 0;
3412 : uint32_t len = sizeof(DltUserControlMsgRegisterContext);
3413 : DltUserControlMsgRegisterContext userctxt;
3414 38 : char description[DLT_DAEMON_DESCSIZE + 1] = { '\0' };
3415 : DltDaemonApplication *application = NULL;
3416 : DltDaemonContext *context = NULL;
3417 : DltServiceGetLogInfoRequest *req = NULL;
3418 : char *origin;
3419 :
3420 : DltMessage msg;
3421 :
3422 38 : PRINT_FUNCTION_VERBOSE(verbose);
3423 :
3424 38 : if ((daemon == NULL) || (daemon_local == NULL) || (rec == NULL)) {
3425 0 : dlt_vlog(LOG_ERR, "Invalid function parameters used for %s\n",
3426 : __func__);
3427 0 : return -1;
3428 : }
3429 :
3430 : memset(&userctxt, 0, sizeof(DltUserControlMsgRegisterContext));
3431 38 : origin = rec->buf;
3432 :
3433 : /* Adding temp variable to check the return value */
3434 : int temp = 0;
3435 :
3436 38 : temp = dlt_receiver_check_and_get(rec,
3437 : &userctxt,
3438 : len,
3439 : DLT_RCV_SKIP_HEADER);
3440 :
3441 38 : if (temp < 0)
3442 : /* Not enough bytes received */
3443 : return -1;
3444 : else {
3445 38 : to_remove = (uint32_t) temp;
3446 : }
3447 :
3448 38 : len = userctxt.description_length;
3449 :
3450 38 : if (len > DLT_DAEMON_DESCSIZE) {
3451 0 : dlt_vlog(LOG_WARNING, "Context description exceeds limit: %u\n", len);
3452 : len = DLT_DAEMON_DESCSIZE;
3453 : }
3454 :
3455 : /* adjust buffer pointer */
3456 38 : rec->buf += to_remove + sizeof(DltUserHeader);
3457 :
3458 38 : if (dlt_receiver_check_and_get(rec, description, len, DLT_RCV_NONE) < 0) {
3459 0 : dlt_log(LOG_ERR, "Unable to get context description\n");
3460 : /* in case description was not readable, set dummy description */
3461 : memcpy(description, "Unknown", sizeof("Unknown"));
3462 :
3463 : /* unknown len of original description, set to 0 to not remove in next
3464 : * step. Because message buffer is re-adjusted the corrupted description
3465 : * is ignored. */
3466 : len = 0;
3467 : }
3468 :
3469 : /* adjust to_remove */
3470 38 : to_remove += (uint32_t) sizeof(DltUserHeader) + len;
3471 : /* point to begin of message */
3472 38 : rec->buf = origin;
3473 :
3474 : /* We can now remove data. */
3475 38 : if (dlt_receiver_remove(rec, (int) to_remove) != DLT_RETURN_OK) {
3476 0 : dlt_log(LOG_WARNING, "Can't remove bytes from receiver\n");
3477 0 : return -1;
3478 : }
3479 :
3480 38 : application = dlt_daemon_application_find(daemon,
3481 : userctxt.apid,
3482 38 : daemon->ecuid,
3483 : verbose);
3484 :
3485 38 : if (application == 0) {
3486 0 : dlt_vlog(LOG_WARNING,
3487 : "ApID '%.4s' not found for new ContextID '%.4s' in %s\n",
3488 : userctxt.apid,
3489 : userctxt.ctid,
3490 : __func__);
3491 :
3492 0 : return 0;
3493 : }
3494 :
3495 : /* Set log level */
3496 38 : if (userctxt.log_level == DLT_USER_LOG_LEVEL_NOT_SET) {
3497 38 : userctxt.log_level = DLT_LOG_DEFAULT;
3498 : } else {
3499 : /* Plausibility check */
3500 0 : if ((userctxt.log_level < DLT_LOG_DEFAULT) ||
3501 : (userctxt.log_level > DLT_LOG_VERBOSE)) {
3502 : return -1;
3503 : }
3504 : }
3505 :
3506 : /* Set trace status */
3507 38 : if (userctxt.trace_status == DLT_USER_TRACE_STATUS_NOT_SET) {
3508 38 : userctxt.trace_status = DLT_TRACE_STATUS_DEFAULT;
3509 : } else {
3510 : /* Plausibility check */
3511 0 : if ((userctxt.trace_status < DLT_TRACE_STATUS_DEFAULT) ||
3512 : (userctxt.trace_status > DLT_TRACE_STATUS_ON)) {
3513 : return -1;
3514 : }
3515 : }
3516 :
3517 38 : context = dlt_daemon_context_add(daemon,
3518 : userctxt.apid,
3519 : userctxt.ctid,
3520 38 : userctxt.log_level,
3521 38 : userctxt.trace_status,
3522 : userctxt.log_level_pos,
3523 : application->user_handle,
3524 : description,
3525 : daemon->ecuid,
3526 : verbose);
3527 :
3528 38 : if (context == 0) {
3529 0 : dlt_vlog(LOG_WARNING,
3530 : "Can't add ContextID '%.4s' for ApID '%.4s'\n in %s",
3531 : userctxt.ctid, userctxt.apid, __func__);
3532 0 : return -1;
3533 : }
3534 : else {
3535 38 : char local_str[DLT_DAEMON_TEXTBUFSIZE] = { '\0' };
3536 :
3537 38 : snprintf(local_str,
3538 : DLT_DAEMON_TEXTBUFSIZE,
3539 : "ContextID '%.4s' registered for ApID '%.4s', Description=%s",
3540 38 : context->ctid,
3541 38 : context->apid,
3542 : context->context_description);
3543 :
3544 38 : if (verbose)
3545 0 : dlt_daemon_log_internal(daemon, daemon_local, local_str,
3546 : DLT_LOG_INFO, DLT_DAEMON_APP_ID,
3547 : DLT_DAEMON_CTX_ID, verbose);
3548 :
3549 38 : dlt_vlog(LOG_DEBUG, "%s%s", local_str, "\n");
3550 : }
3551 :
3552 38 : if (daemon_local->flags.offlineLogstorageMaxDevices)
3553 : /* Store log level set for offline logstorage into context structure*/
3554 33 : context->storage_log_level =
3555 33 : (int8_t) dlt_daemon_logstorage_get_loglevel(daemon,
3556 33 : (int8_t) daemon_local->flags.offlineLogstorageMaxDevices,
3557 : userctxt.apid,
3558 : userctxt.ctid);
3559 : else
3560 5 : context->storage_log_level = DLT_LOG_DEFAULT;
3561 :
3562 : /* Create automatic get log info response for registered context */
3563 38 : if (daemon_local->flags.rflag) {
3564 : /* Prepare request for get log info with one application and one context */
3565 0 : if (dlt_message_init(&msg, verbose) == -1) {
3566 0 : dlt_log(LOG_WARNING, "Can't initialize message");
3567 0 : return -1;
3568 : }
3569 :
3570 0 : msg.datasize = sizeof(DltServiceGetLogInfoRequest);
3571 :
3572 0 : if (msg.databuffer && (msg.databuffersize < msg.datasize)) {
3573 0 : free(msg.databuffer);
3574 0 : msg.databuffer = 0;
3575 : }
3576 :
3577 0 : if (msg.databuffer == 0) {
3578 0 : msg.databuffer = (uint8_t *)malloc(msg.datasize);
3579 0 : msg.databuffersize = msg.datasize;
3580 : }
3581 :
3582 0 : if (msg.databuffer == 0) {
3583 0 : dlt_log(LOG_WARNING, "Can't allocate buffer for get log info message\n");
3584 0 : return -1;
3585 : }
3586 :
3587 : req = (DltServiceGetLogInfoRequest *)msg.databuffer;
3588 :
3589 0 : req->service_id = DLT_SERVICE_ID_GET_LOG_INFO;
3590 0 : req->options = (uint8_t) daemon_local->flags.autoResponseGetLogInfoOption;
3591 0 : dlt_set_id(req->apid, userctxt.apid);
3592 0 : dlt_set_id(req->ctid, userctxt.ctid);
3593 0 : dlt_set_id(req->com, "remo");
3594 :
3595 0 : dlt_daemon_control_get_log_info(DLT_DAEMON_SEND_TO_ALL, daemon, daemon_local, &msg, verbose);
3596 :
3597 0 : dlt_message_free(&msg, verbose);
3598 : }
3599 :
3600 38 : if (context->user_handle >= DLT_FD_MINIMUM) {
3601 38 : if ((userctxt.log_level == DLT_LOG_DEFAULT) || (userctxt.trace_status == DLT_TRACE_STATUS_DEFAULT)) {
3602 : /* This call also replaces the default values with the values defined for default */
3603 38 : if (dlt_daemon_user_send_log_level(daemon, context, verbose) == -1) {
3604 0 : dlt_vlog(LOG_WARNING, "Can't send current log level as response to %s for (%.4s;%.4s)\n",
3605 : __func__,
3606 : context->apid,
3607 : context->ctid);
3608 0 : return -1;
3609 : }
3610 : }
3611 : }
3612 :
3613 : return 0;
3614 : }
3615 :
3616 6 : int dlt_daemon_process_user_message_unregister_application(DltDaemon *daemon,
3617 : DltDaemonLocal *daemon_local,
3618 : DltReceiver *rec,
3619 : int verbose)
3620 : {
3621 : uint32_t len = sizeof(DltUserControlMsgUnregisterApplication);
3622 : DltUserControlMsgUnregisterApplication userapp;
3623 : DltDaemonApplication *application = NULL;
3624 : DltDaemonContext *context;
3625 : int i, offset_base;
3626 : DltDaemonRegisteredUsers *user_list = NULL;
3627 :
3628 6 : PRINT_FUNCTION_VERBOSE(verbose);
3629 :
3630 6 : if ((daemon == NULL) || (daemon_local == NULL) || (rec == NULL)) {
3631 0 : dlt_vlog(LOG_ERR,
3632 : "Invalid function parameters used for %s\n",
3633 : __func__);
3634 0 : return -1;
3635 : }
3636 :
3637 6 : if (dlt_receiver_check_and_get(rec,
3638 : &userapp,
3639 : len,
3640 : DLT_RCV_SKIP_HEADER | DLT_RCV_REMOVE) < 0)
3641 : /* Not enough bytes received */
3642 : return -1;
3643 :
3644 6 : user_list = dlt_daemon_find_users_list(daemon, daemon->ecuid, verbose);
3645 :
3646 6 : if (user_list == NULL)
3647 : return -1;
3648 :
3649 6 : if (user_list->num_applications > 0) {
3650 : /* Delete this application and all corresponding contexts
3651 : * for this application from internal table.
3652 : */
3653 6 : application = dlt_daemon_application_find(daemon,
3654 : userapp.apid,
3655 : daemon->ecuid,
3656 : verbose);
3657 :
3658 6 : if (application) {
3659 : /* Calculate start offset within contexts[] */
3660 : offset_base = 0;
3661 :
3662 6 : for (i = 0; i < (application - (user_list->applications)); i++)
3663 0 : offset_base += user_list->applications[i].num_contexts;
3664 :
3665 6 : for (i = (application->num_contexts) - 1; i >= 0; i--) {
3666 0 : context = &(user_list->contexts[offset_base + i]);
3667 :
3668 0 : if (context) {
3669 : /* Delete context */
3670 0 : if (dlt_daemon_context_del(daemon,
3671 : context,
3672 : daemon->ecuid,
3673 : verbose) == -1) {
3674 0 : dlt_vlog(LOG_WARNING,
3675 : "Can't delete CtID '%.4s' for ApID '%.4s' in %s\n",
3676 0 : context->ctid,
3677 0 : context->apid,
3678 : __func__);
3679 0 : return -1;
3680 : }
3681 : }
3682 : }
3683 :
3684 : /* Delete this application entry from internal table*/
3685 6 : if (dlt_daemon_application_del(daemon,
3686 : application,
3687 : daemon->ecuid,
3688 : verbose) == -1) {
3689 0 : dlt_vlog(LOG_WARNING,
3690 : "Can't delete ApID '%.4s' in %s\n",
3691 0 : application->apid,
3692 : __func__);
3693 0 : return -1;
3694 : }
3695 : else {
3696 6 : char local_str[DLT_DAEMON_TEXTBUFSIZE] = { '\0' };
3697 :
3698 : snprintf(local_str,
3699 : DLT_DAEMON_TEXTBUFSIZE,
3700 : "Unregistered ApID '%.4s'",
3701 : userapp.apid);
3702 6 : dlt_daemon_log_internal(daemon, daemon_local, local_str,
3703 : DLT_LOG_INFO, DLT_DAEMON_APP_ID,
3704 : DLT_DAEMON_CTX_ID, verbose);
3705 6 : dlt_vlog(LOG_DEBUG, "%s%s", local_str, "\n");
3706 : }
3707 : }
3708 : }
3709 :
3710 : return 0;
3711 : }
3712 :
3713 37 : int dlt_daemon_process_user_message_unregister_context(DltDaemon *daemon,
3714 : DltDaemonLocal *daemon_local,
3715 : DltReceiver *rec,
3716 : int verbose)
3717 : {
3718 : uint32_t len = sizeof(DltUserControlMsgUnregisterContext);
3719 : DltUserControlMsgUnregisterContext userctxt;
3720 : DltDaemonContext *context;
3721 :
3722 37 : PRINT_FUNCTION_VERBOSE(verbose);
3723 :
3724 37 : if ((daemon == NULL) || (daemon_local == NULL) || (rec == NULL)) {
3725 0 : dlt_vlog(LOG_ERR,
3726 : "Invalid function parameters used for %s\n",
3727 : __func__);
3728 :
3729 0 : return -1;
3730 : }
3731 :
3732 37 : if (dlt_receiver_check_and_get(rec,
3733 : &userctxt,
3734 : len,
3735 : DLT_RCV_SKIP_HEADER | DLT_RCV_REMOVE) < 0)
3736 : /* Not enough bytes received */
3737 : return -1;
3738 :
3739 37 : context = dlt_daemon_context_find(daemon,
3740 : userctxt.apid,
3741 : userctxt.ctid,
3742 37 : daemon->ecuid,
3743 : verbose);
3744 :
3745 : /* In case the daemon is loaded with predefined contexts and its context
3746 : * unregisters, the context information will not be deleted from daemon's
3747 : * table until its parent application is unregistered.
3748 : */
3749 37 : if (context && (context->predefined == false)) {
3750 : /* Delete this connection entry from internal table*/
3751 37 : if (dlt_daemon_context_del(daemon, context, daemon->ecuid, verbose) == -1) {
3752 0 : dlt_vlog(LOG_WARNING,
3753 : "Can't delete CtID '%.4s' for ApID '%.4s' in %s\n",
3754 : userctxt.ctid,
3755 : userctxt.apid,
3756 : __func__);
3757 0 : return -1;
3758 : }
3759 : else {
3760 37 : char local_str[DLT_DAEMON_TEXTBUFSIZE] = { '\0' };
3761 :
3762 : snprintf(local_str,
3763 : DLT_DAEMON_TEXTBUFSIZE,
3764 : "Unregistered CtID '%.4s' for ApID '%.4s'",
3765 : userctxt.ctid,
3766 : userctxt.apid);
3767 :
3768 37 : if (verbose)
3769 0 : dlt_daemon_log_internal(daemon, daemon_local, local_str,
3770 : DLT_LOG_INFO, DLT_DAEMON_APP_ID,
3771 : DLT_DAEMON_CTX_ID, verbose);
3772 :
3773 37 : dlt_vlog(LOG_DEBUG, "%s%s", local_str, "\n");
3774 : }
3775 : }
3776 :
3777 : /* Create automatic unregister context response for unregistered context */
3778 37 : if (daemon_local->flags.rflag)
3779 0 : dlt_daemon_control_message_unregister_context(DLT_DAEMON_SEND_TO_ALL,
3780 : daemon,
3781 : daemon_local,
3782 : userctxt.apid,
3783 : userctxt.ctid,
3784 : "remo",
3785 : verbose);
3786 :
3787 : return 0;
3788 : }
3789 :
3790 5811 : int dlt_daemon_process_user_message_log(DltDaemon *daemon,
3791 : DltDaemonLocal *daemon_local,
3792 : DltReceiver *rec,
3793 : int verbose)
3794 : {
3795 : int ret = 0;
3796 : int size = 0;
3797 :
3798 5811 : PRINT_FUNCTION_VERBOSE(verbose);
3799 :
3800 5811 : if ((daemon == NULL) || (daemon_local == NULL) || (rec == NULL)) {
3801 0 : dlt_vlog(LOG_ERR, "%s: invalid function parameters.\n", __func__);
3802 0 : return DLT_DAEMON_ERROR_UNKNOWN;
3803 : }
3804 :
3805 : #ifdef DLT_SYSTEMD_WATCHDOG_ENFORCE_MSG_RX_ENABLE
3806 : daemon->received_message_since_last_watchdog_interval = 1;
3807 : #endif
3808 : #ifdef DLT_SHM_ENABLE
3809 :
3810 : /** In case of SHM, the header still received via fifo/unix_socket receiver,
3811 : * so we need to remove header from the receiver.
3812 : */
3813 : if (dlt_receiver_remove(rec, sizeof(DltUserHeader)) < 0)
3814 : /* Not enough bytes received to remove*/
3815 : return DLT_DAEMON_ERROR_UNKNOWN;
3816 :
3817 : while (1) {
3818 : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
3819 : bool watchdog_triggered = dlt_daemon_trigger_systemd_watchdog_if_necessary(daemon);
3820 : if (watchdog_triggered) {
3821 : dlt_vlog(LOG_WARNING, "%s yields due to watchdog.\n", __func__);
3822 : break;
3823 : }
3824 : #endif
3825 :
3826 : /* get log message from SHM then store into receiver buffer */
3827 : size = dlt_shm_pull(&(daemon_local->dlt_shm),
3828 : daemon_local->recv_buf_shm,
3829 : DLT_SHM_RCV_BUFFER_SIZE);
3830 :
3831 : if (size <= 0)
3832 : break;
3833 :
3834 : ret = dlt_message_read(&(daemon_local->msg),
3835 : daemon_local->recv_buf_shm, size, 0, verbose);
3836 :
3837 : if (DLT_MESSAGE_ERROR_OK != ret) {
3838 : dlt_shm_remove(&(daemon_local->dlt_shm));
3839 : dlt_log(LOG_WARNING, "failed to read messages from shm.\n");
3840 : return DLT_DAEMON_ERROR_UNKNOWN;
3841 : }
3842 :
3843 : #if defined(DLT_LOG_LEVEL_APP_CONFIG) || defined(DLT_TRACE_LOAD_CTRL_ENABLE)
3844 : DltDaemonApplication *app = dlt_daemon_application_find(
3845 : daemon, daemon_local->msg.extendedheader->apid, daemon->ecuid, verbose);
3846 : #endif
3847 :
3848 : /* discard non-allowed levels if enforcement is on */
3849 : bool keep_message = enforce_context_ll_and_ts_keep_message(
3850 : daemon_local
3851 : #ifdef DLT_LOG_LEVEL_APP_CONFIG
3852 : , app
3853 : #endif
3854 : );
3855 :
3856 : // check trace_load
3857 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
3858 : keep_message &= trace_load_keep_message(app, size, daemon, daemon_local, verbose);
3859 : #endif
3860 :
3861 : if (keep_message)
3862 : dlt_daemon_client_send_message_to_all_client(daemon, daemon_local, verbose);
3863 :
3864 : if (DLT_DAEMON_ERROR_OK != ret)
3865 : dlt_log(LOG_ERR, "failed to send message to client.\n");
3866 : }
3867 :
3868 : #else
3869 5811 : ret = dlt_message_read(&(daemon_local->msg),
3870 5811 : (unsigned char *)rec->buf + sizeof(DltUserHeader),
3871 5811 : (unsigned int) ((unsigned int) rec->bytesRcvd - sizeof(DltUserHeader)),
3872 : 0,
3873 : verbose);
3874 :
3875 5811 : if (ret != DLT_MESSAGE_ERROR_OK) {
3876 0 : if (ret != DLT_MESSAGE_ERROR_SIZE)
3877 : /* This is a normal usecase: The daemon reads the data in 10kb chunks.
3878 : * Thus the last trace in this chunk is probably not complete and will be completed
3879 : * with the next chunk read. This happens always when the FIFO is filled with more than 10kb before
3880 : * the daemon is able to read from the FIFO.
3881 : * Thus the loglevel of this message is set to DEBUG.
3882 : * A cleaner solution would be to check more in detail whether the message is not complete (normal usecase)
3883 : * or the headers are corrupted (error case). */
3884 0 : dlt_log(LOG_DEBUG, "Can't read messages from receiver\n");
3885 :
3886 0 : if (dlt_receiver_remove(rec, rec->bytesRcvd) != DLT_RETURN_OK) {
3887 : /* In certain rare scenarios where only a partial message has been received
3888 : * (Eg: kernel IPC buffer memory being full), we want to discard the message
3889 : * and not broadcast it forward to connected clients. Since the DLT library
3890 : * checks return value of the writev() call against the sent total message
3891 : * length, the partial message will be buffered and retransmitted again.
3892 : * This implicitly ensures that no message loss occurs.
3893 : */
3894 0 : dlt_log(LOG_WARNING, "failed to remove required bytes from receiver.\n");
3895 : }
3896 :
3897 0 : return DLT_DAEMON_ERROR_UNKNOWN;
3898 : }
3899 :
3900 : #if defined(DLT_LOG_LEVEL_APP_CONFIG) || defined(DLT_TRACE_LOAD_CTRL_ENABLE)
3901 : DltDaemonApplication *app = dlt_daemon_application_find(
3902 : daemon, daemon_local->msg.extendedheader->apid, daemon->ecuid, verbose);
3903 : #endif
3904 :
3905 : /* discard non-allowed levels if enforcement is on */
3906 0 : bool keep_message = enforce_context_ll_and_ts_keep_message(
3907 : daemon_local
3908 : #ifdef DLT_LOG_LEVEL_APP_CONFIG
3909 : , app
3910 : #endif
3911 : );
3912 :
3913 : // check trace_load
3914 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
3915 : keep_message &=
3916 : trace_load_keep_message(app, size, daemon, daemon_local, verbose);
3917 : #endif
3918 :
3919 0 : if (keep_message)
3920 5811 : dlt_daemon_client_send_message_to_all_client(daemon, daemon_local, verbose);
3921 :
3922 : /* keep not read data in buffer */
3923 5811 : size = (int) (daemon_local->msg.headersize +
3924 5811 : daemon_local->msg.datasize - sizeof(DltStorageHeader) +
3925 : sizeof(DltUserHeader));
3926 :
3927 5811 : if (daemon_local->msg.found_serialheader)
3928 : size += (int) sizeof(dltSerialHeader);
3929 :
3930 5811 : if (dlt_receiver_remove(rec, size) != DLT_RETURN_OK) {
3931 0 : dlt_log(LOG_WARNING, "failed to remove bytes from receiver.\n");
3932 0 : return DLT_DAEMON_ERROR_UNKNOWN;
3933 : }
3934 :
3935 : #endif
3936 :
3937 : return DLT_DAEMON_ERROR_OK;
3938 : }
3939 :
3940 0 : bool enforce_context_ll_and_ts_keep_message(DltDaemonLocal *daemon_local
3941 : #ifdef DLT_LOG_LEVEL_APP_CONFIG
3942 : , DltDaemonApplication *app
3943 : #endif
3944 : )
3945 : {
3946 5811 : if (!daemon_local->flags.enforceContextLLAndTS ||
3947 0 : !daemon_local->msg.extendedheader) {
3948 : return true;
3949 : }
3950 :
3951 : #ifdef DLT_LOG_LEVEL_APP_CONFIG
3952 : if (app == NULL) {
3953 : return true;
3954 : }
3955 : #endif
3956 :
3957 0 : const int mtin = DLT_GET_MSIN_MTIN(daemon_local->msg.extendedheader->msin);
3958 : #ifdef DLT_LOG_LEVEL_APP_CONFIG
3959 : if (app->num_context_log_level_settings > 0) {
3960 : DltDaemonContextLogSettings *log_settings =
3961 : dlt_daemon_find_app_log_level_config(app, daemon_local->msg.extendedheader->ctid);
3962 :
3963 : if (log_settings != NULL) {
3964 : return mtin <= log_settings->log_level;
3965 : }
3966 : }
3967 : #endif
3968 0 : return mtin <= daemon_local->flags.contextLogLevel;
3969 : }
3970 :
3971 :
3972 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
3973 : bool trace_load_keep_message(DltDaemonApplication *app,
3974 : const int size, DltDaemon *const daemon,
3975 : DltDaemonLocal *const daemon_local,
3976 : int verbose)
3977 : {
3978 : bool keep_message = true;
3979 : if (app == NULL || !daemon_local->msg.extendedheader) {
3980 : return keep_message;
3981 : }
3982 :
3983 : DltMessage* msg = &daemon_local->msg;
3984 : const int mtin = DLT_GET_MSIN_MTIN(msg->extendedheader->msin);
3985 :
3986 : struct DltTraceLoadLogParams params = {
3987 : daemon,
3988 : daemon_local,
3989 : verbose,
3990 : app->apid,
3991 : };
3992 :
3993 : DltTraceLoadSettings *trace_load_settings =
3994 : dlt_find_runtime_trace_load_settings(
3995 : app->trace_load_settings, app->trace_load_settings_count,
3996 : app->apid, msg->extendedheader->ctid);
3997 :
3998 : if (trace_load_settings != NULL) {
3999 : pthread_rwlock_wrlock(&trace_load_rw_lock);
4000 : keep_message = dlt_check_trace_load(
4001 : trace_load_settings, mtin, msg->headerextra.tmsp, size,
4002 : dlt_daemon_output_internal_msg, (void *)(¶ms));
4003 : pthread_rwlock_unlock(&trace_load_rw_lock);
4004 : }
4005 : else {
4006 : dlt_vlog(
4007 : LOG_ERR,
4008 : "Failed to lookup trace load limits for %s, "
4009 : "dropping message, likely app was not registered properly\n",
4010 : app->apid);
4011 : keep_message = false;
4012 : }
4013 :
4014 : return keep_message;
4015 : }
4016 : #endif
4017 :
4018 0 : int dlt_daemon_process_user_message_set_app_ll_ts(DltDaemon *daemon,
4019 : DltDaemonLocal *daemon_local,
4020 : DltReceiver *rec,
4021 : int verbose)
4022 : {
4023 : uint32_t len = sizeof(DltUserControlMsgAppLogLevelTraceStatus);
4024 : DltUserControlMsgAppLogLevelTraceStatus userctxt;
4025 : DltDaemonApplication *application;
4026 : DltDaemonContext *context;
4027 : int i, offset_base;
4028 : int8_t old_log_level, old_trace_status;
4029 : DltDaemonRegisteredUsers *user_list = NULL;
4030 :
4031 0 : PRINT_FUNCTION_VERBOSE(verbose);
4032 :
4033 0 : if ((daemon == NULL) || (daemon_local == NULL) || (rec == NULL)) {
4034 0 : dlt_vlog(LOG_ERR,
4035 : "Invalid function parameters used for %s\n",
4036 : __func__);
4037 0 : return DLT_RETURN_ERROR;
4038 : }
4039 :
4040 0 : user_list = dlt_daemon_find_users_list(daemon, daemon->ecuid, verbose);
4041 :
4042 0 : if (user_list == NULL)
4043 : return DLT_RETURN_ERROR;
4044 :
4045 : memset(&userctxt, 0, len);
4046 :
4047 0 : if (dlt_receiver_check_and_get(rec,
4048 : &userctxt,
4049 : len,
4050 : DLT_RCV_SKIP_HEADER | DLT_RCV_REMOVE) < 0)
4051 : /* Not enough bytes received */
4052 : return DLT_RETURN_ERROR;
4053 :
4054 0 : if (user_list->num_applications > 0) {
4055 : /* Get all contexts with application id matching the received application id */
4056 0 : application = dlt_daemon_application_find(daemon,
4057 : userctxt.apid,
4058 : daemon->ecuid,
4059 : verbose);
4060 :
4061 0 : if (application) {
4062 : /* Calculate start offset within contexts[] */
4063 : offset_base = 0;
4064 :
4065 0 : for (i = 0; i < (application - (user_list->applications)); i++)
4066 0 : offset_base += user_list->applications[i].num_contexts;
4067 :
4068 0 : for (i = 0; i < application->num_contexts; i++) {
4069 0 : context = &(user_list->contexts[offset_base + i]);
4070 :
4071 0 : if (context) {
4072 0 : old_log_level = context->log_level;
4073 0 : context->log_level = (int8_t) userctxt.log_level; /* No endianess conversion necessary*/
4074 :
4075 0 : old_trace_status = context->trace_status;
4076 0 : context->trace_status = (int8_t) userctxt.trace_status; /* No endianess conversion necessary */
4077 :
4078 : /* The following function sends also the trace status */
4079 0 : if ((context->user_handle >= DLT_FD_MINIMUM) &&
4080 0 : (dlt_daemon_user_send_log_level(daemon,
4081 : context,
4082 : verbose) != 0)) {
4083 0 : context->log_level = old_log_level;
4084 0 : context->trace_status = old_trace_status;
4085 : }
4086 : }
4087 : }
4088 : }
4089 : }
4090 :
4091 : return DLT_RETURN_OK;
4092 : }
4093 :
4094 0 : int dlt_daemon_process_user_message_log_mode(DltDaemon *daemon,
4095 : DltDaemonLocal *daemon_local,
4096 : DltReceiver *rec,
4097 : int verbose)
4098 : {
4099 : DltUserControlMsgLogMode userctxt;
4100 : uint32_t len = sizeof(DltUserControlMsgLogMode);
4101 :
4102 0 : PRINT_FUNCTION_VERBOSE(verbose);
4103 :
4104 0 : if ((daemon == 0) || (daemon_local == 0)) {
4105 0 : dlt_log(LOG_ERR, "Invalid function parameters used for function dlt_daemon_process_log_mode()\n");
4106 0 : return -1;
4107 : }
4108 :
4109 : memset(&userctxt, 0, len);
4110 :
4111 0 : if (dlt_receiver_check_and_get(rec,
4112 : &userctxt,
4113 : len,
4114 : DLT_RCV_SKIP_HEADER | DLT_RCV_REMOVE) < 0)
4115 : /* Not enough bytes received */
4116 : return -1;
4117 :
4118 : /* set the new log mode */
4119 0 : daemon->mode = userctxt.log_mode;
4120 :
4121 : /* write configuration persistantly */
4122 0 : dlt_daemon_configuration_save(daemon, daemon->runtime_configuration, verbose);
4123 :
4124 0 : return 0;
4125 : }
4126 :
4127 0 : int dlt_daemon_process_user_message_marker(DltDaemon *daemon,
4128 : DltDaemonLocal *daemon_local,
4129 : DltReceiver *rec,
4130 : int verbose)
4131 : {
4132 : uint32_t len = sizeof(DltUserControlMsgLogMode);
4133 : DltUserControlMsgLogMode userctxt;
4134 0 : PRINT_FUNCTION_VERBOSE(verbose);
4135 :
4136 0 : if ((daemon == NULL) || (daemon_local == NULL) || (rec == NULL)) {
4137 0 : dlt_vlog(LOG_ERR, "Invalid function parameters used for %s\n",
4138 : __func__);
4139 0 : return -1;
4140 : }
4141 :
4142 : memset(&userctxt, 0, len);
4143 :
4144 0 : if (dlt_receiver_check_and_get(rec,
4145 : &userctxt,
4146 : len,
4147 : DLT_RCV_SKIP_HEADER | DLT_RCV_REMOVE) < 0)
4148 : /* Not enough bytes received */
4149 : return -1;
4150 :
4151 : /* Create automatic unregister context response for unregistered context */
4152 0 : dlt_daemon_control_message_marker(DLT_DAEMON_SEND_TO_ALL, daemon, daemon_local, verbose);
4153 :
4154 0 : return 0;
4155 : }
4156 :
4157 2 : int dlt_daemon_send_ringbuffer_to_client(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose)
4158 : {
4159 : int ret;
4160 : static uint8_t data[DLT_DAEMON_RCVBUFSIZE];
4161 : int length;
4162 : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
4163 : uint32_t curr_time = 0U;
4164 : #endif
4165 :
4166 2 : PRINT_FUNCTION_VERBOSE(verbose);
4167 :
4168 2 : if ((daemon == 0) || (daemon_local == 0)) {
4169 0 : dlt_log(LOG_ERR, "Invalid function parameters used for function dlt_daemon_send_ringbuffer_to_client()\n");
4170 0 : return DLT_DAEMON_ERROR_UNKNOWN;
4171 : }
4172 :
4173 2 : if (dlt_buffer_get_message_count(&(daemon->client_ringbuffer)) <= 0) {
4174 0 : dlt_daemon_change_state(daemon, DLT_DAEMON_STATE_SEND_DIRECT);
4175 0 : return DLT_DAEMON_ERROR_OK;
4176 : }
4177 :
4178 4 : while ((length = dlt_buffer_copy(&(daemon->client_ringbuffer), data, sizeof(data))) > 0) {
4179 : #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
4180 : dlt_daemon_trigger_systemd_watchdog_if_necessary(daemon);
4181 : #endif
4182 :
4183 4 : if ((ret =
4184 4 : dlt_daemon_client_send(DLT_DAEMON_SEND_FORCE, daemon, daemon_local, 0, 0, data, length, 0, 0,
4185 : verbose)))
4186 0 : return ret;
4187 :
4188 4 : dlt_buffer_remove(&(daemon->client_ringbuffer));
4189 :
4190 4 : if (daemon->state != DLT_DAEMON_STATE_SEND_BUFFER)
4191 0 : dlt_daemon_change_state(daemon, DLT_DAEMON_STATE_SEND_BUFFER);
4192 :
4193 4 : if (dlt_buffer_get_message_count(&(daemon->client_ringbuffer)) <= 0) {
4194 2 : dlt_daemon_change_state(daemon, DLT_DAEMON_STATE_SEND_DIRECT);
4195 2 : return DLT_DAEMON_ERROR_OK;
4196 : }
4197 : }
4198 :
4199 : return DLT_DAEMON_ERROR_OK;
4200 : }
4201 :
4202 : #ifdef __QNX__
4203 : static void *timer_thread(void *data)
4204 : {
4205 : int pexit = 0;
4206 : unsigned int sleep_ret = 0;
4207 :
4208 : DltDaemonPeriodicData* timer_thread_data = (DltDaemonPeriodicData*) data;
4209 :
4210 : /* Timer will start in starts_in sec*/
4211 : if ((sleep_ret = sleep(timer_thread_data->starts_in))) {
4212 : dlt_vlog(LOG_NOTICE, "Sleep remains [%u] for starting!"
4213 : "Stop thread of timer [%d]\n",
4214 : sleep_ret, timer_thread_data->timer_id);
4215 : close_pipes(dlt_timer_pipes[timer_thread_data->timer_id]);
4216 : return NULL;
4217 : }
4218 :
4219 : while (1) {
4220 : if ((dlt_timer_pipes[timer_thread_data->timer_id][1] > 0) &&
4221 : (0 > write(dlt_timer_pipes[timer_thread_data->timer_id][1], "1", 1))) {
4222 : dlt_vlog(LOG_ERR, "Failed to send notification for timer [%s]!\n",
4223 : dlt_timer_names[timer_thread_data->timer_id]);
4224 : pexit = 1;
4225 : }
4226 :
4227 : if (pexit || g_exit) {
4228 : dlt_vlog(LOG_NOTICE, "Received signal!"
4229 : "Stop thread of timer [%d]\n",
4230 : timer_thread_data->timer_id);
4231 : close_pipes(dlt_timer_pipes[timer_thread_data->timer_id]);
4232 : return NULL;
4233 : }
4234 :
4235 : if ((sleep_ret = sleep(timer_thread_data->period_sec))) {
4236 : dlt_vlog(LOG_NOTICE, "Sleep remains [%u] for interval!"
4237 : "Stop thread of timer [%d]\n",
4238 : sleep_ret, timer_thread_data->timer_id);
4239 : close_pipes(dlt_timer_pipes[timer_thread_data->timer_id]);
4240 : return NULL;
4241 : }
4242 : }
4243 : }
4244 : #endif
4245 :
4246 10 : int create_timer_fd(DltDaemonLocal *daemon_local,
4247 : int period_sec,
4248 : int starts_in,
4249 : DltTimers timer_id)
4250 : {
4251 : int local_fd = DLT_FD_INIT;
4252 : char *timer_name = NULL;
4253 :
4254 10 : if (timer_id >= DLT_TIMER_UNKNOWN) {
4255 0 : dlt_log(DLT_LOG_ERROR, "Unknown timer.");
4256 0 : return -1;
4257 : }
4258 :
4259 10 : timer_name = dlt_timer_names[timer_id];
4260 :
4261 10 : if (daemon_local == NULL) {
4262 0 : dlt_log(DLT_LOG_ERROR, "Daemon local structure is NULL");
4263 0 : return -1;
4264 : }
4265 :
4266 10 : if ((period_sec <= 0) || (starts_in <= 0)) {
4267 : /* timer not activated via the service file */
4268 0 : dlt_vlog(LOG_INFO, "<%s> not set: period=0\n", timer_name);
4269 : local_fd = DLT_FD_INIT;
4270 : }
4271 : else {
4272 : #ifdef linux
4273 : struct itimerspec l_timer_spec;
4274 10 : local_fd = timerfd_create(CLOCK_MONOTONIC, 0);
4275 :
4276 10 : if (local_fd < 0)
4277 0 : dlt_vlog(LOG_WARNING, "<%s> timerfd_create failed: %s\n",
4278 0 : timer_name, strerror(errno));
4279 :
4280 10 : l_timer_spec.it_interval.tv_sec = period_sec;
4281 10 : l_timer_spec.it_interval.tv_nsec = 0;
4282 10 : l_timer_spec.it_value.tv_sec = starts_in;
4283 10 : l_timer_spec.it_value.tv_nsec = 0;
4284 :
4285 10 : if (timerfd_settime(local_fd, 0, &l_timer_spec, NULL) < 0) {
4286 0 : dlt_vlog(LOG_WARNING, "<%s> timerfd_settime failed: %s\n",
4287 0 : timer_name, strerror(errno));
4288 : local_fd = DLT_FD_INIT;
4289 : }
4290 : #elif __QNX__
4291 : /*
4292 : * Since timerfd is not valid in QNX, new threads are introduced
4293 : * to manage timers and communicate with main thread when timer expires.
4294 : */
4295 : if(0 != pipe(dlt_timer_pipes[timer_id])) {
4296 : dlt_vlog(LOG_ERR, "Failed to create pipe for timer [%s]",
4297 : dlt_timer_names[timer_id]);
4298 : return -1;
4299 : }
4300 : if (NULL == timer_data[timer_id]) {
4301 : timer_data[timer_id] = calloc(1, sizeof(DltDaemonPeriodicData));
4302 : if (NULL == timer_data[timer_id]) {
4303 : dlt_vlog(LOG_ERR, "Failed to allocate memory for timer_data [%s]!\n",
4304 : dlt_timer_names[timer_id]);
4305 : close_pipes(dlt_timer_pipes[timer_id]);
4306 : return -1;
4307 : }
4308 : }
4309 :
4310 : timer_data[timer_id]->timer_id = timer_id;
4311 : timer_data[timer_id]->period_sec = period_sec;
4312 : timer_data[timer_id]->starts_in = starts_in;
4313 : timer_data[timer_id]->wakeups_missed = 0;
4314 :
4315 : if (0 != pthread_create(&timer_threads[timer_id], NULL,
4316 : &timer_thread, (void*)timer_data[timer_id])) {
4317 : dlt_vlog(LOG_ERR, "Failed to create new thread for timer [%s]!\n",
4318 : dlt_timer_names[timer_id]);
4319 : /* Clean up timer before returning */
4320 : close_pipes(dlt_timer_pipes[timer_id]);
4321 : free(timer_data[timer_id]);
4322 : timer_data[timer_id] = NULL;
4323 :
4324 : return -1;
4325 : }
4326 : local_fd = dlt_timer_pipes[timer_id][0];
4327 : #endif
4328 : }
4329 :
4330 10 : return dlt_connection_create(daemon_local,
4331 : &daemon_local->pEvent,
4332 : local_fd,
4333 : POLLIN,
4334 10 : dlt_timer_conn_types[timer_id]);
4335 : }
4336 :
4337 : /* Close connection function */
4338 5 : int dlt_daemon_close_socket(int sock, DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose)
4339 : {
4340 5 : char local_str[DLT_DAEMON_TEXTBUFSIZE] = { '\0' };
4341 :
4342 5 : PRINT_FUNCTION_VERBOSE(verbose);
4343 :
4344 5 : if ((daemon_local == NULL) || (daemon == NULL)) {
4345 0 : dlt_log(LOG_ERR, "dlt_daemon_close_socket: Invalid input parmeters\n");
4346 0 : return -1;
4347 : }
4348 :
4349 : /* Closure is done while unregistering has for any connection */
4350 5 : dlt_event_handler_unregister_connection(&daemon_local->pEvent,
4351 : daemon_local,
4352 : sock);
4353 :
4354 5 : if (daemon_local->client_connections == 0) {
4355 : /* send new log state to all applications */
4356 3 : daemon->connectionState = 0;
4357 3 : dlt_daemon_user_send_all_log_state(daemon, verbose);
4358 :
4359 : /* For offline tracing we still can use the same states */
4360 : /* as for socket sending. Using this trick we see the traces */
4361 : /* In the offline trace AND in the socket stream. */
4362 3 : if (daemon_local->flags.yvalue[0] == 0)
4363 3 : dlt_daemon_change_state(daemon, DLT_DAEMON_STATE_BUFFER);
4364 : }
4365 :
4366 5 : dlt_daemon_control_message_connection_info(DLT_DAEMON_SEND_TO_ALL,
4367 : daemon,
4368 : daemon_local,
4369 : DLT_CONNECTION_STATUS_DISCONNECTED,
4370 : "",
4371 : verbose);
4372 :
4373 5 : snprintf(local_str, DLT_DAEMON_TEXTBUFSIZE,
4374 : "Client connection #%d closed. Total Clients : %d",
4375 : sock,
4376 : daemon_local->client_connections);
4377 5 : dlt_daemon_log_internal(daemon, daemon_local, local_str, DLT_LOG_INFO,
4378 : DLT_DAEMON_APP_ID, DLT_DAEMON_CTX_ID,
4379 : daemon_local->flags.vflag);
4380 5 : dlt_vlog(LOG_DEBUG, "%s%s", local_str, "\n");
4381 :
4382 5 : return 0;
4383 : }
4384 :
4385 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
4386 :
4387 : static DltReturnValue dlt_daemon_output_internal_msg(
4388 : const DltLogLevelType loglevel, const char *const text, void* const params) {
4389 : struct DltTraceLoadLogParams* log_params = (struct DltTraceLoadLogParams*)params;
4390 : return dlt_daemon_log_internal(
4391 : log_params->daemon, log_params->daemon_local, (char *)text, loglevel,
4392 : log_params->app_id, DLT_TRACE_LOAD_CONTEXT_ID, log_params->verbose);
4393 : }
4394 : #endif
4395 :
4396 :
4397 : /**
4398 : \}
4399 : */
|