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