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