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_user.c
26 : */
27 :
28 : #include <stdlib.h> /* for getenv(), free(), atexit() */
29 : #include <string.h> /* for strcmp(), strncmp(), strlen(), memset(), memcpy() */
30 : #include <signal.h> /* for signal(), SIGPIPE, SIG_IGN */
31 :
32 : #if !defined (__WIN32__)
33 : # include <syslog.h> /* for LOG_... */
34 : # include <semaphore.h>
35 : # include <pthread.h> /* POSIX Threads */
36 : #endif
37 :
38 : #include <sys/time.h>
39 : #include <math.h>
40 :
41 : #include <sys/stat.h>
42 : #include <fcntl.h>
43 : #include <errno.h>
44 :
45 : #include <sys/uio.h> /* writev() */
46 : #include <poll.h>
47 :
48 : #include <limits.h>
49 : #ifdef linux
50 : # include <sys/prctl.h> /* for PR_SET_NAME */
51 : #endif
52 :
53 : #include <sys/types.h> /* needed for getpid() */
54 : #include <unistd.h>
55 :
56 : #include <stdbool.h>
57 :
58 : #include <stdatomic.h>
59 : #include <stdint.h>
60 :
61 : #if defined DLT_LIB_USE_UNIX_SOCKET_IPC || defined DLT_LIB_USE_VSOCK_IPC
62 : # include <sys/socket.h>
63 : #endif
64 :
65 : #ifdef DLT_LIB_USE_UNIX_SOCKET_IPC
66 : # include <sys/un.h>
67 : #endif
68 : #ifdef DLT_LIB_USE_VSOCK_IPC
69 : # ifdef linux
70 : # include <linux/vm_sockets.h>
71 : # endif
72 : # ifdef __QNX__
73 : # include <vm_sockets.h>
74 : # endif
75 : #endif
76 :
77 : #include "dlt_user.h"
78 : #include "dlt_common.h"
79 : #include "dlt_log.h"
80 : #include "dlt_user_shared.h"
81 : #include "dlt_user_shared_cfg.h"
82 : #include "dlt_user_cfg.h"
83 :
84 : #ifdef DLT_FATAL_LOG_RESET_ENABLE
85 : # define DLT_LOG_FATAL_RESET_TRAP(LOGLEVEL) \
86 : do { \
87 : if (LOGLEVEL == DLT_LOG_FATAL) { \
88 : int *p = NULL; \
89 : *p = 0; \
90 : } \
91 : } while (false)
92 : #else /* DLT_FATAL_LOG_RESET_ENABLE */
93 : # define DLT_LOG_FATAL_RESET_TRAP(LOGLEVEL)
94 : #endif /* DLT_FATAL_LOG_RESET_ENABLE */
95 :
96 :
97 : enum InitState {
98 : INIT_UNITIALIZED,
99 : INIT_IN_PROGRESS,
100 : INIT_ERROR,
101 : INIT_DONE
102 : };
103 :
104 : static DltUser dlt_user;
105 : static _Atomic enum InitState dlt_user_init_state = INIT_UNITIALIZED;
106 : #define DLT_USER_INITIALIZED (dlt_user_init_state == INIT_DONE)
107 : #define DLT_USER_INIT_ERROR (dlt_user_init_state == INIT_ERROR)
108 : #define DLT_USER_INITIALIZED_NOT_FREEING (DLT_USER_INITIALIZED && (dlt_user_freeing == 0))
109 :
110 : static _Atomic int dlt_user_freeing = 0;
111 : static bool dlt_user_file_reach_max = false;
112 :
113 : #ifdef DLT_LIB_USE_FIFO_IPC
114 : static char dlt_user_dir[DLT_PATH_MAX];
115 : static char dlt_daemon_fifo[DLT_PATH_MAX];
116 : #endif
117 :
118 : static pthread_mutex_t dlt_mutex;
119 : static pthread_mutexattr_t dlt_mutex_attr;
120 :
121 71238 : void dlt_mutex_lock(void)
122 : {
123 71238 : pthread_mutex_lock(&dlt_mutex);
124 71238 : }
125 :
126 116272 : void dlt_mutex_free(void)
127 : {
128 116272 : pthread_mutex_unlock(&dlt_mutex);
129 116272 : }
130 :
131 : static pthread_t dlt_housekeeperthread_handle;
132 : pthread_mutex_t dlt_housekeeper_running_mutex = PTHREAD_MUTEX_INITIALIZER;
133 : pthread_cond_t dlt_housekeeper_running_cond;
134 :
135 : /* calling dlt_user_atexit_handler() second time fails with error message */
136 : static int atexit_registered = 0;
137 :
138 : /* used to disallow DLT usage in fork() child */
139 : static int g_dlt_is_child = 0;
140 :
141 : /* String truncate message */
142 : static const char STR_TRUNCATED_MESSAGE[] = "... <<Message truncated, too long>>";
143 :
144 : /* Enum for type of string */
145 : enum StringType
146 : {
147 : ASCII_STRING = 0,
148 : UTF8_STRING = 1
149 : };
150 :
151 : /* Data type holding "Variable Info" (VARI) properties
152 : * Some of the supported data types (eg. bool, string, raw) have only "name", but not "unit".
153 : */
154 : typedef struct VarInfo
155 : {
156 : const char *name; // the "name" attribute (can be NULL)
157 : const char *unit; // the "unit" attribute (can be NULL)
158 : bool with_unit; // true if the "unit" field is to be considered
159 : } VarInfo;
160 :
161 : #define DLT_UNUSED(x) (void)(x)
162 :
163 : /* Network trace */
164 : #ifdef DLT_NETWORK_TRACE_ENABLE
165 : #define DLT_USER_SEGMENTED_THREAD (1<<2)
166 :
167 : /* Segmented Network Trace */
168 : #define DLT_MAX_TRACE_SEGMENT_SIZE 1024
169 : #define DLT_MESSAGE_QUEUE_NAME "/dlt_message_queue"
170 : #define DLT_DELAYED_RESEND_INDICATOR_PATTERN 0xFFFF
171 :
172 : /* Mutex to wait on while message queue is not initialized */
173 : pthread_mutex_t mq_mutex = PTHREAD_MUTEX_INITIALIZER;
174 : pthread_cond_t mq_init_condition;
175 : #endif /* DLT_NETWORK_TRACE_ENABLE */
176 :
177 45034 : void dlt_lock_mutex(pthread_mutex_t *mutex)
178 : {
179 45034 : int32_t lock_mutex_result = pthread_mutex_lock(mutex);
180 :
181 45034 : if (lock_mutex_result != 0)
182 0 : dlt_vlog(LOG_ERR,
183 : "Mutex lock failed unexpected pid=%i with result %i!\n",
184 : getpid(), lock_mutex_result);
185 45034 : }
186 :
187 67550 : void dlt_unlock_mutex(pthread_mutex_t *mutex)
188 : {
189 67550 : pthread_mutex_unlock(mutex);
190 67551 : }
191 :
192 : /* Structure to pass data to segmented thread */
193 : typedef struct
194 : {
195 : DltContext *handle;
196 : uint32_t id;
197 : DltNetworkTraceType nw_trace_type;
198 : uint32_t header_len;
199 : void *header;
200 : uint32_t payload_len;
201 : void *payload;
202 : } s_segmented_data;
203 :
204 : /* Function prototypes for internally used functions */
205 : static void dlt_user_housekeeperthread_function(void *ptr);
206 : static void dlt_user_atexit_handler(void);
207 : static DltReturnValue dlt_user_log_init(DltContext *handle, DltContextData *log);
208 : static DltReturnValue dlt_user_log_send_log(DltContextData *log, int mtype, int *sent_size);
209 : static DltReturnValue dlt_user_log_send_register_application(void);
210 : static DltReturnValue dlt_user_log_send_unregister_application(void);
211 : static DltReturnValue dlt_user_log_send_register_context(DltContextData *log);
212 : static DltReturnValue dlt_user_log_send_unregister_context(DltContextData *log);
213 : static DltReturnValue dlt_send_app_ll_ts_limit(const char *apid,
214 : DltLogLevelType loglevel,
215 : DltTraceStatusType tracestatus);
216 : static DltReturnValue dlt_user_log_send_log_mode(DltUserLogMode mode);
217 : static DltReturnValue dlt_user_log_send_marker();
218 : static DltReturnValue dlt_user_print_msg(DltMessage *msg, DltContextData *log);
219 : static DltReturnValue dlt_user_log_check_user_message(void);
220 : static void dlt_user_log_reattach_to_daemon(void);
221 : static DltReturnValue dlt_user_log_send_overflow(void);
222 : static DltReturnValue dlt_user_log_out_error_handling(void *ptr1,
223 : size_t len1,
224 : void *ptr2,
225 : size_t len2,
226 : void *ptr3,
227 : size_t len3);
228 : static void dlt_user_cleanup_handler(void *arg);
229 : static int dlt_start_threads();
230 : static void dlt_stop_threads();
231 : static void dlt_fork_child_fork_handler();
232 : #ifdef DLT_NETWORK_TRACE_ENABLE
233 : static void dlt_user_trace_network_segmented_thread(void *unused);
234 : static void dlt_user_trace_network_segmented_thread_segmenter(s_segmented_data *data);
235 : #endif
236 :
237 : static DltReturnValue dlt_user_log_write_string_utils_attr(DltContextData *log, const char *text, const enum StringType type, const char *name, bool with_var_info);
238 : static DltReturnValue dlt_user_log_write_sized_string_utils_attr(DltContextData *log, const char *text, size_t length, const enum StringType type, const char *name, bool with_var_info);
239 :
240 :
241 : static DltReturnValue dlt_unregister_app_util(bool force_sending_messages);
242 :
243 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
244 : /* For trace load control feature */
245 : static DltReturnValue dlt_user_output_internal_msg(DltLogLevelType loglevel, const char *text, void* params);
246 : DltContext trace_load_context = {0};
247 : DltTraceLoadSettings* trace_load_settings = NULL;
248 : uint32_t trace_load_settings_count = 0;
249 : pthread_rwlock_t trace_load_rw_lock = PTHREAD_RWLOCK_INITIALIZER;
250 : #endif
251 :
252 7 : DltReturnValue dlt_user_check_library_version(const char *user_major_version, const char *user_minor_version)
253 : {
254 : char lib_major_version[DLT_USER_MAX_LIB_VERSION_LENGTH];
255 : char lib_minor_version[DLT_USER_MAX_LIB_VERSION_LENGTH];
256 :
257 7 : dlt_get_major_version(lib_major_version, DLT_USER_MAX_LIB_VERSION_LENGTH);
258 7 : dlt_get_minor_version(lib_minor_version, DLT_USER_MAX_LIB_VERSION_LENGTH);
259 :
260 7 : if ((strcmp(lib_major_version, user_major_version) != 0) || (strcmp(lib_minor_version, user_minor_version) != 0)) {
261 0 : dlt_vnlog(LOG_WARNING,
262 : DLT_USER_BUFFER_LENGTH,
263 : "DLT Library version check failed! Installed DLT library version is %s.%s - Application using DLT library version %s.%s\n",
264 : lib_major_version,
265 : lib_minor_version,
266 : user_major_version,
267 : user_minor_version);
268 :
269 0 : return DLT_RETURN_ERROR;
270 : }
271 :
272 : return DLT_RETURN_OK;
273 : }
274 :
275 : #if defined DLT_LIB_USE_UNIX_SOCKET_IPC || defined DLT_LIB_USE_VSOCK_IPC
276 : static DltReturnValue dlt_socket_set_nonblock_and_linger(int sockfd)
277 : {
278 : int status;
279 : struct linger l_opt;
280 :
281 : status = fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);
282 : if (status == -1) {
283 : dlt_log(LOG_INFO, "Socket cannot be changed to NON BLOCK\n");
284 : return DLT_RETURN_ERROR;
285 : }
286 :
287 : l_opt.l_onoff = 1;
288 : l_opt.l_linger = 10;
289 :
290 : if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &l_opt, sizeof l_opt) < 0)
291 : dlt_log(LOG_WARNING, "Failed to set socket linger option\n");
292 :
293 : return DLT_RETURN_OK;
294 : }
295 : #endif
296 :
297 : #ifdef DLT_LIB_USE_UNIX_SOCKET_IPC
298 : static DltReturnValue dlt_initialize_socket_connection(void)
299 : {
300 : struct sockaddr_un remote;
301 : char dltSockBaseDir[DLT_IPC_PATH_MAX];
302 :
303 : dlt_mutex_lock();
304 : int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
305 :
306 : if (sockfd == DLT_FD_INIT) {
307 : dlt_log(LOG_CRIT, "Failed to create socket\n");
308 : dlt_mutex_free();
309 : return DLT_RETURN_ERROR;
310 : }
311 :
312 : if (dlt_socket_set_nonblock_and_linger(sockfd) != DLT_RETURN_OK) {
313 : close(sockfd);
314 : dlt_mutex_free();
315 : return DLT_RETURN_ERROR;
316 : }
317 :
318 : remote.sun_family = AF_UNIX;
319 : snprintf(dltSockBaseDir, DLT_IPC_PATH_MAX, "%s/dlt", DLT_USER_IPC_PATH);
320 : strncpy(remote.sun_path, dltSockBaseDir, sizeof(remote.sun_path));
321 :
322 : if (strlen(DLT_USER_IPC_PATH) > DLT_IPC_PATH_MAX)
323 : dlt_vlog(LOG_INFO,
324 : "Provided path too long...trimming it to path[%s]\n",
325 : dltSockBaseDir);
326 :
327 : if (connect(sockfd, (struct sockaddr *)&remote, sizeof(remote)) == -1) {
328 : if (dlt_user.connection_state != DLT_USER_RETRY_CONNECT) {
329 : dlt_vlog(LOG_INFO,
330 : "Socket %s cannot be opened (errno=%d). Retrying later...\n",
331 : dltSockBaseDir, errno);
332 : dlt_user.connection_state = DLT_USER_RETRY_CONNECT;
333 : }
334 :
335 : close(sockfd);
336 : dlt_user.dlt_log_handle = -1;
337 : }
338 : else {
339 : dlt_user.dlt_log_handle = sockfd;
340 : dlt_user.connection_state = DLT_USER_CONNECTED;
341 :
342 : if (dlt_receiver_init(&(dlt_user.receiver),
343 : sockfd,
344 : DLT_RECEIVE_SOCKET,
345 : DLT_USER_RCVBUF_MAX_SIZE) == DLT_RETURN_ERROR) {
346 : dlt_user_init_state = INIT_UNITIALIZED;
347 : close(sockfd);
348 : dlt_mutex_free();
349 : return DLT_RETURN_ERROR;
350 : }
351 : }
352 :
353 : dlt_mutex_free();
354 : return DLT_RETURN_OK;
355 : }
356 : #elif defined DLT_LIB_USE_VSOCK_IPC
357 : static DltReturnValue dlt_initialize_vsock_connection()
358 : {
359 : struct sockaddr_vm remote;
360 :
361 : dlt_mutex_lock();
362 : int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
363 :
364 : if (sockfd == DLT_FD_INIT) {
365 : dlt_log(LOG_CRIT, "Failed to create VSOCK socket\n");
366 : dlt_mutex_free();
367 : return DLT_RETURN_ERROR;
368 : }
369 :
370 : memset(&remote, 0, sizeof(remote));
371 : remote.svm_family = AF_VSOCK;
372 : remote.svm_port = DLT_VSOCK_PORT;
373 : remote.svm_cid = VMADDR_CID_HOST;
374 :
375 : if (connect(sockfd, (struct sockaddr *)&remote, sizeof(remote)) == -1) {
376 : if (dlt_user.connection_state != DLT_USER_RETRY_CONNECT) {
377 : dlt_vlog(LOG_INFO, "VSOCK socket cannot be opened. Retrying later...\n");
378 : dlt_user.connection_state = DLT_USER_RETRY_CONNECT;
379 : }
380 :
381 : close(sockfd);
382 : dlt_user.dlt_log_handle = -1;
383 : }
384 : else {
385 : /* Set to non-blocking after connect() to avoid EINPROGRESS. DltUserConntextionState
386 : needs "connecting" state if connect() should be non-blocking. */
387 : if (dlt_socket_set_nonblock_and_linger(sockfd) != DLT_RETURN_OK) {
388 : close(sockfd);
389 : dlt_mutex_free();
390 : return DLT_RETURN_ERROR;
391 : }
392 :
393 : dlt_user.dlt_log_handle = sockfd;
394 : dlt_user.connection_state = DLT_USER_CONNECTED;
395 :
396 : if (dlt_receiver_init(&(dlt_user.receiver),
397 : sockfd,
398 : DLT_RECEIVE_SOCKET,
399 : DLT_USER_RCVBUF_MAX_SIZE) == DLT_RETURN_ERROR) {
400 : dlt_user_init_state = INIT_UNITIALIZED;
401 : close(sockfd);
402 : dlt_mutex_free();
403 : return DLT_RETURN_ERROR;
404 : }
405 : }
406 :
407 : dlt_mutex_free();
408 : return DLT_RETURN_OK;
409 : }
410 : #else /* DLT_LIB_USE_FIFO_IPC */
411 22517 : static DltReturnValue dlt_initialize_fifo_connection(void)
412 : {
413 : char filename[DLT_PATH_MAX];
414 : int ret;
415 :
416 : snprintf(dlt_user_dir, DLT_PATH_MAX, "%s/dltpipes", dltFifoBaseDir);
417 : snprintf(dlt_daemon_fifo, DLT_PATH_MAX, "%s/dlt", dltFifoBaseDir);
418 22517 : ret = mkdir(dlt_user_dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH | S_ISVTX);
419 :
420 22517 : if ((ret == -1) && (errno != EEXIST)) {
421 0 : dlt_vnlog(LOG_ERR, DLT_USER_BUFFER_LENGTH, "FIFO user dir %s cannot be created!\n", dlt_user_dir);
422 0 : return DLT_RETURN_ERROR;
423 : }
424 :
425 : /* if dlt pipes directory is created by the application also chmod the directory */
426 22517 : if (ret == 0) {
427 : /* S_ISGID cannot be set by mkdir, let's reassign right bits */
428 1 : ret = chmod(dlt_user_dir,
429 : S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH | S_ISGID |
430 : S_ISVTX);
431 :
432 1 : if (ret == -1) {
433 0 : dlt_vnlog(LOG_ERR, DLT_USER_BUFFER_LENGTH, "FIFO user dir %s cannot be chmoded!\n", dlt_user_dir);
434 0 : return DLT_RETURN_ERROR;
435 : }
436 : }
437 :
438 : /* create and open DLT user FIFO */
439 22517 : snprintf(filename, DLT_PATH_MAX, "%s/dlt%d", dlt_user_dir, getpid());
440 :
441 : /* Try to delete existing pipe, ignore result of unlink */
442 22517 : unlink(filename);
443 :
444 22517 : ret = mkfifo(filename, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP);
445 :
446 22517 : if (ret == -1)
447 0 : dlt_vnlog(LOG_WARNING, DLT_USER_BUFFER_LENGTH, "Loging disabled, FIFO user %s cannot be created!\n", filename);
448 :
449 : /* S_IWGRP cannot be set by mkfifo (???), let's reassign right bits */
450 22517 : ret = chmod(filename, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP);
451 :
452 22517 : if (ret == -1) {
453 0 : dlt_vnlog(LOG_WARNING, DLT_USER_BUFFER_LENGTH, "FIFO user %s cannot be chmoded!\n", dlt_user_dir);
454 0 : return DLT_RETURN_ERROR;
455 : }
456 :
457 22517 : dlt_user.dlt_user_handle = open(filename, O_RDWR | O_NONBLOCK | O_CLOEXEC);
458 :
459 22517 : if (dlt_user.dlt_user_handle == DLT_FD_INIT) {
460 0 : dlt_vnlog(LOG_WARNING, DLT_USER_BUFFER_LENGTH, "Logging disabled, FIFO user %s cannot be opened!\n", filename);
461 0 : unlink(filename);
462 0 : return DLT_RETURN_OK;
463 : }
464 :
465 : /* open DLT output FIFO */
466 22517 : dlt_user.dlt_log_handle = open(dlt_daemon_fifo, O_WRONLY | O_NONBLOCK | O_CLOEXEC);
467 :
468 22517 : if (dlt_user.dlt_log_handle == -1)
469 : /* This is a normal usecase. It is OK that the daemon (and thus the FIFO /tmp/dlt)
470 : * starts later and some DLT users have already been started before.
471 : * Thus it is OK if the FIFO can't be opened. */
472 22510 : dlt_vnlog(LOG_INFO, DLT_USER_BUFFER_LENGTH, "FIFO %s cannot be opened. Retrying later...\n",
473 : dlt_daemon_fifo);
474 :
475 : return DLT_RETURN_OK;
476 : }
477 : #endif
478 :
479 59538791 : DltReturnValue dlt_init(void)
480 : {
481 : /* process is exiting. Do not allocate new resources. */
482 59538791 : if (dlt_user_freeing != 0) {
483 : #ifndef DLT_UNIT_TESTS
484 : dlt_vlog(LOG_INFO, "%s logging disabled, process is exiting\n", __func__);
485 : #endif
486 : /* return negative value, to stop the current log */
487 : return DLT_RETURN_LOGGING_DISABLED;
488 : }
489 :
490 : /* Compare dlt_user_init_state to INIT_UNITIALIZED. If equal it will be set to INIT_IN_PROGRESS.
491 : * Call returns DLT_RETURN_OK init state != INIT_UNITIALIZED
492 : * That way it's no problem, if two threads enter this function, because only the very first one will
493 : * pass fully. The other one will immediately return, because when it executes the atomic function
494 : * dlt_user_init_state won't be INIT_UNITIALIZED anymore.
495 : * This is not handled via a simple boolean to prevent issues with shutting down while the init is still running.
496 : * Furthermore, this makes sure we enter some function only when dlt_init is fully done.
497 : * */
498 : enum InitState expectedInitState = INIT_UNITIALIZED;
499 10919744 : if (!(atomic_compare_exchange_strong(&dlt_user_init_state, &expectedInitState, INIT_IN_PROGRESS))) {
500 : return DLT_RETURN_OK;
501 : }
502 :
503 : /* check environment variables */
504 22517 : dlt_check_envvar();
505 :
506 : /* Check logging mode and internal log file is opened or not*/
507 22517 : if (logging_mode == DLT_LOG_TO_FILE && logging_handle == NULL) {
508 0 : dlt_log_init(logging_mode);
509 : }
510 :
511 : /* Initialize common part of dlt_init()/dlt_init_file() */
512 22517 : if (dlt_init_common() == DLT_RETURN_ERROR) {
513 0 : dlt_user_init_state = INIT_ERROR;
514 0 : dlt_free();
515 0 : return DLT_RETURN_ERROR;
516 : }
517 :
518 22517 : dlt_user.dlt_is_file = 0;
519 22517 : dlt_user.filesize_max = UINT_MAX;
520 22517 : dlt_user_file_reach_max = false;
521 :
522 22517 : dlt_user.overflow = 0;
523 22517 : dlt_user.overflow_counter = 0;
524 : #ifdef DLT_SHM_ENABLE
525 : memset(&(dlt_user.dlt_shm), 0, sizeof(DltShm));
526 :
527 : /* init shared memory */
528 : if (dlt_shm_init_client(&(dlt_user.dlt_shm), dltShmName) < DLT_RETURN_OK)
529 : dlt_vnlog(LOG_WARNING, DLT_USER_BUFFER_LENGTH, "Logging disabled,"
530 : " Shared memory %s cannot be created!\n", dltShmName);
531 :
532 : #endif
533 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
534 : pthread_rwlock_wrlock(&trace_load_rw_lock);
535 : trace_load_settings = malloc(sizeof(DltTraceLoadSettings));
536 : if (trace_load_settings == NULL) {
537 : dlt_vlog(LOG_ERR, "Failed to allocate memory for trace load settings\n");
538 : dlt_user_init_state = INIT_DONE;
539 : pthread_rwlock_unlock(&trace_load_rw_lock);
540 : dlt_free();
541 : return DLT_RETURN_ERROR;
542 : }
543 : memset(trace_load_settings, 0, sizeof(DltTraceLoadSettings));
544 : trace_load_settings[0].soft_limit = DLT_TRACE_LOAD_CLIENT_SOFT_LIMIT_DEFAULT;
545 : trace_load_settings[0].hard_limit = DLT_TRACE_LOAD_CLIENT_HARD_LIMIT_DEFAULT;
546 : strncpy(trace_load_settings[0].apid, dlt_user.appID, DLT_ID_SIZE);
547 : trace_load_settings_count = 1;
548 : pthread_rwlock_unlock(&trace_load_rw_lock);
549 : #endif
550 : #ifdef DLT_LIB_USE_UNIX_SOCKET_IPC
551 :
552 : if (dlt_initialize_socket_connection() != DLT_RETURN_OK) {
553 : /* We could connect to the pipe, but not to the socket, which is normally */
554 : /* open before by the DLT daemon => bad failure => return error code */
555 : /* in case application is started before daemon, it is expected behaviour */
556 : dlt_user_init_state = INIT_ERROR;
557 : dlt_free();
558 : return DLT_RETURN_ERROR;
559 : }
560 :
561 : #elif defined DLT_LIB_USE_VSOCK_IPC
562 :
563 : if (dlt_initialize_vsock_connection() != DLT_RETURN_OK) {
564 : dlt_user_init_state = INIT_ERROR;
565 : dlt_free();
566 : return DLT_RETURN_ERROR;
567 : }
568 :
569 : #else /* DLT_LIB_USE_FIFO_IPC */
570 :
571 22517 : if (dlt_initialize_fifo_connection() != DLT_RETURN_OK) {
572 0 : dlt_user_init_state = INIT_ERROR;
573 0 : dlt_free();
574 0 : return DLT_RETURN_ERROR;
575 : }
576 :
577 22517 : if (dlt_receiver_init(&(dlt_user.receiver),
578 : dlt_user.dlt_user_handle,
579 : DLT_RECEIVE_FD,
580 : DLT_USER_RCVBUF_MAX_SIZE) == DLT_RETURN_ERROR) {
581 0 : dlt_user_init_state = INIT_ERROR;
582 0 : dlt_free();
583 0 : return DLT_RETURN_ERROR;
584 : }
585 :
586 : #endif
587 :
588 : #ifdef DLT_NETWORK_TRACE_ENABLE
589 : /* These will be lazy initialized only when needed */
590 22517 : dlt_user.dlt_segmented_queue_read_handle = -1;
591 22517 : dlt_user.dlt_segmented_queue_write_handle = -1;
592 :
593 22517 : pthread_cond_init(&mq_init_condition, NULL);
594 : #endif
595 :
596 22517 : if (dlt_start_threads() < 0) {
597 0 : dlt_user_init_state = INIT_ERROR;
598 0 : dlt_free();
599 0 : return DLT_RETURN_ERROR;
600 : }
601 :
602 : /* prepare for fork() call */
603 22517 : pthread_atfork(NULL, NULL, &dlt_fork_child_fork_handler);
604 :
605 22517 : atomic_store(&dlt_user_init_state, INIT_DONE);
606 :
607 22517 : return DLT_RETURN_OK;
608 : }
609 :
610 0 : DltReturnValue dlt_get_appid(char *appid)
611 : {
612 0 : if (appid != NULL) {
613 : strncpy(appid, dlt_user.appID, 4);
614 0 : return DLT_RETURN_OK;
615 : } else {
616 0 : dlt_log(LOG_ERR, "Invalid parameter.\n");
617 0 : return DLT_RETURN_WRONG_PARAMETER;
618 : }
619 : }
620 :
621 0 : DltReturnValue dlt_init_file(const char *name)
622 : {
623 : /* check null pointer */
624 0 : if (!name)
625 : return DLT_RETURN_WRONG_PARAMETER;
626 :
627 : /* Compare dlt_user_init_state to INIT_UNITIALIZED. If equal it will be set to INIT_IN_PROGRESS.
628 : * Call returns DLT_RETURN_OK init state != INIT_UNITIALIZED
629 : * That way it's no problem, if two threads enter this function, because only the very first one will
630 : * pass fully. The other one will immediately return, because when it executes the atomic function
631 : * dlt_user_init_state won't be INIT_UNITIALIZED anymore.
632 : * This is not handled via a simple boolean to prevent issues with shutting down while the init is still running.
633 : * Furthermore, this makes sure we enter some function only when dlt_init is fully done.
634 : * */
635 : enum InitState expectedInitState = INIT_UNITIALIZED;
636 0 : if (!(atomic_compare_exchange_strong(&dlt_user_init_state, &expectedInitState, INIT_IN_PROGRESS)))
637 : return DLT_RETURN_OK;
638 :
639 : /* Initialize common part of dlt_init()/dlt_init_file() */
640 0 : if (dlt_init_common() == DLT_RETURN_ERROR) {
641 : expectedInitState = INIT_UNITIALIZED;
642 : return DLT_RETURN_ERROR;
643 : }
644 :
645 0 : dlt_user.dlt_is_file = 1;
646 :
647 : /* open DLT output file */
648 0 : dlt_user.dlt_log_handle = open(name, O_WRONLY | O_CREAT,
649 : S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* mode: wb */
650 :
651 0 : if (dlt_user.dlt_log_handle == -1) {
652 0 : dlt_vnlog(LOG_ERR, DLT_USER_BUFFER_LENGTH, "Log file %s cannot be opened!\n", name);
653 0 : dlt_user.dlt_is_file = 0;
654 0 : return DLT_RETURN_ERROR;
655 : }
656 0 : atomic_store(&dlt_user_init_state, INIT_DONE);
657 :
658 0 : return DLT_RETURN_OK;
659 : }
660 :
661 0 : DltReturnValue dlt_set_filesize_max(unsigned int filesize)
662 : {
663 0 : if (dlt_user.dlt_is_file == 0)
664 : {
665 0 : dlt_vlog(LOG_ERR, "%s: Library is not configured to log to file\n",
666 : __func__);
667 0 : return DLT_RETURN_ERROR;
668 : }
669 :
670 0 : if (filesize == 0) {
671 0 : dlt_user.filesize_max = UINT_MAX;
672 : }
673 : else {
674 0 : dlt_user.filesize_max = filesize;
675 : }
676 0 : dlt_vlog(LOG_DEBUG, "%s: Defined filesize_max is [%d]\n", __func__,
677 : dlt_user.filesize_max);
678 :
679 0 : return DLT_RETURN_OK;
680 : }
681 :
682 : #ifdef DLT_NETWORK_TRACE_ENABLE
683 0 : DltReturnValue dlt_init_message_queue(void)
684 : {
685 0 : dlt_lock_mutex(&mq_mutex);
686 :
687 0 : if ((dlt_user.dlt_segmented_queue_read_handle >= 0) &&
688 0 : (dlt_user.dlt_segmented_queue_write_handle >= 0)) {
689 : /* Already intialized */
690 0 : dlt_unlock_mutex(&mq_mutex);
691 0 : return DLT_RETURN_OK;
692 : }
693 :
694 : /* Generate per process name for queue */
695 : char queue_name[NAME_MAX];
696 0 : snprintf(queue_name, NAME_MAX, "%s.%d", DLT_MESSAGE_QUEUE_NAME, getpid());
697 :
698 : /* Maximum queue size is 10, limit to size of pointers */
699 : struct mq_attr mqatr;
700 0 : mqatr.mq_flags = 0;
701 0 : mqatr.mq_maxmsg = 10;
702 0 : mqatr.mq_msgsize = sizeof(s_segmented_data *);
703 0 : mqatr.mq_curmsgs = 0;
704 :
705 : /**
706 : * Create the message queue. It must be newly created
707 : * if old one was left by a crashing process.
708 : * */
709 0 : dlt_user.dlt_segmented_queue_read_handle = mq_open(queue_name, O_CREAT | O_RDONLY | O_EXCL,
710 : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
711 : &mqatr);
712 :
713 0 : if (dlt_user.dlt_segmented_queue_read_handle < 0) {
714 0 : if (errno == EEXIST) {
715 0 : dlt_log(LOG_WARNING, "Old message queue exists, trying to delete.\n");
716 :
717 0 : if (mq_unlink(queue_name) < 0)
718 0 : dlt_vnlog(LOG_CRIT, 256, "Could not delete existing message queue!: %s \n", strerror(errno));
719 : else /* Retry */
720 :
721 0 : dlt_user.dlt_segmented_queue_read_handle = mq_open(queue_name,
722 : O_CREAT | O_RDONLY | O_EXCL,
723 : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
724 : &mqatr);
725 : }
726 :
727 0 : if (dlt_user.dlt_segmented_queue_read_handle < 0) {
728 0 : dlt_vnlog(LOG_CRIT, 256, "Can't create message queue read handle!: %s \n", strerror(errno));
729 0 : dlt_unlock_mutex(&mq_mutex);
730 0 : return DLT_RETURN_ERROR;
731 : }
732 : }
733 :
734 0 : dlt_user.dlt_segmented_queue_write_handle = mq_open(queue_name, O_WRONLY | O_NONBLOCK);
735 :
736 0 : if (dlt_user.dlt_segmented_queue_write_handle < 0) {
737 :
738 0 : dlt_vnlog(LOG_CRIT, 256, "Can't open message queue write handle!: %s \n", strerror(errno));
739 0 : dlt_unlock_mutex(&mq_mutex);
740 0 : return DLT_RETURN_ERROR;
741 : }
742 :
743 0 : pthread_cond_signal(&mq_init_condition);
744 0 : dlt_unlock_mutex(&mq_mutex);
745 0 : return DLT_RETURN_OK;
746 : }
747 : #endif /* DLT_NETWORK_TRACE_ENABLE */
748 :
749 : /* Return true if verbose mode is to be used for this DltContextData */
750 : static inline bool is_verbose_mode(int8_t dltuser_verbose_mode, const DltContextData* log)
751 : {
752 11776 : return (dltuser_verbose_mode == 1) || (log != NULL && log->verbose_mode);
753 : }
754 :
755 22518 : DltReturnValue dlt_init_common(void)
756 : {
757 : char *env_local_print;
758 : char *env_initial_log_level;
759 : char *env_buffer_min;
760 : uint32_t buffer_min = DLT_USER_RINGBUFFER_MIN_SIZE;
761 : char *env_buffer_max;
762 : uint32_t buffer_max = DLT_USER_RINGBUFFER_MAX_SIZE;
763 : char *env_buffer_step;
764 : uint32_t buffer_step = DLT_USER_RINGBUFFER_STEP_SIZE;
765 : char *env_disable_extended_header_for_nonverbose;
766 : char *env_log_buffer_len;
767 : uint32_t buffer_max_configured = 0;
768 : uint32_t header_size = 0;
769 :
770 : // already initialized, nothing to do
771 22518 : if (DLT_USER_INITIALIZED) {
772 : return DLT_RETURN_OK;
773 : }
774 :
775 45034 : if ((pthread_mutexattr_init(&dlt_mutex_attr) != 0) ||
776 45034 : (pthread_mutexattr_settype(&dlt_mutex_attr, PTHREAD_MUTEX_RECURSIVE) != 0) ||
777 22517 : (pthread_mutex_init(&dlt_mutex, &dlt_mutex_attr) != 0)) {
778 0 : dlt_user_init_state = INIT_UNITIALIZED;
779 0 : return DLT_RETURN_ERROR;
780 : }
781 :
782 : /* set to unknown state of connected client */
783 22517 : dlt_user.log_state = -1;
784 :
785 : /* set pid cache to none until we need it */
786 22517 : dlt_user.local_pid = -1;
787 :
788 22517 : dlt_user.dlt_log_handle = -1;
789 22517 : dlt_user.dlt_user_handle = DLT_FD_INIT;
790 :
791 22517 : dlt_set_id(dlt_user.ecuID, DLT_USER_DEFAULT_ECU_ID);
792 22517 : dlt_set_id(dlt_user.appID, "");
793 :
794 22517 : dlt_user.application_description = NULL;
795 :
796 : /* Verbose mode is enabled by default */
797 22517 : dlt_user.verbose_mode = 1;
798 :
799 : /* header_size is used for resend buffer
800 : * so it won't include DltStorageHeader
801 : */
802 : header_size = sizeof(DltUserHeader) + sizeof(DltStandardHeader) +
803 : sizeof(DltStandardHeaderExtra);
804 :
805 : /* Use extended header for non verbose is enabled by default */
806 22517 : dlt_user.use_extended_header_for_non_verbose =
807 : DLT_USER_USE_EXTENDED_HEADER_FOR_NONVERBOSE;
808 :
809 : /* Use extended header for non verbose is modified as per environment variable */
810 : env_disable_extended_header_for_nonverbose =
811 22517 : getenv(DLT_USER_ENV_DISABLE_EXTENDED_HEADER_FOR_NONVERBOSE);
812 :
813 22517 : if (env_disable_extended_header_for_nonverbose) {
814 0 : if (strcmp(env_disable_extended_header_for_nonverbose, "1") == 0)
815 0 : dlt_user.use_extended_header_for_non_verbose =
816 : DLT_USER_NO_USE_EXTENDED_HEADER_FOR_NONVERBOSE;
817 : }
818 :
819 22517 : if (dlt_user.use_extended_header_for_non_verbose ==
820 : DLT_USER_USE_EXTENDED_HEADER_FOR_NONVERBOSE)
821 : header_size += (uint32_t) sizeof(DltExtendedHeader);
822 :
823 : /* With session id is enabled by default */
824 22517 : dlt_user.with_session_id = DLT_USER_WITH_SESSION_ID;
825 :
826 : /* With timestamp is enabled by default */
827 22517 : dlt_user.with_timestamp = DLT_USER_WITH_TIMESTAMP;
828 :
829 : /* With timestamp is enabled by default */
830 22517 : dlt_user.with_ecu_id = DLT_USER_WITH_ECU_ID;
831 :
832 : /* Local print is disabled by default */
833 22517 : dlt_user.enable_local_print = 0;
834 :
835 22517 : dlt_user.local_print_mode = DLT_PM_UNSET;
836 :
837 22517 : dlt_user.timeout_at_exit_handler = DLT_USER_ATEXIT_RESEND_BUFFER_EXIT_TIMEOUT;
838 :
839 22517 : env_local_print = getenv(DLT_USER_ENV_LOCAL_PRINT_MODE);
840 :
841 22517 : if (env_local_print) {
842 0 : if (strcmp(env_local_print, "AUTOMATIC") == 0)
843 0 : dlt_user.local_print_mode = DLT_PM_AUTOMATIC;
844 0 : else if (strcmp(env_local_print, "FORCE_ON") == 0)
845 0 : dlt_user.local_print_mode = DLT_PM_FORCE_ON;
846 0 : else if (strcmp(env_local_print, "FORCE_OFF") == 0)
847 0 : dlt_user.local_print_mode = DLT_PM_FORCE_OFF;
848 : }
849 :
850 22517 : env_initial_log_level = getenv("DLT_INITIAL_LOG_LEVEL");
851 :
852 22517 : if (env_initial_log_level != NULL) {
853 0 : if (dlt_env_extract_ll_set(&env_initial_log_level, &dlt_user.initial_ll_set) != 0)
854 0 : dlt_vlog(LOG_WARNING,
855 : "Unable to parse initial set of log-levels from environment! Env:\n%s\n",
856 : getenv("DLT_INITIAL_LOG_LEVEL"));
857 : }
858 :
859 : /* Initialize LogLevel/TraceStatus field */
860 22517 : dlt_mutex_lock();
861 22517 : dlt_user.dlt_ll_ts = NULL;
862 22517 : dlt_user.dlt_ll_ts_max_num_entries = 0;
863 22517 : dlt_user.dlt_ll_ts_num_entries = 0;
864 :
865 22517 : env_buffer_min = getenv(DLT_USER_ENV_BUFFER_MIN_SIZE);
866 22517 : env_buffer_max = getenv(DLT_USER_ENV_BUFFER_MAX_SIZE);
867 22517 : env_buffer_step = getenv(DLT_USER_ENV_BUFFER_STEP_SIZE);
868 :
869 22517 : if (env_buffer_min != NULL) {
870 0 : buffer_min = (uint32_t)strtol(env_buffer_min, NULL, 10);
871 :
872 0 : if ((errno == EINVAL) || (errno == ERANGE)) {
873 0 : dlt_vlog(LOG_ERR,
874 : "Wrong value specified for %s. Using default\n",
875 : DLT_USER_ENV_BUFFER_MIN_SIZE);
876 : buffer_min = DLT_USER_RINGBUFFER_MIN_SIZE;
877 : }
878 : }
879 :
880 22517 : if (env_buffer_max != NULL) {
881 0 : buffer_max = (uint32_t)strtol(env_buffer_max, NULL, 10);
882 :
883 0 : if ((errno == EINVAL) || (errno == ERANGE)) {
884 0 : dlt_vlog(LOG_ERR,
885 : "Wrong value specified for %s. Using default\n",
886 : DLT_USER_ENV_BUFFER_MAX_SIZE);
887 : buffer_max = DLT_USER_RINGBUFFER_MAX_SIZE;
888 : }
889 : }
890 :
891 22517 : if (env_buffer_step != NULL) {
892 0 : buffer_step = (uint32_t)strtol(env_buffer_step, NULL, 10);
893 :
894 0 : if ((errno == EINVAL) || (errno == ERANGE)) {
895 0 : dlt_vlog(LOG_ERR,
896 : "Wrong value specified for %s. Using default\n",
897 : DLT_USER_ENV_BUFFER_STEP_SIZE);
898 : buffer_step = DLT_USER_RINGBUFFER_STEP_SIZE;
899 : }
900 : }
901 :
902 : /* init log buffer size */
903 22517 : dlt_user.log_buf_len = DLT_USER_BUF_MAX_SIZE;
904 22517 : env_log_buffer_len = getenv(DLT_USER_ENV_LOG_MSG_BUF_LEN);
905 :
906 22517 : if (env_log_buffer_len != NULL) {
907 7 : buffer_max_configured = (uint32_t)strtol(env_log_buffer_len, NULL, 10);
908 :
909 7 : if (buffer_max_configured > DLT_LOG_MSG_BUF_MAX_SIZE) {
910 0 : dlt_user.log_buf_len = DLT_LOG_MSG_BUF_MAX_SIZE;
911 0 : dlt_vlog(LOG_WARNING,
912 : "Configured size exceeds maximum allowed size,restricting to max [65535 bytes]\n");
913 : }
914 : else {
915 7 : dlt_user.log_buf_len = (uint16_t) buffer_max_configured;
916 7 : dlt_vlog(LOG_INFO,
917 : "Configured buffer size to [%u bytes]\n",
918 : buffer_max_configured);
919 : }
920 : }
921 :
922 22517 : if (dlt_user.resend_buffer == NULL) {
923 22517 : dlt_user.resend_buffer = calloc(sizeof(unsigned char),
924 22517 : (dlt_user.log_buf_len + header_size));
925 :
926 22517 : if (dlt_user.resend_buffer == NULL) {
927 0 : dlt_user_init_state = INIT_UNITIALIZED;
928 0 : dlt_vlog(LOG_ERR, "cannot allocate memory for resend buffer\n");
929 0 : dlt_mutex_free();
930 0 : return DLT_RETURN_ERROR;
931 : }
932 : }
933 :
934 22517 : dlt_user.disable_injection_msg = 0;
935 22517 : if (getenv(DLT_USER_ENV_DISABLE_INJECTION_MSG)) {
936 0 : dlt_log(LOG_WARNING, "Injection message is disabled\n");
937 0 : dlt_user.disable_injection_msg = 1;
938 : }
939 :
940 22517 : if (dlt_buffer_init_dynamic(&(dlt_user.startup_buffer),
941 : buffer_min,
942 : buffer_max,
943 : buffer_step) == DLT_RETURN_ERROR) {
944 0 : dlt_user_init_state = INIT_UNITIALIZED;
945 0 : dlt_mutex_free();
946 0 : return DLT_RETURN_ERROR;
947 : }
948 :
949 22517 : dlt_mutex_free();
950 22517 : signal(SIGPIPE, SIG_IGN); /* ignore pipe signals */
951 :
952 22517 : if (atexit_registered == 0) {
953 8 : atexit_registered = 1;
954 8 : atexit(dlt_user_atexit_handler);
955 : }
956 :
957 : #ifdef DLT_TEST_ENABLE
958 : dlt_user.corrupt_user_header = 0;
959 : dlt_user.corrupt_message_size = 0;
960 : dlt_user.corrupt_message_size_size = 0;
961 : #endif
962 :
963 : return DLT_RETURN_OK;
964 : }
965 :
966 8 : void dlt_user_atexit_handler(void)
967 : {
968 : /* parent will do clean-up */
969 8 : if (g_dlt_is_child)
970 : return;
971 :
972 8 : if (!DLT_USER_INITIALIZED) {
973 1 : dlt_vlog(LOG_WARNING, "%s dlt_user_init_state=%i (expected INIT_DONE), dlt_user_freeing=%i\n", __FUNCTION__, dlt_user_init_state, dlt_user_freeing);
974 : /* close file */
975 1 : dlt_log_free();
976 1 : return;
977 : }
978 :
979 : /* Try to resend potential log messages in the user buffer */
980 7 : int count = dlt_user_atexit_blow_out_user_buffer();
981 :
982 7 : if (count != 0)
983 1 : dlt_vnlog(LOG_WARNING, 128, "Lost log messages in user buffer when exiting: %i\n", count);
984 :
985 : /* Unregister app (this also unregisters all contexts in daemon) */
986 : /* Ignore return value */
987 7 : dlt_unregister_app_util(false);
988 :
989 : /* Cleanup */
990 : /* Ignore return value */
991 7 : dlt_free();
992 :
993 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
994 : pthread_rwlock_destroy(&trace_load_rw_lock);
995 : #endif
996 : }
997 :
998 7 : int dlt_user_atexit_blow_out_user_buffer(void)
999 : {
1000 :
1001 : int count, ret;
1002 : struct timespec ts;
1003 :
1004 7 : uint32_t exitTime = dlt_uptime() + dlt_user.timeout_at_exit_handler;
1005 :
1006 : /* Send content of ringbuffer */
1007 7 : dlt_mutex_lock();
1008 7 : count = dlt_buffer_get_message_count(&(dlt_user.startup_buffer));
1009 7 : dlt_mutex_free();
1010 :
1011 7 : if (count > 0) {
1012 101 : while (dlt_uptime() < exitTime) {
1013 100 : if (dlt_user.dlt_log_handle == -1) {
1014 : /* Reattach to daemon if neccesary */
1015 100 : dlt_user_log_reattach_to_daemon();
1016 :
1017 100 : if ((dlt_user.dlt_log_handle != -1) && (dlt_user.overflow_counter)) {
1018 0 : if (dlt_user_log_send_overflow() == 0) {
1019 0 : dlt_vnlog(LOG_WARNING,
1020 : DLT_USER_BUFFER_LENGTH,
1021 : "%u messages discarded!\n",
1022 : dlt_user.overflow_counter);
1023 0 : dlt_user.overflow_counter = 0;
1024 : }
1025 : }
1026 : }
1027 :
1028 100 : if (dlt_user.dlt_log_handle != -1) {
1029 0 : ret = dlt_user_log_resend_buffer();
1030 :
1031 0 : if (ret == 0) {
1032 0 : dlt_mutex_lock();
1033 0 : count = dlt_buffer_get_message_count(&(dlt_user.startup_buffer));
1034 0 : dlt_mutex_free();
1035 :
1036 0 : return count;
1037 : }
1038 : }
1039 :
1040 100 : ts.tv_sec = 0;
1041 100 : ts.tv_nsec = DLT_USER_ATEXIT_RESEND_BUFFER_SLEEP;
1042 100 : nanosleep(&ts, NULL);
1043 : }
1044 :
1045 1 : dlt_mutex_lock();
1046 1 : count = dlt_buffer_get_message_count(&(dlt_user.startup_buffer));
1047 1 : dlt_mutex_free();
1048 : }
1049 :
1050 : return count;
1051 : }
1052 :
1053 : static void dlt_user_free_buffer(unsigned char **buffer)
1054 : {
1055 28527 : if (*buffer) {
1056 2 : free(*buffer);
1057 28516 : *buffer = NULL;
1058 : }
1059 : }
1060 :
1061 70915 : DltReturnValue dlt_free(void)
1062 : {
1063 : uint32_t i;
1064 : int ret = 0;
1065 : int expected = 0;
1066 : #ifdef DLT_LIB_USE_FIFO_IPC
1067 : char filename[DLT_PATH_MAX];
1068 : #endif
1069 :
1070 : /* library is freeing its resources. Avoid to allocate it in dlt_init() */
1071 70915 : if (!(atomic_compare_exchange_strong(&dlt_user_freeing, &expected, 1))) {
1072 : /* resources are already being freed. Do nothing and return. */
1073 : return DLT_RETURN_ERROR;
1074 : }
1075 :
1076 : // no need to free when not initialized and no error occurred.
1077 : // on error some resources might have been allocated, so free them.
1078 70915 : if (!DLT_USER_INITIALIZED && !DLT_USER_INIT_ERROR) {
1079 48398 : dlt_user_freeing = 0;
1080 48398 : return DLT_RETURN_ERROR;
1081 : }
1082 :
1083 22517 : dlt_mutex_lock();
1084 :
1085 22517 : dlt_stop_threads();
1086 :
1087 22517 : dlt_user_init_state = INIT_UNITIALIZED;
1088 :
1089 : #ifdef DLT_LIB_USE_FIFO_IPC
1090 :
1091 22517 : if (dlt_user.dlt_user_handle != DLT_FD_INIT) {
1092 22517 : close(dlt_user.dlt_user_handle);
1093 22517 : dlt_user.dlt_user_handle = DLT_FD_INIT;
1094 22517 : snprintf(filename, DLT_PATH_MAX, "%s/dlt%d", dlt_user_dir, getpid());
1095 22517 : unlink(filename);
1096 : }
1097 :
1098 : #endif
1099 :
1100 : #ifdef DLT_SHM_ENABLE
1101 : /* free shared memory */
1102 : dlt_shm_free_client(&dlt_user.dlt_shm);
1103 : #endif
1104 :
1105 22517 : if (dlt_user.dlt_log_handle != -1) {
1106 : /* close log file/output fifo to daemon */
1107 : #if defined DLT_LIB_USE_UNIX_SOCKET_IPC || defined DLT_LIB_USE_VSOCK_IPC
1108 : ret = shutdown(dlt_user.dlt_log_handle, SHUT_WR);
1109 :
1110 : if (ret < 0) {
1111 : dlt_vlog(LOG_WARNING, "%s: shutdown failed: %s\n", __func__, strerror(errno));
1112 : }
1113 : else {
1114 : ssize_t bytes_read = 0;
1115 : int prev_errno = 0;
1116 : struct pollfd nfd[1];
1117 : nfd[0].events = POLLIN;
1118 : nfd[0].fd = dlt_user.dlt_log_handle;
1119 :
1120 : while (1) {
1121 : ret = poll(nfd, 1, DLT_USER_RECEIVE_MDELAY);
1122 :
1123 : /* In case failure of polling or reaching timeout,
1124 : * continue to close socket anyway.
1125 : * */
1126 : if (ret < 0) {
1127 : dlt_vlog(LOG_WARNING, "[%s] Failed to poll with error [%s]\n",
1128 : __func__, strerror(errno));
1129 : break;
1130 : }
1131 : else if (ret == 0) {
1132 : dlt_vlog(LOG_DEBUG, "[%s] Polling timeout\n", __func__);
1133 : break;
1134 : }
1135 : else {
1136 : /* It could take some time to get the socket is shutdown
1137 : * So it means there could be some data available to read.
1138 : * Try to consume the data and poll the socket again.
1139 : * If read fails, time to close the socket then.
1140 : */
1141 : dlt_vlog(LOG_DEBUG, "[%s] polling returns [%d] with revent [0x%x]."
1142 : "There are something to read\n", __func__, ret, (unsigned int)nfd[0].revents);
1143 :
1144 : bytes_read = read(dlt_user.dlt_log_handle, dlt_user.resend_buffer, dlt_user.log_buf_len);
1145 : prev_errno = errno;
1146 :
1147 : if (bytes_read < 0) {
1148 : dlt_vlog(LOG_WARNING, "[%s] Failed to read with error [%s]\n",
1149 : __func__, strerror(prev_errno));
1150 :
1151 : if ((prev_errno == EAGAIN) || (EWOULDBLOCK != EAGAIN && prev_errno == EWOULDBLOCK))
1152 : continue;
1153 : else
1154 : break;
1155 : }
1156 : if (bytes_read >= 0) {
1157 : dlt_vlog(LOG_DEBUG, "%s - %d: %d bytes read from resend buffer\n",
1158 : __func__, __LINE__, (int)bytes_read);
1159 : if (!bytes_read)
1160 : break;
1161 : dlt_vlog(LOG_NOTICE, "[%s] data is still readable... [%zd] bytes read\n",
1162 : __func__, bytes_read);
1163 : }
1164 : }
1165 : }
1166 : }
1167 :
1168 : #endif
1169 6 : ret = close(dlt_user.dlt_log_handle);
1170 :
1171 6 : if (ret < 0)
1172 0 : dlt_vlog(LOG_WARNING, "%s: close failed: %s\n", __func__, strerror(errno));
1173 :
1174 6 : dlt_user.dlt_log_handle = -1;
1175 : }
1176 :
1177 22517 : dlt_receiver_free(&(dlt_user.receiver));
1178 :
1179 : dlt_user_free_buffer(&(dlt_user.resend_buffer));
1180 :
1181 22517 : dlt_buffer_free_dynamic(&(dlt_user.startup_buffer));
1182 :
1183 : /* Clear and free local stored application information */
1184 22517 : if (dlt_user.application_description != NULL)
1185 0 : free(dlt_user.application_description);
1186 22517 : dlt_user.application_description = NULL;
1187 :
1188 22517 : if (dlt_user.dlt_ll_ts) {
1189 10521 : for (i = 0; i < dlt_user.dlt_ll_ts_max_num_entries; i++) {
1190 10500 : if (dlt_user.dlt_ll_ts[i].context_description != NULL) {
1191 1 : free (dlt_user.dlt_ll_ts[i].context_description);
1192 1 : dlt_user.dlt_ll_ts[i].context_description = NULL;
1193 : }
1194 :
1195 10500 : if (dlt_user.dlt_ll_ts[i].log_level_ptr != NULL) {
1196 1 : free(dlt_user.dlt_ll_ts[i].log_level_ptr);
1197 1 : dlt_user.dlt_ll_ts[i].log_level_ptr = NULL;
1198 : }
1199 :
1200 10500 : if (dlt_user.dlt_ll_ts[i].trace_status_ptr != NULL) {
1201 1 : free(dlt_user.dlt_ll_ts[i].trace_status_ptr);
1202 1 : dlt_user.dlt_ll_ts[i].trace_status_ptr = NULL;
1203 : }
1204 :
1205 10500 : if (dlt_user.dlt_ll_ts[i].injection_table != NULL) {
1206 0 : free(dlt_user.dlt_ll_ts[i].injection_table);
1207 0 : dlt_user.dlt_ll_ts[i].injection_table = NULL;
1208 : }
1209 :
1210 10500 : dlt_user.dlt_ll_ts[i].nrcallbacks = 0;
1211 10500 : dlt_user.dlt_ll_ts[i].log_level_changed_callback = 0;
1212 : }
1213 :
1214 21 : free(dlt_user.dlt_ll_ts);
1215 21 : dlt_user.dlt_ll_ts = NULL;
1216 21 : dlt_user.dlt_ll_ts_max_num_entries = 0;
1217 21 : dlt_user.dlt_ll_ts_num_entries = 0;
1218 : }
1219 :
1220 22517 : dlt_env_free_ll_set(&dlt_user.initial_ll_set);
1221 :
1222 : #ifdef DLT_NETWORK_TRACE_ENABLE
1223 : char queue_name[NAME_MAX];
1224 22517 : snprintf(queue_name, NAME_MAX, "%s.%d", DLT_MESSAGE_QUEUE_NAME, getpid());
1225 :
1226 : /**
1227 : * Ignore errors from these, to not to spam user if dlt_free
1228 : * is accidentally called multiple times.
1229 : */
1230 22517 : if (dlt_user.dlt_segmented_queue_write_handle > 0)
1231 0 : mq_close(dlt_user.dlt_segmented_queue_write_handle);
1232 :
1233 22517 : if (dlt_user.dlt_segmented_queue_read_handle > 0)
1234 0 : mq_close(dlt_user.dlt_segmented_queue_read_handle);
1235 :
1236 22517 : if ((dlt_user.dlt_segmented_queue_write_handle > 0) ||
1237 22517 : (dlt_user.dlt_segmented_queue_read_handle > 0))
1238 0 : mq_unlink(queue_name);
1239 :
1240 22517 : dlt_user.dlt_segmented_queue_write_handle = DLT_FD_INIT;
1241 22517 : dlt_user.dlt_segmented_queue_read_handle = DLT_FD_INIT;
1242 :
1243 22517 : pthread_cond_destroy(&mq_init_condition);
1244 : #endif /* DLT_NETWORK_TRACE_ENABLE */
1245 :
1246 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
1247 : if (trace_load_settings != NULL) {
1248 : free(trace_load_settings);
1249 : trace_load_settings = NULL;
1250 : }
1251 : trace_load_settings_count = 0;
1252 : #endif
1253 22517 : dlt_mutex_free();
1254 22517 : pthread_mutex_destroy(&dlt_mutex);
1255 :
1256 : /* allow the user app to do dlt_init() again. */
1257 : /* The flag is unset only to keep almost the same behaviour as before, on EntryNav */
1258 : /* This should be removed for other projects (see documentation of dlt_free() */
1259 22517 : dlt_user_freeing = 0;
1260 :
1261 22517 : return DLT_RETURN_OK;
1262 : }
1263 :
1264 7 : DltReturnValue dlt_check_library_version(const char *user_major_version, const char *user_minor_version)
1265 : {
1266 7 : return dlt_user_check_library_version(user_major_version, user_minor_version);
1267 : }
1268 :
1269 176 : DltReturnValue dlt_register_app(const char *apid, const char *description)
1270 : {
1271 : DltReturnValue ret = DLT_RETURN_OK;
1272 :
1273 : /* forbid dlt usage in child after fork */
1274 176 : if (g_dlt_is_child)
1275 : return DLT_RETURN_ERROR;
1276 :
1277 176 : if (!DLT_USER_INITIALIZED) {
1278 8 : if (dlt_init() < 0) {
1279 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
1280 0 : return DLT_RETURN_ERROR;
1281 : }
1282 : }
1283 :
1284 176 : if ((apid == NULL) || (apid[0] == '\0'))
1285 : return DLT_RETURN_WRONG_PARAMETER;
1286 :
1287 : /* check if application already registered */
1288 : /* if yes do not register again */
1289 172 : if (apid[1] == 0) {
1290 2 : if (apid[0] == dlt_user.appID[0])
1291 : return DLT_RETURN_OK;
1292 : }
1293 170 : else if (apid[2] == 0)
1294 : {
1295 2 : if ((apid[0] == dlt_user.appID[0]) &&
1296 0 : (apid[1] == dlt_user.appID[1]))
1297 : return DLT_RETURN_OK;
1298 : }
1299 168 : else if (apid[3] == 0)
1300 : {
1301 2 : if ((apid[0] == dlt_user.appID[0]) &&
1302 0 : (apid[1] == dlt_user.appID[1]) &&
1303 0 : (apid[2] == dlt_user.appID[2]))
1304 : return DLT_RETURN_OK;
1305 : }
1306 166 : else if ((apid[0] == dlt_user.appID[0]) &&
1307 1 : (apid[1] == dlt_user.appID[1]) &&
1308 1 : (apid[2] == dlt_user.appID[2]) &&
1309 1 : (apid[3] == dlt_user.appID[3]))
1310 : {
1311 : return DLT_RETURN_OK;
1312 : }
1313 :
1314 171 : dlt_mutex_lock();
1315 :
1316 : /* Store locally application id and application description */
1317 171 : dlt_set_id(dlt_user.appID, apid);
1318 :
1319 171 : if (dlt_user.application_description != NULL)
1320 0 : free(dlt_user.application_description);
1321 :
1322 171 : dlt_user.application_description = NULL;
1323 :
1324 171 : if (description != NULL) {
1325 171 : size_t desc_len = strlen(description);
1326 171 : dlt_user.application_description = malloc(desc_len + 1);
1327 :
1328 171 : if (dlt_user.application_description) {
1329 : strncpy(dlt_user.application_description, description, desc_len + 1);
1330 : } else {
1331 0 : dlt_mutex_free();
1332 0 : return DLT_RETURN_ERROR;
1333 : }
1334 : }
1335 :
1336 171 : dlt_mutex_free();
1337 :
1338 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
1339 : pthread_rwlock_wrlock(&trace_load_rw_lock);
1340 : strncpy(trace_load_settings[0].apid, dlt_user.appID, DLT_ID_SIZE);
1341 : pthread_rwlock_unlock(&trace_load_rw_lock);
1342 : if (!trace_load_context.contextID[0])
1343 : {
1344 : // Register Special Context ID for output DLT library internal message
1345 : ret = dlt_register_context(&trace_load_context, DLT_TRACE_LOAD_CONTEXT_ID, "DLT user library internal context");
1346 : if (ret < DLT_RETURN_OK)
1347 : {
1348 : return ret;
1349 : }
1350 : }
1351 : #endif
1352 :
1353 171 : ret = dlt_user_log_send_register_application();
1354 :
1355 171 : if ((ret == DLT_RETURN_OK) && (dlt_user.dlt_log_handle != -1))
1356 7 : ret = dlt_user_log_resend_buffer();
1357 :
1358 : return ret;
1359 : }
1360 :
1361 203 : DltReturnValue dlt_register_context(DltContext *handle, const char *contextid, const char *description)
1362 : {
1363 : /* check nullpointer */
1364 203 : if (handle == NULL)
1365 : return DLT_RETURN_WRONG_PARAMETER;
1366 :
1367 : /* forbid dlt usage in child after fork */
1368 197 : if (g_dlt_is_child)
1369 : return DLT_RETURN_ERROR;
1370 :
1371 197 : if (!DLT_USER_INITIALIZED) {
1372 0 : if (dlt_init() < 0) {
1373 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
1374 0 : return DLT_RETURN_ERROR;
1375 : }
1376 : }
1377 :
1378 197 : if ((contextid == NULL) || (contextid[0] == '\0'))
1379 : return DLT_RETURN_WRONG_PARAMETER;
1380 :
1381 189 : return dlt_register_context_ll_ts(handle,
1382 : contextid,
1383 : description,
1384 : DLT_USER_LOG_LEVEL_NOT_SET,
1385 : DLT_USER_TRACE_STATUS_NOT_SET);
1386 : }
1387 :
1388 216 : DltReturnValue dlt_register_context_ll_ts_llccb(DltContext *handle,
1389 : const char *contextid,
1390 : const char *description,
1391 : int loglevel,
1392 : int tracestatus,
1393 : void (*dlt_log_level_changed_callback)(char context_id[DLT_ID_SIZE],
1394 : uint8_t log_level,
1395 : uint8_t trace_status))
1396 : {
1397 : DltContextData log;
1398 : uint32_t i;
1399 : int envLogLevel = DLT_USER_LOG_LEVEL_NOT_SET;
1400 :
1401 : /*check nullpointer */
1402 216 : if ((handle == NULL) || (contextid == NULL) || (contextid[0] == '\0'))
1403 : return DLT_RETURN_WRONG_PARAMETER;
1404 :
1405 : /* forbid dlt usage in child after fork */
1406 209 : if (g_dlt_is_child)
1407 : return DLT_RETURN_ERROR;
1408 :
1409 209 : if ((loglevel < DLT_USER_LOG_LEVEL_NOT_SET) || (loglevel >= DLT_LOG_MAX)) {
1410 2 : dlt_vlog(LOG_ERR, "Loglevel %d is outside valid range", loglevel);
1411 2 : return DLT_RETURN_WRONG_PARAMETER;
1412 : }
1413 :
1414 207 : if ((tracestatus < DLT_USER_TRACE_STATUS_NOT_SET) || (tracestatus >= DLT_TRACE_STATUS_MAX)) {
1415 2 : dlt_vlog(LOG_ERR, "Tracestatus %d is outside valid range", tracestatus);
1416 2 : return DLT_RETURN_WRONG_PARAMETER;
1417 : }
1418 :
1419 205 : if (dlt_user_log_init(handle, &log) < DLT_RETURN_OK)
1420 : return DLT_RETURN_ERROR;
1421 :
1422 : /* Reset message counter */
1423 205 : handle->mcnt = 0;
1424 :
1425 : /* Store context id in log level/trace status field */
1426 :
1427 : /* Check if already registered, else register context */
1428 205 : dlt_mutex_lock();
1429 :
1430 : /* Check of double context registration removed */
1431 : /* Double registration is already checked by daemon */
1432 :
1433 : /* Allocate or expand context array */
1434 205 : if (dlt_user.dlt_ll_ts == NULL) {
1435 21 : dlt_user.dlt_ll_ts = (dlt_ll_ts_type *)malloc(sizeof(dlt_ll_ts_type) * DLT_USER_CONTEXT_ALLOC_SIZE);
1436 :
1437 21 : if (dlt_user.dlt_ll_ts == NULL) {
1438 0 : dlt_mutex_free();
1439 0 : return DLT_RETURN_ERROR;
1440 : }
1441 :
1442 21 : dlt_user.dlt_ll_ts_max_num_entries = DLT_USER_CONTEXT_ALLOC_SIZE;
1443 :
1444 : /* Initialize new entries */
1445 10521 : for (i = 0; i < dlt_user.dlt_ll_ts_max_num_entries; i++) {
1446 10500 : dlt_set_id(dlt_user.dlt_ll_ts[i].contextID, "");
1447 :
1448 : /* At startup, logging and tracing is locally enabled */
1449 : /* the correct log level/status is set after received from daemon */
1450 10500 : dlt_user.dlt_ll_ts[i].log_level = DLT_USER_INITIAL_LOG_LEVEL;
1451 10500 : dlt_user.dlt_ll_ts[i].trace_status = DLT_USER_INITIAL_TRACE_STATUS;
1452 :
1453 10500 : dlt_user.dlt_ll_ts[i].log_level_ptr = 0;
1454 10500 : dlt_user.dlt_ll_ts[i].trace_status_ptr = 0;
1455 :
1456 10500 : dlt_user.dlt_ll_ts[i].context_description = 0;
1457 :
1458 10500 : dlt_user.dlt_ll_ts[i].injection_table = 0;
1459 10500 : dlt_user.dlt_ll_ts[i].nrcallbacks = 0;
1460 10500 : dlt_user.dlt_ll_ts[i].log_level_changed_callback = 0;
1461 : }
1462 : }
1463 184 : else if ((dlt_user.dlt_ll_ts_num_entries % DLT_USER_CONTEXT_ALLOC_SIZE) == 0)
1464 : {
1465 : /* allocate memory in steps of DLT_USER_CONTEXT_ALLOC_SIZE, e.g. 500 */
1466 : dlt_ll_ts_type *old_ll_ts;
1467 : uint32_t old_max_entries;
1468 :
1469 : old_ll_ts = dlt_user.dlt_ll_ts;
1470 0 : old_max_entries = dlt_user.dlt_ll_ts_max_num_entries;
1471 :
1472 0 : dlt_user.dlt_ll_ts_max_num_entries = ((dlt_user.dlt_ll_ts_num_entries
1473 0 : / DLT_USER_CONTEXT_ALLOC_SIZE) + 1)
1474 0 : * DLT_USER_CONTEXT_ALLOC_SIZE;
1475 0 : dlt_user.dlt_ll_ts = (dlt_ll_ts_type *)malloc(sizeof(dlt_ll_ts_type) *
1476 0 : dlt_user.dlt_ll_ts_max_num_entries);
1477 :
1478 0 : if (dlt_user.dlt_ll_ts == NULL) {
1479 0 : dlt_user.dlt_ll_ts = old_ll_ts;
1480 0 : dlt_user.dlt_ll_ts_max_num_entries = old_max_entries;
1481 0 : dlt_mutex_free();
1482 0 : return DLT_RETURN_ERROR;
1483 : }
1484 :
1485 0 : memcpy(dlt_user.dlt_ll_ts, old_ll_ts, sizeof(dlt_ll_ts_type) * dlt_user.dlt_ll_ts_num_entries);
1486 0 : free(old_ll_ts);
1487 :
1488 : /* Initialize new entries */
1489 0 : for (i = dlt_user.dlt_ll_ts_num_entries; i < dlt_user.dlt_ll_ts_max_num_entries; i++) {
1490 0 : dlt_set_id(dlt_user.dlt_ll_ts[i].contextID, "");
1491 :
1492 : /* At startup, logging and tracing is locally enabled */
1493 : /* the correct log level/status is set after received from daemon */
1494 0 : dlt_user.dlt_ll_ts[i].log_level = DLT_USER_INITIAL_LOG_LEVEL;
1495 0 : dlt_user.dlt_ll_ts[i].trace_status = DLT_USER_INITIAL_TRACE_STATUS;
1496 :
1497 0 : dlt_user.dlt_ll_ts[i].log_level_ptr = 0;
1498 0 : dlt_user.dlt_ll_ts[i].trace_status_ptr = 0;
1499 :
1500 0 : dlt_user.dlt_ll_ts[i].context_description = 0;
1501 :
1502 0 : dlt_user.dlt_ll_ts[i].injection_table = 0;
1503 0 : dlt_user.dlt_ll_ts[i].nrcallbacks = 0;
1504 0 : dlt_user.dlt_ll_ts[i].log_level_changed_callback = 0;
1505 : }
1506 : }
1507 :
1508 : /* New context entry to be initialized */
1509 : dlt_ll_ts_type *ctx_entry;
1510 205 : ctx_entry = &dlt_user.dlt_ll_ts[dlt_user.dlt_ll_ts_num_entries];
1511 :
1512 : /* Store locally context id and context description */
1513 205 : dlt_set_id(ctx_entry->contextID, contextid);
1514 :
1515 205 : if (ctx_entry->context_description != 0)
1516 0 : free(ctx_entry->context_description);
1517 :
1518 205 : ctx_entry->context_description = 0;
1519 :
1520 205 : if (description != 0) {
1521 205 : size_t desc_len = strlen(description);
1522 205 : ctx_entry->context_description = malloc(desc_len + 1);
1523 :
1524 205 : if (ctx_entry->context_description == 0) {
1525 0 : dlt_mutex_free();
1526 0 : return DLT_RETURN_ERROR;
1527 : }
1528 :
1529 : strncpy(ctx_entry->context_description, description, desc_len + 1);
1530 : }
1531 :
1532 205 : if (ctx_entry->log_level_ptr == 0) {
1533 205 : ctx_entry->log_level_ptr = malloc(sizeof(int8_t));
1534 :
1535 205 : if (ctx_entry->log_level_ptr == 0) {
1536 0 : dlt_mutex_free();
1537 0 : return DLT_RETURN_ERROR;
1538 : }
1539 : }
1540 :
1541 205 : if (ctx_entry->trace_status_ptr == 0) {
1542 205 : ctx_entry->trace_status_ptr = malloc(sizeof(int8_t));
1543 :
1544 205 : if (ctx_entry->trace_status_ptr == 0) {
1545 0 : dlt_mutex_free();
1546 0 : return DLT_RETURN_ERROR;
1547 : }
1548 : }
1549 :
1550 : /* check if the log level is set in the environement */
1551 205 : envLogLevel = dlt_env_adjust_ll_from_env(&dlt_user.initial_ll_set,
1552 : dlt_user.appID,
1553 : contextid,
1554 : DLT_USER_LOG_LEVEL_NOT_SET);
1555 :
1556 205 : if (envLogLevel != DLT_USER_LOG_LEVEL_NOT_SET) {
1557 0 : ctx_entry->log_level = (int8_t) envLogLevel;
1558 : loglevel = envLogLevel;
1559 : }
1560 205 : else if (loglevel != DLT_USER_LOG_LEVEL_NOT_SET)
1561 : {
1562 16 : ctx_entry->log_level = (int8_t) loglevel;
1563 : }
1564 :
1565 205 : if (tracestatus != DLT_USER_TRACE_STATUS_NOT_SET)
1566 15 : ctx_entry->trace_status = (int8_t) tracestatus;
1567 :
1568 : /* Prepare transfer struct */
1569 205 : dlt_set_id(handle->contextID, contextid);
1570 205 : handle->log_level_pos = (int32_t) dlt_user.dlt_ll_ts_num_entries;
1571 :
1572 205 : handle->log_level_ptr = ctx_entry->log_level_ptr;
1573 205 : handle->trace_status_ptr = ctx_entry->trace_status_ptr;
1574 :
1575 205 : log.context_description = ctx_entry->context_description;
1576 :
1577 205 : *(ctx_entry->log_level_ptr) = ctx_entry->log_level;
1578 205 : *(ctx_entry->trace_status_ptr) = ctx_entry->trace_status = (int8_t) tracestatus;
1579 205 : ctx_entry->log_level_changed_callback = dlt_log_level_changed_callback;
1580 :
1581 205 : log.log_level = loglevel;
1582 205 : log.trace_status = tracestatus;
1583 :
1584 205 : dlt_user.dlt_ll_ts_num_entries++;
1585 205 : dlt_mutex_free();
1586 :
1587 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
1588 : /* Compute runtime trace-load settings under the rwlock,
1589 : * then publish the pointer while holding the DLT mutex
1590 : * to avoid races with other threads that may reallocate
1591 : * the context array. This avoids holding both locks at
1592 : * the same time.
1593 : */
1594 : pthread_rwlock_rdlock(&trace_load_rw_lock);
1595 : DltTraceLoadSettings *settings = dlt_find_runtime_trace_load_settings(
1596 : trace_load_settings,
1597 : trace_load_settings_count,
1598 : dlt_user.appID,
1599 : ctx_entry->contextID);
1600 : pthread_rwlock_unlock(&trace_load_rw_lock);
1601 :
1602 : dlt_mutex_lock();
1603 : /* ctx_entry points into dlt_user.dlt_ll_ts which is protected by dlt_mutex */
1604 : ctx_entry->trace_load_settings = settings;
1605 : dlt_mutex_free();
1606 : #endif
1607 :
1608 205 : return dlt_user_log_send_register_context(&log);
1609 : }
1610 :
1611 216 : DltReturnValue dlt_register_context_ll_ts(DltContext *handle,
1612 : const char *contextid,
1613 : const char *description,
1614 : int loglevel,
1615 : int tracestatus)
1616 : {
1617 216 : return dlt_register_context_ll_ts_llccb(handle,
1618 : contextid,
1619 : description,
1620 : loglevel,
1621 : tracestatus,
1622 : NULL);
1623 :
1624 : }
1625 :
1626 0 : DltReturnValue dlt_register_context_llccb(DltContext *handle,
1627 : const char *contextid,
1628 : const char *description,
1629 : void (*dlt_log_level_changed_callback)(char context_id[DLT_ID_SIZE],
1630 : uint8_t log_level,
1631 : uint8_t trace_status))
1632 : {
1633 0 : if ((handle == NULL) || (contextid == NULL) || (contextid[0] == '\0'))
1634 : return DLT_RETURN_WRONG_PARAMETER;
1635 :
1636 : /* forbid dlt usage in child after fork */
1637 0 : if (g_dlt_is_child)
1638 : return DLT_RETURN_ERROR;
1639 :
1640 0 : if (!DLT_USER_INITIALIZED) {
1641 0 : if (dlt_init() < 0) {
1642 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
1643 0 : return DLT_RETURN_ERROR;
1644 : }
1645 : }
1646 :
1647 0 : return dlt_register_context_ll_ts_llccb(handle,
1648 : contextid,
1649 : description,
1650 : DLT_USER_LOG_LEVEL_NOT_SET,
1651 : DLT_USER_TRACE_STATUS_NOT_SET,
1652 : dlt_log_level_changed_callback);
1653 : }
1654 :
1655 : /* If force_sending_messages is set to true, do not clean appIDs when there are
1656 : * still data in startup_buffer. atexit_handler will free the appIDs */
1657 181 : DltReturnValue dlt_unregister_app_util(bool force_sending_messages)
1658 : {
1659 : DltReturnValue ret = DLT_RETURN_OK;
1660 :
1661 : /* forbid dlt usage in child after fork */
1662 181 : if (g_dlt_is_child) {
1663 : return DLT_RETURN_ERROR;
1664 : }
1665 :
1666 181 : if (!DLT_USER_INITIALIZED) {
1667 0 : dlt_vlog(LOG_WARNING, "%s dlt_user_init_state=%i (expected INIT_DONE), dlt_user_freeing=%i\n", __FUNCTION__, dlt_user_init_state, dlt_user_freeing);
1668 0 : return DLT_RETURN_ERROR;
1669 : }
1670 :
1671 : /* Inform daemon to unregister application and all of its contexts */
1672 181 : ret = dlt_user_log_send_unregister_application();
1673 :
1674 181 : dlt_mutex_lock();
1675 :
1676 181 : int count = dlt_buffer_get_message_count(&(dlt_user.startup_buffer));
1677 :
1678 181 : if (!force_sending_messages ||
1679 7 : (force_sending_messages && (count == 0))) {
1680 : /* Clear and free local stored application information */
1681 180 : dlt_set_id(dlt_user.appID, "");
1682 :
1683 180 : if (dlt_user.application_description != NULL) {
1684 171 : free(dlt_user.application_description);
1685 : }
1686 :
1687 180 : dlt_user.application_description = NULL;
1688 : }
1689 :
1690 181 : dlt_mutex_free();
1691 :
1692 181 : return ret;
1693 : }
1694 :
1695 167 : DltReturnValue dlt_unregister_app(void)
1696 : {
1697 167 : return dlt_unregister_app_util(false);
1698 : }
1699 :
1700 7 : DltReturnValue dlt_unregister_app_flush_buffered_logs(void)
1701 : {
1702 : DltReturnValue ret = DLT_RETURN_OK;
1703 :
1704 : /* forbid dlt usage in child after fork */
1705 7 : if (g_dlt_is_child)
1706 : return DLT_RETURN_ERROR;
1707 :
1708 7 : if (!DLT_USER_INITIALIZED) {
1709 0 : dlt_vlog(LOG_WARNING, "%s dlt_user_init_state=%i (expected INIT_DONE), dlt_user_freeing=%i\n", __FUNCTION__, dlt_user_init_state, dlt_user_freeing);
1710 0 : return DLT_RETURN_ERROR;
1711 : }
1712 :
1713 7 : if (dlt_user.dlt_log_handle != -1) {
1714 : do
1715 6 : ret = dlt_user_log_resend_buffer();
1716 6 : while ((ret != DLT_RETURN_OK) && (dlt_user.dlt_log_handle != -1));
1717 : }
1718 :
1719 7 : return dlt_unregister_app_util(true);
1720 : }
1721 :
1722 204 : DltReturnValue dlt_unregister_context(DltContext *handle)
1723 : {
1724 : DltContextData log;
1725 : DltReturnValue ret = DLT_RETURN_OK;
1726 :
1727 : /* forbid dlt usage in child after fork */
1728 204 : if (g_dlt_is_child) {
1729 : return DLT_RETURN_ERROR;
1730 : }
1731 :
1732 204 : log.handle = NULL;
1733 204 : log.context_description = NULL;
1734 :
1735 204 : if (dlt_user_log_init(handle, &log) <= DLT_RETURN_ERROR) {
1736 : return DLT_RETURN_ERROR;
1737 : }
1738 :
1739 204 : dlt_mutex_lock();
1740 204 : handle->log_level_ptr = NULL;
1741 204 : handle->trace_status_ptr = NULL;
1742 :
1743 204 : if (dlt_user.dlt_ll_ts != NULL) {
1744 : /* Clear and free local stored context information */
1745 204 : dlt_set_id(dlt_user.dlt_ll_ts[handle->log_level_pos].contextID, "");
1746 :
1747 204 : dlt_user.dlt_ll_ts[handle->log_level_pos].log_level = DLT_USER_INITIAL_LOG_LEVEL;
1748 204 : dlt_user.dlt_ll_ts[handle->log_level_pos].trace_status = DLT_USER_INITIAL_TRACE_STATUS;
1749 :
1750 204 : if (dlt_user.dlt_ll_ts[handle->log_level_pos].context_description != NULL) {
1751 204 : free(dlt_user.dlt_ll_ts[handle->log_level_pos].context_description);
1752 : }
1753 :
1754 204 : if (dlt_user.dlt_ll_ts[handle->log_level_pos].log_level_ptr != NULL) {
1755 204 : free(dlt_user.dlt_ll_ts[handle->log_level_pos].log_level_ptr);
1756 204 : dlt_user.dlt_ll_ts[handle->log_level_pos].log_level_ptr = NULL;
1757 : }
1758 :
1759 204 : if (dlt_user.dlt_ll_ts[handle->log_level_pos].trace_status_ptr != NULL) {
1760 204 : free(dlt_user.dlt_ll_ts[handle->log_level_pos].trace_status_ptr);
1761 204 : dlt_user.dlt_ll_ts[handle->log_level_pos].trace_status_ptr = NULL;
1762 : }
1763 :
1764 204 : dlt_user.dlt_ll_ts[handle->log_level_pos].context_description = NULL;
1765 :
1766 204 : if (dlt_user.dlt_ll_ts[handle->log_level_pos].injection_table != NULL) {
1767 0 : free(dlt_user.dlt_ll_ts[handle->log_level_pos].injection_table);
1768 0 : dlt_user.dlt_ll_ts[handle->log_level_pos].injection_table = NULL;
1769 : }
1770 :
1771 204 : dlt_user.dlt_ll_ts[handle->log_level_pos].nrcallbacks = 0;
1772 204 : dlt_user.dlt_ll_ts[handle->log_level_pos].log_level_changed_callback = 0;
1773 : }
1774 204 : dlt_mutex_free();
1775 :
1776 : /* Inform daemon to unregister context */
1777 204 : ret = dlt_user_log_send_unregister_context(&log);
1778 :
1779 204 : return ret;
1780 : }
1781 :
1782 0 : DltReturnValue dlt_set_application_ll_ts_limit(DltLogLevelType loglevel, DltTraceStatusType tracestatus)
1783 : {
1784 : uint32_t i;
1785 :
1786 : /* forbid dlt usage in child after fork */
1787 0 : if (g_dlt_is_child)
1788 : return DLT_RETURN_ERROR;
1789 :
1790 0 : if ((loglevel < DLT_USER_LOG_LEVEL_NOT_SET) || (loglevel >= DLT_LOG_MAX)) {
1791 0 : dlt_vlog(LOG_ERR, "Loglevel %d is outside valid range", loglevel);
1792 0 : return DLT_RETURN_WRONG_PARAMETER;
1793 : }
1794 :
1795 0 : if ((tracestatus < DLT_USER_TRACE_STATUS_NOT_SET) || (tracestatus >= DLT_TRACE_STATUS_MAX)) {
1796 0 : dlt_vlog(LOG_ERR, "Tracestatus %d is outside valid range", tracestatus);
1797 0 : return DLT_RETURN_WRONG_PARAMETER;
1798 : }
1799 :
1800 0 : if (!DLT_USER_INITIALIZED) {
1801 0 : if (dlt_init() < 0) {
1802 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
1803 0 : return DLT_RETURN_ERROR;
1804 : }
1805 : }
1806 :
1807 0 : dlt_mutex_lock();
1808 :
1809 0 : if (dlt_user.dlt_ll_ts == NULL) {
1810 0 : dlt_mutex_free();
1811 0 : return DLT_RETURN_ERROR;
1812 : }
1813 :
1814 : /* Update local structures */
1815 0 : for (i = 0; i < dlt_user.dlt_ll_ts_num_entries; i++) {
1816 0 : dlt_user.dlt_ll_ts[i].log_level = loglevel;
1817 0 : dlt_user.dlt_ll_ts[i].trace_status = tracestatus;
1818 :
1819 0 : if (dlt_user.dlt_ll_ts[i].log_level_ptr)
1820 0 : *(dlt_user.dlt_ll_ts[i].log_level_ptr) = loglevel;
1821 :
1822 0 : if (dlt_user.dlt_ll_ts[i].trace_status_ptr)
1823 0 : *(dlt_user.dlt_ll_ts[i].trace_status_ptr) = tracestatus;
1824 : }
1825 :
1826 0 : dlt_mutex_free();
1827 :
1828 : /* Inform DLT server about update */
1829 0 : return dlt_send_app_ll_ts_limit(dlt_user.appID, loglevel, tracestatus);
1830 : }
1831 :
1832 1 : int dlt_get_log_state()
1833 : {
1834 1 : return dlt_user.log_state;
1835 : }
1836 :
1837 4 : DltReturnValue dlt_set_log_mode(DltUserLogMode mode)
1838 : {
1839 : DLT_UNUSED(mode);
1840 :
1841 : /* forbid dlt usage in child after fork */
1842 4 : if (g_dlt_is_child)
1843 : return DLT_RETURN_ERROR;
1844 :
1845 4 : if ((mode < DLT_USER_MODE_UNDEFINED) || (mode >= DLT_USER_MODE_MAX)) {
1846 0 : dlt_vlog(LOG_ERR, "User log mode %d is outside valid range", mode);
1847 0 : return DLT_RETURN_WRONG_PARAMETER;
1848 : }
1849 :
1850 4 : if (!DLT_USER_INITIALIZED) {
1851 0 : if (dlt_init() < 0) {
1852 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
1853 0 : return DLT_RETURN_ERROR;
1854 : }
1855 : }
1856 :
1857 4 : return dlt_user_log_send_log_mode(mode);
1858 : }
1859 :
1860 0 : int dlt_set_resend_timeout_atexit(uint32_t timeout_in_milliseconds)
1861 : {
1862 : /* forbid dlt usage in child after fork */
1863 0 : if (g_dlt_is_child)
1864 : return DLT_RETURN_ERROR;
1865 :
1866 0 : if (DLT_USER_INITIALIZED == 0)
1867 0 : if (dlt_init() < 0)
1868 : return -1;
1869 :
1870 0 : dlt_user.timeout_at_exit_handler = timeout_in_milliseconds * 10;
1871 0 : return 0;
1872 : }
1873 :
1874 : /* ********************************************************************************************* */
1875 :
1876 6001 : DltReturnValue dlt_user_log_write_start_init(DltContext *handle,
1877 : DltContextData *log,
1878 : DltLogLevelType loglevel,
1879 : bool is_verbose)
1880 : {
1881 : DLT_LOG_FATAL_RESET_TRAP(loglevel);
1882 :
1883 : /* initialize values */
1884 6001 : if ((dlt_user_log_init(handle, log) < DLT_RETURN_OK) || (dlt_user.dlt_ll_ts == NULL))
1885 : return DLT_RETURN_ERROR;
1886 :
1887 6001 : log->args_num = 0;
1888 6001 : log->log_level = loglevel;
1889 6001 : log->size = 0;
1890 6001 : log->use_timestamp = DLT_AUTO_TIMESTAMP;
1891 6001 : log->verbose_mode = is_verbose;
1892 :
1893 6001 : return DLT_RETURN_TRUE;
1894 : }
1895 :
1896 : static DltReturnValue dlt_user_log_write_start_internal(DltContext *handle,
1897 : DltContextData *log,
1898 : DltLogLevelType loglevel,
1899 : uint32_t messageid,
1900 : bool is_verbose);
1901 :
1902 5926 : inline DltReturnValue dlt_user_log_write_start(DltContext *handle, DltContextData *log, DltLogLevelType loglevel)
1903 : {
1904 6036 : return dlt_user_log_write_start_internal(handle, log, loglevel, DLT_USER_DEFAULT_MSGID, true);
1905 : }
1906 :
1907 23 : DltReturnValue dlt_user_log_write_start_id(DltContext *handle,
1908 : DltContextData *log,
1909 : DltLogLevelType loglevel,
1910 : uint32_t messageid)
1911 : {
1912 23 : return dlt_user_log_write_start_internal(handle, log, loglevel, messageid, false);
1913 : }
1914 :
1915 6059 : DltReturnValue dlt_user_log_write_start_internal(DltContext *handle,
1916 : DltContextData *log,
1917 : DltLogLevelType loglevel,
1918 : uint32_t messageid,
1919 : bool is_verbose)
1920 : {
1921 : int ret = DLT_RETURN_TRUE;
1922 :
1923 : /* check nullpointer */
1924 6059 : if ((handle == NULL) || (log == NULL))
1925 : return DLT_RETURN_WRONG_PARAMETER;
1926 :
1927 : /* forbid dlt usage in child after fork */
1928 6053 : if (g_dlt_is_child)
1929 : return DLT_RETURN_ERROR;
1930 :
1931 : /* check log levels */
1932 6053 : ret = dlt_user_is_logLevel_enabled(handle, loglevel);
1933 :
1934 6053 : if (ret == DLT_RETURN_WRONG_PARAMETER) {
1935 : return DLT_RETURN_WRONG_PARAMETER;
1936 6040 : } else if (ret == DLT_RETURN_LOGGING_DISABLED) {
1937 39 : log->handle = NULL;
1938 39 : return DLT_RETURN_OK;
1939 : }
1940 :
1941 6001 : ret = dlt_user_log_write_start_init(handle, log, loglevel, is_verbose);
1942 6001 : if (ret == DLT_RETURN_TRUE) {
1943 : /* initialize values */
1944 6001 : if ((NULL != log->buffer))
1945 : {
1946 0 : free(log->buffer);
1947 0 : log->buffer = NULL;
1948 : }
1949 : else
1950 : {
1951 6001 : log->buffer = calloc(sizeof(unsigned char), dlt_user.log_buf_len);
1952 : }
1953 :
1954 6001 : if (log->buffer == NULL) {
1955 0 : dlt_vlog(LOG_ERR, "Cannot allocate buffer for DLT Log message\n");
1956 0 : return DLT_RETURN_ERROR;
1957 : }
1958 : else
1959 : {
1960 : /* In non-verbose mode, insert message id */
1961 12002 : if (!is_verbose_mode(dlt_user.verbose_mode, log)) {
1962 3 : if ((sizeof(uint32_t)) > dlt_user.log_buf_len)
1963 : return DLT_RETURN_USER_BUFFER_FULL;
1964 :
1965 : /* Write message id */
1966 : memcpy(log->buffer, &(messageid), sizeof(uint32_t));
1967 3 : log->size = sizeof(uint32_t);
1968 :
1969 : /* as the message id is part of each message in non-verbose mode,
1970 : * it doesn't increment the argument counter in extended header (if used) */
1971 : }
1972 : }
1973 : }
1974 :
1975 : return ret;
1976 : }
1977 :
1978 0 : DltReturnValue dlt_user_log_write_start_w_given_buffer(DltContext *handle,
1979 : DltContextData *log,
1980 : DltLogLevelType loglevel,
1981 : char *buffer,
1982 : size_t size,
1983 : int32_t args_num)
1984 : {
1985 : int ret = DLT_RETURN_TRUE;
1986 :
1987 : /* check nullpointer */
1988 0 : if ((handle == NULL) || (log == NULL) || (buffer == NULL))
1989 : return DLT_RETURN_WRONG_PARAMETER;
1990 :
1991 : /* discard unexpected parameters */
1992 0 : if ((size <= 0) || (size > dlt_user.log_buf_len) || (args_num <= 0))
1993 : return DLT_RETURN_WRONG_PARAMETER;
1994 :
1995 : /* forbid dlt usage in child after fork */
1996 0 : if (g_dlt_is_child)
1997 : return DLT_RETURN_ERROR;
1998 :
1999 : /* discard non-verbose mode */
2000 0 : if (dlt_user.verbose_mode == 0)
2001 : return DLT_RETURN_ERROR;
2002 :
2003 0 : ret = dlt_user_log_write_start_init(handle, log, loglevel, true);
2004 0 : if (ret == DLT_RETURN_TRUE) {
2005 0 : log->buffer = (unsigned char *)buffer;
2006 0 : log->size = size;
2007 0 : log->args_num = args_num;
2008 : }
2009 :
2010 : return ret;
2011 : }
2012 :
2013 6008 : DltReturnValue dlt_user_log_write_finish(DltContextData *log)
2014 : {
2015 : int ret = DLT_RETURN_ERROR;
2016 :
2017 6008 : if (log == NULL)
2018 : return DLT_RETURN_WRONG_PARAMETER;
2019 :
2020 6008 : ret = dlt_user_log_send_log(log, DLT_TYPE_LOG, NULL);
2021 :
2022 : dlt_user_free_buffer(&(log->buffer));
2023 :
2024 : return ret;
2025 : }
2026 :
2027 0 : DltReturnValue dlt_user_log_write_finish_w_given_buffer(DltContextData *log)
2028 : {
2029 : int ret = DLT_RETURN_ERROR;
2030 :
2031 0 : if (log == NULL)
2032 : return DLT_RETURN_WRONG_PARAMETER;
2033 :
2034 0 : ret = dlt_user_log_send_log(log, DLT_TYPE_LOG, NULL);
2035 :
2036 0 : return ret;
2037 : }
2038 :
2039 38 : static DltReturnValue dlt_user_log_write_raw_internal(DltContextData *log, const void *data, uint16_t length, DltFormatType type, const char *name, bool with_var_info)
2040 : {
2041 : /* check nullpointer */
2042 38 : if ((log == NULL) || ((data == NULL) && (length != 0)))
2043 : return DLT_RETURN_WRONG_PARAMETER;
2044 :
2045 : /* Have to cast type to signed type because some compilers assume that DltFormatType is unsigned and issue a warning */
2046 31 : if (((int16_t)type < DLT_FORMAT_DEFAULT) || (type >= DLT_FORMAT_MAX)) {
2047 0 : dlt_vlog(LOG_ERR, "Format type %u is outside valid range", type);
2048 0 : return DLT_RETURN_WRONG_PARAMETER;
2049 : }
2050 :
2051 31 : if (!DLT_USER_INITIALIZED) {
2052 0 : dlt_vlog(LOG_WARNING, "%s dlt_user_init_state=%i (expected INIT_DONE), dlt_user_freeing=%i\n", __FUNCTION__, dlt_user_init_state, dlt_user_freeing);
2053 0 : return DLT_RETURN_ERROR;
2054 : }
2055 :
2056 31 : const uint16_t name_size = (name != NULL) ? strlen(name)+1 : 0;
2057 :
2058 31 : size_t needed_size = length + sizeof(uint16_t);
2059 31 : if ((log->size + needed_size) > dlt_user.log_buf_len)
2060 : return DLT_RETURN_USER_BUFFER_FULL;
2061 :
2062 29 : if (is_verbose_mode(dlt_user.verbose_mode, log)) {
2063 29 : uint32_t type_info = DLT_TYPE_INFO_RAWD;
2064 :
2065 29 : needed_size += sizeof(uint32_t); // Type Info field
2066 29 : if (with_var_info) {
2067 6 : needed_size += sizeof(uint16_t); // length of name
2068 6 : needed_size += name_size; // the name itself
2069 :
2070 6 : type_info |= DLT_TYPE_INFO_VARI;
2071 : }
2072 29 : if ((log->size + needed_size) > dlt_user.log_buf_len)
2073 0 : return DLT_RETURN_USER_BUFFER_FULL;
2074 :
2075 : // Genivi extension: put formatting hints into the unused (for RAWD) TYLE + SCOD fields.
2076 : // The SCOD field holds the base (hex or bin); the TYLE field holds the column width (8bit..64bit).
2077 29 : if ((type >= DLT_FORMAT_HEX8) && (type <= DLT_FORMAT_HEX64)) {
2078 8 : type_info |= DLT_SCOD_HEX;
2079 8 : type_info += type;
2080 : }
2081 21 : else if ((type >= DLT_FORMAT_BIN8) && (type <= DLT_FORMAT_BIN16))
2082 : {
2083 4 : type_info |= DLT_SCOD_BIN;
2084 4 : type_info += type - DLT_FORMAT_BIN8 + 1;
2085 : }
2086 :
2087 29 : memcpy(log->buffer + log->size, &type_info, sizeof(uint32_t));
2088 29 : log->size += sizeof(uint32_t);
2089 : }
2090 :
2091 29 : memcpy(log->buffer + log->size, &length, sizeof(uint16_t));
2092 29 : log->size += sizeof(uint16_t);
2093 :
2094 29 : if (is_verbose_mode(dlt_user.verbose_mode, log)) {
2095 29 : if (with_var_info) {
2096 : // Write length of "name" attribute.
2097 : // We assume that the protocol allows zero-sized strings here (which this code will create
2098 : // when the input pointer is NULL).
2099 6 : memcpy(log->buffer + log->size, &name_size, sizeof(uint16_t));
2100 6 : log->size += sizeof(uint16_t);
2101 :
2102 : // Write name string itself.
2103 : // Must not use NULL as source pointer for memcpy. This check assures that.
2104 6 : if (name_size != 0) {
2105 4 : memcpy(log->buffer + log->size, name, name_size);
2106 4 : log->size += name_size;
2107 : }
2108 : }
2109 : }
2110 :
2111 29 : if (data != NULL) {
2112 27 : memcpy(log->buffer + log->size, data, length);
2113 27 : log->size += length;
2114 27 : log->args_num++;
2115 : }
2116 :
2117 : return DLT_RETURN_OK;
2118 : }
2119 :
2120 13 : DltReturnValue dlt_user_log_write_raw(DltContextData *log, void *data, uint16_t length)
2121 : {
2122 13 : return dlt_user_log_write_raw_internal(log, data, length, DLT_FORMAT_DEFAULT, NULL, false);
2123 : }
2124 :
2125 19 : DltReturnValue dlt_user_log_write_raw_formatted(DltContextData *log, void *data, uint16_t length, DltFormatType type)
2126 : {
2127 19 : return dlt_user_log_write_raw_internal(log, data, length, type, NULL, false);
2128 : }
2129 :
2130 3 : DltReturnValue dlt_user_log_write_raw_attr(DltContextData *log, const void *data, uint16_t length, const char *name)
2131 : {
2132 3 : return dlt_user_log_write_raw_internal(log, data, length, DLT_FORMAT_DEFAULT, name, true);
2133 : }
2134 :
2135 3 : DltReturnValue dlt_user_log_write_raw_formatted_attr(DltContextData *log, const void *data, uint16_t length, DltFormatType type, const char *name)
2136 : {
2137 3 : return dlt_user_log_write_raw_internal(log, data, length, type, name, true);
2138 : }
2139 :
2140 : // Generic implementation for all "simple" types, possibly with attributes
2141 11760 : static DltReturnValue dlt_user_log_write_generic_attr(DltContextData *log, const void *datap, size_t datalen, uint32_t type_info, const VarInfo *varinfo)
2142 : {
2143 11760 : if (log == NULL)
2144 : return DLT_RETURN_WRONG_PARAMETER;
2145 :
2146 11749 : if (!DLT_USER_INITIALIZED_NOT_FREEING) {
2147 0 : dlt_vlog(LOG_WARNING, "%s dlt_user_init_state=%i (expected INIT_DONE), dlt_user_freeing=%i\n", __FUNCTION__, dlt_user_init_state, dlt_user_freeing);
2148 0 : return DLT_RETURN_ERROR;
2149 : }
2150 :
2151 : size_t needed_size = datalen;
2152 11749 : if ((log->size + needed_size) > dlt_user.log_buf_len)
2153 : return DLT_RETURN_USER_BUFFER_FULL;
2154 :
2155 11747 : if (is_verbose_mode(dlt_user.verbose_mode, log)) {
2156 : bool with_var_info = (varinfo != NULL);
2157 :
2158 : uint16_t name_size;
2159 : uint16_t unit_size;
2160 :
2161 11745 : needed_size += sizeof(uint32_t); // Type Info field
2162 11745 : if (with_var_info) {
2163 89 : name_size = (varinfo->name != NULL) ? strlen(varinfo->name)+1 : 0;
2164 89 : unit_size = (varinfo->unit != NULL) ? strlen(varinfo->unit)+1 : 0;
2165 :
2166 89 : needed_size += sizeof(uint16_t); // length of name
2167 89 : needed_size += name_size; // the name itself
2168 89 : if (varinfo->with_unit) {
2169 86 : needed_size += sizeof(uint16_t); // length of unit
2170 86 : needed_size += unit_size; // the unit itself
2171 : }
2172 :
2173 89 : type_info |= DLT_TYPE_INFO_VARI;
2174 : }
2175 11745 : if ((log->size + needed_size) > dlt_user.log_buf_len)
2176 0 : return DLT_RETURN_USER_BUFFER_FULL;
2177 :
2178 11745 : memcpy(log->buffer + log->size, &type_info, sizeof(uint32_t));
2179 11745 : log->size += sizeof(uint32_t);
2180 :
2181 11745 : if (with_var_info) {
2182 : // Write lengths of name/unit strings
2183 : // We assume here that the protocol allows zero-sized strings here (which occur
2184 : // when the input pointers are NULL).
2185 89 : memcpy(log->buffer + log->size, &name_size, sizeof(uint16_t));
2186 89 : log->size += sizeof(uint16_t);
2187 89 : if (varinfo->with_unit) {
2188 86 : memcpy(log->buffer + log->size, &unit_size, sizeof(uint16_t));
2189 86 : log->size += sizeof(uint16_t);
2190 : }
2191 :
2192 : // Write name/unit strings themselves
2193 : // Must not use NULL as source pointer for memcpy.
2194 89 : if (name_size != 0) {
2195 64 : memcpy(log->buffer + log->size, varinfo->name, name_size);
2196 64 : log->size += name_size;
2197 : }
2198 89 : if (unit_size != 0) {
2199 62 : memcpy(log->buffer + log->size, varinfo->unit, unit_size);
2200 62 : log->size += unit_size;
2201 : }
2202 : }
2203 : }
2204 :
2205 11747 : memcpy(log->buffer + log->size, datap, datalen);
2206 11747 : log->size += datalen;
2207 :
2208 11747 : log->args_num++;
2209 :
2210 11747 : return DLT_RETURN_OK;
2211 : }
2212 :
2213 : // Generic implementation for all "simple" types
2214 112 : static DltReturnValue dlt_user_log_write_generic_formatted(DltContextData *log, const void *datap, size_t datalen, uint32_t type_info, DltFormatType type)
2215 : {
2216 112 : if (log == NULL)
2217 : return DLT_RETURN_WRONG_PARAMETER;
2218 :
2219 : /* Have to cast type to signed type because some compilers assume that DltFormatType is unsigned and issue a warning */
2220 84 : if (((int16_t)type < DLT_FORMAT_DEFAULT) || (type >= DLT_FORMAT_MAX)) {
2221 0 : dlt_vlog(LOG_ERR, "Format type %d is outside valid range", type);
2222 0 : return DLT_RETURN_WRONG_PARAMETER;
2223 : }
2224 :
2225 84 : if (!DLT_USER_INITIALIZED) {
2226 0 : dlt_vlog(LOG_WARNING, "%s dlt_user_init_state=%i (expected INIT_DONE), dlt_user_freeing=%i\n", __FUNCTION__, dlt_user_init_state, dlt_user_freeing);
2227 0 : return DLT_RETURN_ERROR;
2228 : }
2229 :
2230 : size_t needed_size = datalen;
2231 84 : if ((log->size + needed_size) > dlt_user.log_buf_len)
2232 : return DLT_RETURN_USER_BUFFER_FULL;
2233 :
2234 84 : if (is_verbose_mode(dlt_user.verbose_mode, log)) {
2235 84 : needed_size += sizeof(uint32_t); // Type Info field
2236 84 : if ((log->size + needed_size) > dlt_user.log_buf_len)
2237 : return DLT_RETURN_USER_BUFFER_FULL;
2238 :
2239 : // Genivi extension: put formatting hints into the unused (for SINT/UINT/FLOA) SCOD field.
2240 84 : if ((type >= DLT_FORMAT_HEX8) && (type <= DLT_FORMAT_HEX64))
2241 48 : type_info |= DLT_SCOD_HEX;
2242 :
2243 36 : else if ((type >= DLT_FORMAT_BIN8) && (type <= DLT_FORMAT_BIN16))
2244 24 : type_info |= DLT_SCOD_BIN;
2245 :
2246 84 : memcpy(log->buffer + log->size, &type_info, sizeof(uint32_t));
2247 84 : log->size += sizeof(uint32_t);
2248 : }
2249 :
2250 84 : memcpy(log->buffer + log->size, datap, datalen);
2251 84 : log->size += datalen;
2252 :
2253 84 : log->args_num++;
2254 :
2255 84 : return DLT_RETURN_OK;
2256 : }
2257 :
2258 7 : DltReturnValue dlt_user_log_write_float32(DltContextData *log, float32_t data)
2259 : {
2260 : if (sizeof(float32_t) != 4)
2261 : return DLT_RETURN_ERROR;
2262 :
2263 : uint32_t type_info = DLT_TYPE_INFO_FLOA | DLT_TYLE_32BIT;
2264 7 : return dlt_user_log_write_generic_attr(log, &data, sizeof(float32_t), type_info, NULL);
2265 : }
2266 :
2267 7 : DltReturnValue dlt_user_log_write_float64(DltContextData *log, float64_t data)
2268 : {
2269 : if (sizeof(float64_t) != 8)
2270 : return DLT_RETURN_ERROR;
2271 :
2272 : uint32_t type_info = DLT_TYPE_INFO_FLOA | DLT_TYLE_64BIT;
2273 7 : return dlt_user_log_write_generic_attr(log, &data, sizeof(float64_t), type_info, NULL);
2274 : }
2275 :
2276 7 : DltReturnValue dlt_user_log_write_float32_attr(DltContextData *log, float32_t data, const char *name, const char *unit)
2277 : {
2278 : if (sizeof(float32_t) != 4)
2279 : return DLT_RETURN_ERROR;
2280 :
2281 : uint32_t type_info = DLT_TYPE_INFO_FLOA | DLT_TYLE_32BIT;
2282 7 : const VarInfo var_info = { name, unit, true };
2283 7 : return dlt_user_log_write_generic_attr(log, &data, sizeof(float32_t), type_info, &var_info);
2284 : }
2285 :
2286 7 : DltReturnValue dlt_user_log_write_float64_attr(DltContextData *log, float64_t data, const char *name, const char *unit)
2287 : {
2288 : if (sizeof(float64_t) != 8)
2289 : return DLT_RETURN_ERROR;
2290 :
2291 : uint32_t type_info = DLT_TYPE_INFO_FLOA | DLT_TYLE_64BIT;
2292 7 : const VarInfo var_info = { name, unit, true };
2293 7 : return dlt_user_log_write_generic_attr(log, &data, sizeof(float64_t), type_info, &var_info);
2294 : }
2295 :
2296 35 : DltReturnValue dlt_user_log_write_uint(DltContextData *log, unsigned int data)
2297 : {
2298 35 : if (log == NULL)
2299 : return DLT_RETURN_WRONG_PARAMETER;
2300 :
2301 34 : if (!DLT_USER_INITIALIZED_NOT_FREEING) {
2302 0 : dlt_vlog(LOG_WARNING, "%s dlt_user_init_state=%i (expected INIT_DONE), dlt_user_freeing=%i\n", __FUNCTION__, dlt_user_init_state, dlt_user_freeing);
2303 0 : return DLT_RETURN_ERROR;
2304 : }
2305 :
2306 : switch (sizeof(unsigned int)) {
2307 : case 1:
2308 : {
2309 : return dlt_user_log_write_uint8(log, (uint8_t)data);
2310 : break;
2311 : }
2312 : case 2:
2313 : {
2314 : return dlt_user_log_write_uint16(log, (uint16_t)data);
2315 : break;
2316 : }
2317 34 : case 4:
2318 : {
2319 34 : return dlt_user_log_write_uint32(log, (uint32_t)data);
2320 : break;
2321 : }
2322 : case 8:
2323 : {
2324 : return dlt_user_log_write_uint64(log, (uint64_t)data);
2325 : break;
2326 : }
2327 : default:
2328 : {
2329 : return DLT_RETURN_ERROR;
2330 : break;
2331 : }
2332 : }
2333 :
2334 : return DLT_RETURN_OK;
2335 : }
2336 :
2337 4 : DltReturnValue dlt_user_log_write_uint8(DltContextData *log, uint8_t data)
2338 : {
2339 : uint32_t type_info = DLT_TYPE_INFO_UINT | DLT_TYLE_8BIT;
2340 4 : return dlt_user_log_write_generic_attr(log, &data, sizeof(uint8_t), type_info, NULL);
2341 : }
2342 :
2343 4 : DltReturnValue dlt_user_log_write_uint16(DltContextData *log, uint16_t data)
2344 : {
2345 : uint32_t type_info = DLT_TYPE_INFO_UINT | DLT_TYLE_16BIT;
2346 4 : return dlt_user_log_write_generic_attr(log, &data, sizeof(uint16_t), type_info, NULL);
2347 : }
2348 :
2349 11580 : DltReturnValue dlt_user_log_write_uint32(DltContextData *log, uint32_t data)
2350 : {
2351 : uint32_t type_info = DLT_TYPE_INFO_UINT | DLT_TYLE_32BIT;
2352 11580 : return dlt_user_log_write_generic_attr(log, &data, sizeof(uint32_t), type_info, NULL);
2353 : }
2354 :
2355 4 : DltReturnValue dlt_user_log_write_uint64(DltContextData *log, uint64_t data)
2356 : {
2357 : uint32_t type_info = DLT_TYPE_INFO_UINT | DLT_TYLE_64BIT;
2358 4 : return dlt_user_log_write_generic_attr(log, &data, sizeof(uint64_t), type_info, NULL);
2359 : }
2360 :
2361 7 : DltReturnValue dlt_user_log_write_uint_attr(DltContextData *log, unsigned int data, const char *name, const char *unit)
2362 : {
2363 7 : if (log == NULL)
2364 : return DLT_RETURN_WRONG_PARAMETER;
2365 :
2366 7 : if (!DLT_USER_INITIALIZED_NOT_FREEING) {
2367 0 : dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
2368 0 : return DLT_RETURN_ERROR;
2369 : }
2370 :
2371 : switch (sizeof(unsigned int)) {
2372 : case 1:
2373 : {
2374 : return dlt_user_log_write_uint8_attr(log, (uint8_t)data, name, unit);
2375 : break;
2376 : }
2377 : case 2:
2378 : {
2379 : return dlt_user_log_write_uint16_attr(log, (uint16_t)data, name, unit);
2380 : break;
2381 : }
2382 7 : case 4:
2383 : {
2384 7 : return dlt_user_log_write_uint32_attr(log, (uint32_t)data, name, unit);
2385 : break;
2386 : }
2387 : case 8:
2388 : {
2389 : return dlt_user_log_write_uint64_attr(log, (uint64_t)data, name, unit);
2390 : break;
2391 : }
2392 : default:
2393 : {
2394 : return DLT_RETURN_ERROR;
2395 : break;
2396 : }
2397 : }
2398 :
2399 : return DLT_RETURN_OK;
2400 : }
2401 :
2402 7 : DltReturnValue dlt_user_log_write_uint8_attr(DltContextData *log, uint8_t data, const char *name, const char *unit)
2403 : {
2404 : uint32_t type_info = DLT_TYPE_INFO_UINT | DLT_TYLE_8BIT;
2405 7 : const VarInfo var_info = { name, unit, true };
2406 7 : return dlt_user_log_write_generic_attr(log, &data, sizeof(uint8_t), type_info, &var_info);
2407 : }
2408 :
2409 7 : DltReturnValue dlt_user_log_write_uint16_attr(DltContextData *log, uint16_t data, const char *name, const char *unit)
2410 : {
2411 : uint32_t type_info = DLT_TYPE_INFO_UINT | DLT_TYLE_16BIT;
2412 7 : const VarInfo var_info = { name, unit, true };
2413 7 : return dlt_user_log_write_generic_attr(log, &data, sizeof(uint16_t), type_info, &var_info);
2414 : }
2415 :
2416 18 : DltReturnValue dlt_user_log_write_uint32_attr(DltContextData *log, uint32_t data, const char *name, const char *unit)
2417 : {
2418 : uint32_t type_info = DLT_TYPE_INFO_UINT | DLT_TYLE_32BIT;
2419 18 : const VarInfo var_info = { name, unit, true };
2420 18 : return dlt_user_log_write_generic_attr(log, &data, sizeof(uint32_t), type_info, &var_info);
2421 : }
2422 :
2423 7 : DltReturnValue dlt_user_log_write_uint64_attr(DltContextData *log, uint64_t data, const char *name, const char *unit)
2424 : {
2425 : uint32_t type_info = DLT_TYPE_INFO_UINT | DLT_TYLE_64BIT;
2426 7 : const VarInfo var_info = { name, unit, true };
2427 7 : return dlt_user_log_write_generic_attr(log, &data, sizeof(uint64_t), type_info, &var_info);
2428 : }
2429 :
2430 28 : DltReturnValue dlt_user_log_write_uint8_formatted(DltContextData *log, uint8_t data, DltFormatType type)
2431 : {
2432 : uint32_t type_info = DLT_TYPE_INFO_UINT | DLT_TYLE_8BIT;
2433 28 : return dlt_user_log_write_generic_formatted(log, &data, sizeof(uint8_t), type_info, type);
2434 : }
2435 :
2436 28 : DltReturnValue dlt_user_log_write_uint16_formatted(DltContextData *log, uint16_t data, DltFormatType type)
2437 : {
2438 : uint32_t type_info = DLT_TYPE_INFO_UINT | DLT_TYLE_16BIT;
2439 28 : return dlt_user_log_write_generic_formatted(log, &data, sizeof(uint16_t), type_info, type);
2440 : }
2441 :
2442 28 : DltReturnValue dlt_user_log_write_uint32_formatted(DltContextData *log, uint32_t data, DltFormatType type)
2443 : {
2444 : uint32_t type_info = DLT_TYPE_INFO_UINT | DLT_TYLE_32BIT;
2445 28 : return dlt_user_log_write_generic_formatted(log, &data, sizeof(uint32_t), type_info, type);
2446 : }
2447 :
2448 28 : DltReturnValue dlt_user_log_write_uint64_formatted(DltContextData *log, uint64_t data, DltFormatType type)
2449 : {
2450 : uint32_t type_info = DLT_TYPE_INFO_UINT | DLT_TYLE_64BIT;
2451 28 : return dlt_user_log_write_generic_formatted(log, &data, sizeof(uint64_t), type_info, type);
2452 : }
2453 :
2454 0 : DltReturnValue dlt_user_log_write_ptr(DltContextData *log, void *data)
2455 : {
2456 0 : if (log == NULL)
2457 : return DLT_RETURN_WRONG_PARAMETER;
2458 :
2459 0 : if (!DLT_USER_INITIALIZED_NOT_FREEING) {
2460 0 : dlt_vlog(LOG_WARNING, "%s user_initialised false\n", __FUNCTION__);
2461 0 : return DLT_RETURN_ERROR;
2462 : }
2463 :
2464 : switch (sizeof(void *)) {
2465 : case 4:
2466 : return dlt_user_log_write_uint32_formatted(log,
2467 : (uintptr_t) data,
2468 : DLT_FORMAT_HEX32);
2469 : break;
2470 0 : case 8:
2471 0 : return dlt_user_log_write_uint64_formatted(log,
2472 : (uintptr_t) data,
2473 : DLT_FORMAT_HEX64);
2474 : break;
2475 : default:
2476 : ; /* skip */
2477 : }
2478 :
2479 : return DLT_RETURN_OK;
2480 : }
2481 :
2482 37 : DltReturnValue dlt_user_log_write_int(DltContextData *log, int data)
2483 : {
2484 37 : if (log == NULL)
2485 : return DLT_RETURN_WRONG_PARAMETER;
2486 :
2487 36 : if (!DLT_USER_INITIALIZED_NOT_FREEING) {
2488 0 : dlt_vlog(LOG_WARNING, "%s dlt_user_init_state=%i (expected INIT_DONE), dlt_user_freeing=%i\n", __FUNCTION__, dlt_user_init_state, dlt_user_freeing);
2489 0 : return DLT_RETURN_ERROR;
2490 : }
2491 :
2492 : switch (sizeof(int)) {
2493 : case 1:
2494 : {
2495 : return dlt_user_log_write_int8(log, (int8_t)data);
2496 : break;
2497 : }
2498 : case 2:
2499 : {
2500 : return dlt_user_log_write_int16(log, (int16_t)data);
2501 : break;
2502 : }
2503 36 : case 4:
2504 : {
2505 36 : return dlt_user_log_write_int32(log, (int32_t)data);
2506 : break;
2507 : }
2508 : case 8:
2509 : {
2510 : return dlt_user_log_write_int64(log, (int64_t)data);
2511 : break;
2512 : }
2513 : default:
2514 : {
2515 : return DLT_RETURN_ERROR;
2516 : break;
2517 : }
2518 : }
2519 :
2520 : return DLT_RETURN_OK;
2521 : }
2522 :
2523 6 : DltReturnValue dlt_user_log_write_int8(DltContextData *log, int8_t data)
2524 : {
2525 : uint32_t type_info = DLT_TYPE_INFO_SINT | DLT_TYLE_8BIT;
2526 6 : return dlt_user_log_write_generic_attr(log, &data, sizeof(int8_t), type_info, NULL);
2527 : }
2528 :
2529 6 : DltReturnValue dlt_user_log_write_int16(DltContextData *log, int16_t data)
2530 : {
2531 : uint32_t type_info = DLT_TYPE_INFO_SINT | DLT_TYLE_16BIT;
2532 6 : return dlt_user_log_write_generic_attr(log, &data, sizeof(int16_t), type_info, NULL);
2533 : }
2534 :
2535 42 : DltReturnValue dlt_user_log_write_int32(DltContextData *log, int32_t data)
2536 : {
2537 : uint32_t type_info = DLT_TYPE_INFO_SINT | DLT_TYLE_32BIT;
2538 42 : return dlt_user_log_write_generic_attr(log, &data, sizeof(int32_t), type_info, NULL);
2539 : }
2540 :
2541 6 : DltReturnValue dlt_user_log_write_int64(DltContextData *log, int64_t data)
2542 : {
2543 : uint32_t type_info = DLT_TYPE_INFO_SINT | DLT_TYLE_64BIT;
2544 6 : return dlt_user_log_write_generic_attr(log, &data, sizeof(int64_t), type_info, NULL);
2545 : }
2546 :
2547 7 : DltReturnValue dlt_user_log_write_int_attr(DltContextData *log, int data, const char *name, const char *unit)
2548 : {
2549 7 : if (log == NULL)
2550 : return DLT_RETURN_WRONG_PARAMETER;
2551 :
2552 7 : if (!DLT_USER_INITIALIZED_NOT_FREEING) {
2553 0 : dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
2554 0 : return DLT_RETURN_ERROR;
2555 : }
2556 :
2557 : switch (sizeof(int)) {
2558 : case 1:
2559 : {
2560 : return dlt_user_log_write_int8_attr(log, (int8_t)data, name, unit);
2561 : break;
2562 : }
2563 : case 2:
2564 : {
2565 : return dlt_user_log_write_int16_attr(log, (int16_t)data, name, unit);
2566 : break;
2567 : }
2568 7 : case 4:
2569 : {
2570 7 : return dlt_user_log_write_int32_attr(log, (int32_t)data, name, unit);
2571 : break;
2572 : }
2573 : case 8:
2574 : {
2575 : return dlt_user_log_write_int64_attr(log, (int64_t)data, name, unit);
2576 : break;
2577 : }
2578 : default:
2579 : {
2580 : return DLT_RETURN_ERROR;
2581 : break;
2582 : }
2583 : }
2584 :
2585 : return DLT_RETURN_OK;
2586 : }
2587 :
2588 7 : DltReturnValue dlt_user_log_write_int8_attr(DltContextData *log, int8_t data, const char *name, const char *unit)
2589 : {
2590 : uint32_t type_info = DLT_TYPE_INFO_SINT | DLT_TYLE_8BIT;
2591 7 : const VarInfo var_info = { name, unit, true };
2592 7 : return dlt_user_log_write_generic_attr(log, &data, sizeof(int8_t), type_info, &var_info);
2593 : }
2594 :
2595 7 : DltReturnValue dlt_user_log_write_int16_attr(DltContextData *log, int16_t data, const char *name, const char *unit)
2596 : {
2597 : uint32_t type_info = DLT_TYPE_INFO_SINT | DLT_TYLE_16BIT;
2598 7 : const VarInfo var_info = { name, unit, true };
2599 7 : return dlt_user_log_write_generic_attr(log, &data, sizeof(int16_t), type_info, &var_info);
2600 : }
2601 :
2602 14 : DltReturnValue dlt_user_log_write_int32_attr(DltContextData *log, int32_t data, const char *name, const char *unit)
2603 : {
2604 : uint32_t type_info = DLT_TYPE_INFO_SINT | DLT_TYLE_32BIT;
2605 14 : const VarInfo var_info = { name, unit, true };
2606 14 : return dlt_user_log_write_generic_attr(log, &data, sizeof(int32_t), type_info, &var_info);
2607 : }
2608 :
2609 7 : DltReturnValue dlt_user_log_write_int64_attr(DltContextData *log, int64_t data, const char *name, const char *unit)
2610 : {
2611 : uint32_t type_info = DLT_TYPE_INFO_SINT | DLT_TYLE_64BIT;
2612 7 : const VarInfo var_info = { name, unit, true };
2613 7 : return dlt_user_log_write_generic_attr(log, &data, sizeof(int64_t), type_info, &var_info);
2614 : }
2615 :
2616 3 : DltReturnValue dlt_user_log_write_bool(DltContextData *log, uint8_t data)
2617 : {
2618 : uint32_t type_info = DLT_TYPE_INFO_BOOL | DLT_TYLE_8BIT;
2619 3 : return dlt_user_log_write_generic_attr(log, &data, sizeof(uint8_t), type_info, NULL);
2620 : }
2621 :
2622 3 : DltReturnValue dlt_user_log_write_bool_attr(DltContextData *log, uint8_t data, const char *name)
2623 : {
2624 : uint32_t type_info = DLT_TYPE_INFO_BOOL | DLT_TYLE_8BIT;
2625 3 : const VarInfo var_info = { name, NULL, false };
2626 3 : return dlt_user_log_write_generic_attr(log, &data, sizeof(uint8_t), type_info, &var_info);
2627 : }
2628 :
2629 11686 : DltReturnValue dlt_user_log_write_string(DltContextData *log, const char *text)
2630 : {
2631 11686 : return dlt_user_log_write_string_utils_attr(log, text, ASCII_STRING, NULL, false);
2632 : }
2633 :
2634 7 : DltReturnValue dlt_user_log_write_string_attr(DltContextData *log, const char *text, const char *name)
2635 : {
2636 7 : return dlt_user_log_write_string_utils_attr(log, text, ASCII_STRING, name, true);
2637 : }
2638 :
2639 2 : DltReturnValue dlt_user_log_write_sized_string(DltContextData *log, const char *text, uint16_t length)
2640 : {
2641 2 : return dlt_user_log_write_sized_string_utils_attr(log, text, length, ASCII_STRING, NULL, false);
2642 : }
2643 :
2644 6 : DltReturnValue dlt_user_log_write_sized_string_attr(DltContextData *log, const char *text, uint16_t length, const char *name)
2645 : {
2646 6 : return dlt_user_log_write_sized_string_utils_attr(log, text, length, ASCII_STRING, name, true);
2647 : }
2648 :
2649 7 : DltReturnValue dlt_user_log_write_constant_string(DltContextData *log, const char *text)
2650 : {
2651 : /* Send parameter only in verbose mode */
2652 8 : return is_verbose_mode(dlt_user.verbose_mode, log) ? dlt_user_log_write_string(log, text) : DLT_RETURN_OK;
2653 : }
2654 :
2655 5 : DltReturnValue dlt_user_log_write_constant_string_attr(DltContextData *log, const char *text, const char *name)
2656 : {
2657 : /* Send parameter only in verbose mode */
2658 6 : return is_verbose_mode(dlt_user.verbose_mode, log) ? dlt_user_log_write_string_attr(log, text, name) : DLT_RETURN_OK;
2659 : }
2660 :
2661 1 : DltReturnValue dlt_user_log_write_sized_constant_string(DltContextData *log, const char *text, uint16_t length)
2662 : {
2663 : /* Send parameter only in verbose mode */
2664 1 : return is_verbose_mode(dlt_user.verbose_mode, log) ? dlt_user_log_write_sized_string(log, text, length) : DLT_RETURN_OK;
2665 : }
2666 :
2667 3 : DltReturnValue dlt_user_log_write_sized_constant_string_attr(DltContextData *log, const char *text, uint16_t length, const char *name)
2668 : {
2669 : /* Send parameter only in verbose mode */
2670 3 : return is_verbose_mode(dlt_user.verbose_mode, log) ? dlt_user_log_write_sized_string_attr(log, text, length, name) : DLT_RETURN_OK;
2671 : }
2672 :
2673 21 : DltReturnValue dlt_user_log_write_utf8_string(DltContextData *log, const char *text)
2674 : {
2675 21 : return dlt_user_log_write_string_utils_attr(log, text, UTF8_STRING, NULL, false);
2676 : }
2677 :
2678 7 : DltReturnValue dlt_user_log_write_utf8_string_attr(DltContextData *log, const char *text, const char *name)
2679 : {
2680 7 : return dlt_user_log_write_string_utils_attr(log, text, UTF8_STRING, name, true);
2681 : }
2682 :
2683 8 : DltReturnValue dlt_user_log_write_sized_utf8_string(DltContextData *log, const char *text, uint16_t length)
2684 : {
2685 8 : return dlt_user_log_write_sized_string_utils_attr(log, text, length, UTF8_STRING, NULL, false);
2686 : }
2687 :
2688 7 : DltReturnValue dlt_user_log_write_sized_utf8_string_attr(DltContextData *log, const char *text, uint16_t length, const char *name)
2689 : {
2690 7 : return dlt_user_log_write_sized_string_utils_attr(log, text, length, UTF8_STRING, name, true);
2691 : }
2692 :
2693 5 : DltReturnValue dlt_user_log_write_constant_utf8_string(DltContextData *log, const char *text)
2694 : {
2695 : /* Send parameter only in verbose mode */
2696 5 : return is_verbose_mode(dlt_user.verbose_mode, log) ? dlt_user_log_write_utf8_string(log, text) : DLT_RETURN_OK;
2697 : }
2698 :
2699 4 : DltReturnValue dlt_user_log_write_constant_utf8_string_attr(DltContextData *log, const char *text, const char *name)
2700 : {
2701 : /* Send parameter only in verbose mode */
2702 4 : return is_verbose_mode(dlt_user.verbose_mode, log) ? dlt_user_log_write_utf8_string_attr(log, text, name) : DLT_RETURN_OK;
2703 : }
2704 :
2705 5 : DltReturnValue dlt_user_log_write_sized_constant_utf8_string(DltContextData *log, const char *text, uint16_t length)
2706 : {
2707 : /* Send parameter only in verbose mode */
2708 5 : return is_verbose_mode(dlt_user.verbose_mode, log) ? dlt_user_log_write_sized_utf8_string(log, text, length) : DLT_RETURN_OK;
2709 : }
2710 :
2711 4 : DltReturnValue dlt_user_log_write_sized_constant_utf8_string_attr(DltContextData *log, const char *text, uint16_t length, const char *name)
2712 : {
2713 : /* Send parameter only in verbose mode */
2714 4 : return is_verbose_mode(dlt_user.verbose_mode, log) ? dlt_user_log_write_sized_utf8_string_attr(log, text, length, name) : DLT_RETURN_OK;
2715 : }
2716 :
2717 11729 : static DltReturnValue dlt_user_log_write_sized_string_utils_attr(DltContextData *log, const char *text, size_t length, const enum StringType type, const char *name, bool with_var_info)
2718 : {
2719 11729 : if ((log == NULL) || (text == NULL))
2720 : return DLT_RETURN_WRONG_PARAMETER;
2721 :
2722 11720 : if (!DLT_USER_INITIALIZED_NOT_FREEING) {
2723 0 : dlt_vlog(LOG_WARNING, "%s dlt_user_init_state=%i (expected INIT_DONE), dlt_user_freeing=%i\n", __FUNCTION__, dlt_user_init_state, dlt_user_freeing);
2724 0 : return DLT_RETURN_ERROR;
2725 : }
2726 :
2727 11720 : const uint16_t name_size = (name != NULL) ? strlen(name)+1 : 0;
2728 :
2729 11720 : size_t arg_size = (size_t) (length + 1);
2730 :
2731 11720 : size_t new_log_size = log->size + arg_size + sizeof(uint16_t);
2732 :
2733 11720 : uint32_t type_info = 0;
2734 :
2735 11720 : if (is_verbose_mode(dlt_user.verbose_mode, log)) {
2736 11720 : new_log_size += sizeof(uint32_t);
2737 11720 : if (with_var_info) {
2738 21 : new_log_size += sizeof(uint16_t); // length of "name" attribute
2739 21 : new_log_size += name_size; // the "name" attribute itself
2740 :
2741 21 : type_info |= DLT_TYPE_INFO_VARI;
2742 : }
2743 : }
2744 :
2745 : size_t str_truncate_message_length = strlen(STR_TRUNCATED_MESSAGE) + 1;
2746 : size_t max_payload_str_msg;
2747 : DltReturnValue ret = DLT_RETURN_OK;
2748 :
2749 : /* Check log size condition */
2750 11720 : if (new_log_size > dlt_user.log_buf_len) {
2751 : ret = DLT_RETURN_USER_BUFFER_FULL;
2752 :
2753 : /* Re-calculate arg_size */
2754 21 : arg_size = (size_t) (dlt_user.log_buf_len - log->size - sizeof(uint16_t));
2755 :
2756 21 : size_t min_payload_str_truncate_msg = log->size + str_truncate_message_length + sizeof(uint16_t);
2757 :
2758 : if (is_verbose_mode(dlt_user.verbose_mode, log)) {
2759 21 : min_payload_str_truncate_msg += sizeof(uint32_t);
2760 21 : arg_size -= (size_t) sizeof(uint32_t);
2761 21 : if (with_var_info) {
2762 0 : min_payload_str_truncate_msg += sizeof(uint16_t) + name_size;
2763 0 : arg_size -= sizeof(uint16_t) + name_size;
2764 : }
2765 : }
2766 :
2767 : /* Return when dlt_user.log_buf_len does not have enough space for min_payload_str_truncate_msg */
2768 21 : if (min_payload_str_truncate_msg > dlt_user.log_buf_len) {
2769 1 : dlt_vlog(LOG_WARNING, "%s not enough minimum space to store data\n", __FUNCTION__);
2770 1 : return ret;
2771 : }
2772 :
2773 : /* Calculate the maximum size of string will be copied after truncate */
2774 20 : max_payload_str_msg = dlt_user.log_buf_len - min_payload_str_truncate_msg;
2775 :
2776 20 : if (type == UTF8_STRING) {
2777 : /**
2778 : * Adjust the lengh to truncate one utf8 character corectly
2779 : * refer: https://en.wikipedia.org/wiki/UTF-8
2780 : * one utf8 character will have maximum 4 bytes then maximum bytes will be truncate additional is 3
2781 : */
2782 12 : const char *tmp = (text + max_payload_str_msg - 3);
2783 : uint16_t reduce_size = 0;
2784 :
2785 12 : if (tmp[2] & 0x80) {
2786 : /* Is the last byte of truncated text is the first byte in multi-byte sequence (utf8 2 bytes) */
2787 9 : if (tmp[2] & 0x40)
2788 : reduce_size = 1;
2789 : /* Is the next to last byte of truncated text is the first byte in multi-byte sequence (utf8 3 bytes) */
2790 6 : else if ((tmp[1] & 0xe0) == 0xe0)
2791 : reduce_size = 2;
2792 : /* utf8 4 bytes */
2793 3 : else if ((tmp[0] & 0xf0) == 0xf0)
2794 : reduce_size = 3;
2795 : }
2796 :
2797 12 : max_payload_str_msg -= reduce_size;
2798 12 : arg_size -= (size_t) reduce_size;
2799 : }
2800 : }
2801 :
2802 : if (is_verbose_mode(dlt_user.verbose_mode, log)) {
2803 11719 : switch (type) {
2804 11694 : case ASCII_STRING:
2805 11694 : type_info |= DLT_TYPE_INFO_STRG | DLT_SCOD_ASCII;
2806 11694 : break;
2807 25 : case UTF8_STRING:
2808 25 : type_info |= DLT_TYPE_INFO_STRG | DLT_SCOD_UTF8;
2809 25 : break;
2810 : default:
2811 : /* Do nothing */
2812 : break;
2813 : }
2814 :
2815 11719 : memcpy(log->buffer + log->size, &type_info, sizeof(uint32_t));
2816 11719 : log->size += sizeof(uint32_t);
2817 : }
2818 :
2819 11719 : memcpy(log->buffer + log->size, &arg_size, sizeof(uint16_t));
2820 11719 : log->size += sizeof(uint16_t);
2821 :
2822 11719 : if (is_verbose_mode(dlt_user.verbose_mode, log)) {
2823 11719 : if (with_var_info) {
2824 : // Write length of "name" attribute.
2825 : // We assume that the protocol allows zero-sized strings here (which this code will create
2826 : // when the input pointer is NULL).
2827 21 : memcpy(log->buffer + log->size, &name_size, sizeof(uint16_t));
2828 21 : log->size += sizeof(uint16_t);
2829 :
2830 : // Write name string itself.
2831 : // Must not use NULL as source pointer for memcpy. This check assures that.
2832 21 : if (name_size != 0) {
2833 15 : memcpy(log->buffer + log->size, name, name_size);
2834 15 : log->size += name_size;
2835 : }
2836 : }
2837 : }
2838 :
2839 11719 : switch (ret) {
2840 11699 : case DLT_RETURN_OK:
2841 : {
2842 : /* Whole string will be copied */
2843 11699 : memcpy(log->buffer + log->size, text, length);
2844 : /* The input string might not be null-terminated, so we're doing that by ourselves */
2845 11699 : log->buffer[log->size + length] = '\0';
2846 11699 : log->size += arg_size;
2847 11699 : break;
2848 : }
2849 20 : case DLT_RETURN_USER_BUFFER_FULL:
2850 : {
2851 : /* Only copy partial string */
2852 20 : memcpy(log->buffer + log->size, text, max_payload_str_msg);
2853 20 : log->size += max_payload_str_msg;
2854 :
2855 : /* Append string truncate the input string */
2856 20 : memcpy(log->buffer + log->size, STR_TRUNCATED_MESSAGE, str_truncate_message_length);
2857 20 : log->size += str_truncate_message_length;
2858 20 : break;
2859 : }
2860 : default:
2861 : {
2862 : /* Do nothing */
2863 : break;
2864 : }
2865 : }
2866 :
2867 11719 : log->args_num++;
2868 :
2869 11719 : return ret;
2870 : }
2871 :
2872 11721 : static DltReturnValue dlt_user_log_write_string_utils_attr(DltContextData *log, const char *text, const enum StringType type, const char *name, bool with_var_info)
2873 : {
2874 11721 : if ((log == NULL) || (text == NULL))
2875 : return DLT_RETURN_WRONG_PARAMETER;
2876 :
2877 11706 : size_t length = strlen(text);
2878 11706 : return dlt_user_log_write_sized_string_utils_attr(log, text, length, type, name, with_var_info);
2879 : }
2880 :
2881 0 : DltReturnValue dlt_register_injection_callback_with_id(DltContext *handle, uint32_t service_id,
2882 : dlt_injection_callback_id dlt_injection_cbk, void *priv)
2883 : {
2884 : DltContextData log;
2885 : uint32_t i, j, k;
2886 : int found = 0;
2887 :
2888 : DltUserInjectionCallback *old;
2889 :
2890 0 : if (dlt_user_log_init(handle, &log) < DLT_RETURN_OK)
2891 : return DLT_RETURN_ERROR;
2892 :
2893 0 : if (service_id < DLT_USER_INJECTION_MIN)
2894 : return DLT_RETURN_WRONG_PARAMETER;
2895 :
2896 : /* This function doesn't make sense storing to local file is choosen;
2897 : * so terminate this function */
2898 0 : if (dlt_user.dlt_is_file)
2899 : return DLT_RETURN_OK;
2900 :
2901 0 : dlt_mutex_lock();
2902 :
2903 0 : if (dlt_user.dlt_ll_ts == NULL) {
2904 0 : dlt_mutex_free();
2905 0 : return DLT_RETURN_OK;
2906 : }
2907 :
2908 : /* Insert callback in corresponding table */
2909 0 : i = (uint32_t) handle->log_level_pos;
2910 :
2911 : /* Insert each service_id only once */
2912 0 : for (k = 0; k < dlt_user.dlt_ll_ts[i].nrcallbacks; k++)
2913 0 : if ((dlt_user.dlt_ll_ts[i].injection_table) &&
2914 0 : (dlt_user.dlt_ll_ts[i].injection_table[k].service_id == service_id)) {
2915 : found = 1;
2916 : break;
2917 : }
2918 :
2919 0 : if (found) {
2920 : j = k;
2921 : }
2922 : else {
2923 : j = dlt_user.dlt_ll_ts[i].nrcallbacks;
2924 :
2925 : /* Allocate or expand injection table */
2926 0 : if (dlt_user.dlt_ll_ts[i].injection_table == NULL) {
2927 0 : dlt_user.dlt_ll_ts[i].injection_table =
2928 0 : (DltUserInjectionCallback *)malloc(sizeof(DltUserInjectionCallback));
2929 :
2930 0 : if (dlt_user.dlt_ll_ts[i].injection_table == NULL) {
2931 0 : dlt_mutex_free();
2932 0 : return DLT_RETURN_ERROR;
2933 : }
2934 : }
2935 : else {
2936 : old = dlt_user.dlt_ll_ts[i].injection_table;
2937 0 : dlt_user.dlt_ll_ts[i].injection_table = (DltUserInjectionCallback *)malloc(
2938 0 : sizeof(DltUserInjectionCallback) * (j + 1));
2939 :
2940 0 : if (dlt_user.dlt_ll_ts[i].injection_table == NULL) {
2941 0 : dlt_user.dlt_ll_ts[i].injection_table = old;
2942 0 : dlt_mutex_free();
2943 0 : return DLT_RETURN_ERROR;
2944 : }
2945 :
2946 0 : memcpy(dlt_user.dlt_ll_ts[i].injection_table, old, sizeof(DltUserInjectionCallback) * j);
2947 0 : free(old);
2948 : }
2949 :
2950 0 : dlt_user.dlt_ll_ts[i].nrcallbacks++;
2951 : }
2952 :
2953 : /* Store service_id and corresponding function pointer for callback function */
2954 0 : dlt_user.dlt_ll_ts[i].injection_table[j].service_id = service_id;
2955 :
2956 0 : if (priv == NULL) {
2957 0 : dlt_user.dlt_ll_ts[i].injection_table[j].injection_callback = (dlt_injection_callback)(void*)dlt_injection_cbk;
2958 0 : dlt_user.dlt_ll_ts[i].injection_table[j].injection_callback_with_id = NULL;
2959 0 : dlt_user.dlt_ll_ts[i].injection_table[j].data = NULL;
2960 : }
2961 : else {
2962 0 : dlt_user.dlt_ll_ts[i].injection_table[j].injection_callback = NULL;
2963 0 : dlt_user.dlt_ll_ts[i].injection_table[j].injection_callback_with_id = dlt_injection_cbk;
2964 0 : dlt_user.dlt_ll_ts[i].injection_table[j].data = priv;
2965 : }
2966 :
2967 0 : dlt_mutex_free();
2968 :
2969 0 : return DLT_RETURN_OK;
2970 : }
2971 :
2972 0 : DltReturnValue dlt_register_injection_callback(DltContext *handle, uint32_t service_id,
2973 : int (*dlt_injection_callback)(uint32_t service_id,
2974 : void *data,
2975 : uint32_t length))
2976 : {
2977 0 : return dlt_register_injection_callback_with_id(handle,
2978 : service_id,
2979 : (dlt_injection_callback_id)(void*)dlt_injection_callback,
2980 : NULL);
2981 : }
2982 :
2983 1 : DltReturnValue dlt_register_log_level_changed_callback(DltContext *handle,
2984 : void (*dlt_log_level_changed_callback)(
2985 : char context_id[DLT_ID_SIZE],
2986 : uint8_t log_level,
2987 : uint8_t trace_status))
2988 : {
2989 : DltContextData log;
2990 : uint32_t i;
2991 :
2992 1 : if (dlt_user_log_init(handle, &log) < DLT_RETURN_OK)
2993 : return DLT_RETURN_ERROR;
2994 :
2995 : /* This function doesn't make sense storing to local file is choosen;
2996 : * so terminate this function */
2997 1 : if (dlt_user.dlt_is_file)
2998 : return DLT_RETURN_OK;
2999 :
3000 1 : dlt_mutex_lock();
3001 :
3002 1 : if (dlt_user.dlt_ll_ts == NULL) {
3003 0 : dlt_mutex_free();
3004 0 : return DLT_RETURN_OK;
3005 : }
3006 :
3007 : /* Insert callback in corresponding table */
3008 1 : i = (uint32_t) handle->log_level_pos;
3009 :
3010 : /* Store new callback function */
3011 1 : dlt_user.dlt_ll_ts[i].log_level_changed_callback = dlt_log_level_changed_callback;
3012 :
3013 1 : dlt_mutex_free();
3014 :
3015 1 : return DLT_RETURN_OK;
3016 : }
3017 :
3018 : /**
3019 : * NW Trace related
3020 : */
3021 :
3022 : #ifdef DLT_NETWORK_TRACE_ENABLE
3023 0 : int check_buffer(void)
3024 : {
3025 : int total_size, used_size;
3026 0 : dlt_user_check_buffer(&total_size, &used_size);
3027 :
3028 0 : return (total_size - used_size < total_size / 2) ? -1 : 1;
3029 : }
3030 :
3031 : /**
3032 : * Send the start of a segment chain.
3033 : * Returns DLT_RETURN_ERROR on failure
3034 : */
3035 0 : DltReturnValue dlt_user_trace_network_segmented_start(uint32_t *id,
3036 : DltContext *handle,
3037 : DltNetworkTraceType nw_trace_type,
3038 : uint16_t header_len,
3039 : void *header,
3040 : uint16_t payload_len)
3041 : {
3042 0 : DltContextData log = { 0 };
3043 : struct timeval tv;
3044 : int ret = DLT_RETURN_ERROR;
3045 :
3046 : /* check null pointer */
3047 0 : if (id == NULL)
3048 : return DLT_RETURN_WRONG_PARAMETER;
3049 :
3050 0 : if ((nw_trace_type < DLT_NW_TRACE_IPC) || (nw_trace_type >= DLT_NW_TRACE_MAX)) {
3051 0 : dlt_vlog(LOG_ERR, "Network trace type %u is outside valid range", nw_trace_type);
3052 0 : return DLT_RETURN_WRONG_PARAMETER;
3053 : }
3054 :
3055 0 : if (dlt_user.dlt_ll_ts == NULL)
3056 : return DLT_RETURN_ERROR;
3057 :
3058 0 : if (handle->trace_status_ptr && (*(handle->trace_status_ptr) == DLT_TRACE_STATUS_ON)) {
3059 : /* initialize values */
3060 0 : if (dlt_user_log_init(handle, &log) < DLT_RETURN_OK)
3061 : return DLT_RETURN_ERROR;
3062 :
3063 0 : if (log.buffer == NULL) {
3064 0 : log.buffer = calloc(sizeof(unsigned char), dlt_user.log_buf_len);
3065 :
3066 0 : if (log.buffer == NULL) {
3067 0 : dlt_vlog(LOG_ERR, "Cannot allocate buffer for DLT Log message\n");
3068 0 : return DLT_RETURN_ERROR;
3069 : }
3070 : }
3071 :
3072 0 : log.args_num = 0;
3073 0 : log.trace_status = nw_trace_type;
3074 0 : log.size = 0;
3075 :
3076 0 : gettimeofday(&tv, NULL);
3077 0 : *id = (uint32_t) tv.tv_usec;
3078 :
3079 : /* Write identifier */
3080 0 : if (dlt_user_log_write_string(&log, DLT_TRACE_NW_START) < 0) {
3081 : dlt_user_free_buffer(&(log.buffer));
3082 0 : return DLT_RETURN_ERROR;
3083 : }
3084 :
3085 : /* Write stream handle */
3086 0 : if (dlt_user_log_write_uint32(&log, *id) < 0) {
3087 : dlt_user_free_buffer(&(log.buffer));
3088 0 : return DLT_RETURN_ERROR;
3089 : }
3090 :
3091 : /* Write header */
3092 0 : if (dlt_user_log_write_raw(&log, header, header_len) < 0) {
3093 : dlt_user_free_buffer(&(log.buffer));
3094 0 : return DLT_RETURN_ERROR;
3095 : }
3096 :
3097 : /* Write size of payload */
3098 0 : if (dlt_user_log_write_uint32(&log, payload_len) < 0) {
3099 : dlt_user_free_buffer(&(log.buffer));
3100 0 : return DLT_RETURN_ERROR;
3101 : }
3102 :
3103 : /* Write expected segment count */
3104 0 : uint16_t segment_count = (uint16_t) (payload_len / DLT_MAX_TRACE_SEGMENT_SIZE + 1);
3105 :
3106 : /* If segments align perfectly with segment size, avoid sending empty segment */
3107 0 : if ((payload_len % DLT_MAX_TRACE_SEGMENT_SIZE) == 0)
3108 : segment_count--;
3109 :
3110 0 : if (dlt_user_log_write_uint16(&log, segment_count) < 0) {
3111 : dlt_user_free_buffer(&(log.buffer));
3112 0 : return DLT_RETURN_ERROR;
3113 : }
3114 :
3115 : /* Write length of one segment */
3116 0 : if (dlt_user_log_write_uint16(&log, DLT_MAX_TRACE_SEGMENT_SIZE) < 0) {
3117 : dlt_user_free_buffer(&(log.buffer));
3118 0 : return DLT_RETURN_ERROR;
3119 : }
3120 :
3121 : /* Send log */
3122 0 : ret = dlt_user_log_send_log(&log, DLT_TYPE_NW_TRACE, NULL);
3123 :
3124 : dlt_user_free_buffer(&(log.buffer));
3125 :
3126 0 : return ret;
3127 : }
3128 :
3129 : return DLT_RETURN_OK;
3130 : }
3131 :
3132 0 : DltReturnValue dlt_user_trace_network_segmented_segment(uint32_t id,
3133 : DltContext *handle,
3134 : DltNetworkTraceType nw_trace_type,
3135 : int sequence,
3136 : uint16_t payload_len,
3137 : void *payload)
3138 : {
3139 : int ret = DLT_RETURN_ERROR;
3140 : struct timespec ts;
3141 :
3142 0 : if ((nw_trace_type < DLT_NW_TRACE_IPC) || (nw_trace_type >= DLT_NW_TRACE_MAX)) {
3143 0 : dlt_vlog(LOG_ERR, "Network trace type %u is outside valid range", nw_trace_type);
3144 0 : return DLT_RETURN_WRONG_PARAMETER;
3145 : }
3146 :
3147 0 : while (check_buffer() < 0) {
3148 : /* Wait 50ms */
3149 0 : ts.tv_sec = 0;
3150 0 : ts.tv_nsec = 1000000 * 50;
3151 0 : nanosleep(&ts, NULL);
3152 0 : dlt_user_log_resend_buffer();
3153 : }
3154 :
3155 0 : if (dlt_user.dlt_ll_ts == NULL)
3156 : return DLT_RETURN_ERROR;
3157 :
3158 0 : if (handle->trace_status_ptr && (*(handle->trace_status_ptr) == DLT_TRACE_STATUS_ON)) {
3159 0 : DltContextData log = { 0 };
3160 :
3161 0 : if (dlt_user_log_init(handle, &log) < DLT_RETURN_OK)
3162 : return DLT_RETURN_ERROR;
3163 :
3164 : /* initialize values */
3165 0 : if (log.buffer == NULL) {
3166 0 : log.buffer = calloc(sizeof(unsigned char), dlt_user.log_buf_len);
3167 :
3168 0 : if (log.buffer == NULL) {
3169 0 : dlt_vlog(LOG_ERR, "Cannot allocate buffer for DLT Log message\n");
3170 0 : return DLT_RETURN_ERROR;
3171 : }
3172 : }
3173 :
3174 0 : log.args_num = 0;
3175 0 : log.trace_status = nw_trace_type;
3176 0 : log.size = 0;
3177 :
3178 : /* Write identifier */
3179 0 : if (dlt_user_log_write_string(&log, DLT_TRACE_NW_SEGMENT) < DLT_RETURN_OK) {
3180 : dlt_user_free_buffer(&(log.buffer));
3181 0 : return DLT_RETURN_ERROR;
3182 : }
3183 :
3184 : /* Write stream handle */
3185 0 : if (dlt_user_log_write_uint32(&log, id) < DLT_RETURN_OK) {
3186 : dlt_user_free_buffer(&(log.buffer));
3187 0 : return DLT_RETURN_ERROR;
3188 : }
3189 :
3190 : /* Write segment sequence number */
3191 0 : if (dlt_user_log_write_uint16(&log, (uint16_t) sequence) < DLT_RETURN_OK) {
3192 : dlt_user_free_buffer(&(log.buffer));
3193 0 : return DLT_RETURN_ERROR;
3194 : }
3195 :
3196 : /* Write data */
3197 0 : if (dlt_user_log_write_raw(&log, payload, payload_len) < DLT_RETURN_OK) {
3198 : dlt_user_free_buffer(&(log.buffer));
3199 0 : return DLT_RETURN_ERROR;
3200 : }
3201 :
3202 0 : ret = dlt_user_log_send_log(&log, DLT_TYPE_NW_TRACE, NULL);
3203 : /* Send log */
3204 :
3205 : dlt_user_free_buffer(&(log.buffer));
3206 :
3207 0 : return ret;
3208 : }
3209 :
3210 : /* Allow other threads to log between chunks */
3211 0 : sched_yield();
3212 0 : return DLT_RETURN_OK;
3213 : }
3214 :
3215 0 : DltReturnValue dlt_user_trace_network_segmented_end(uint32_t id, DltContext *handle, DltNetworkTraceType nw_trace_type)
3216 : {
3217 0 : DltContextData log = { 0 };
3218 : int ret = DLT_RETURN_ERROR;
3219 :
3220 0 : if ((nw_trace_type < DLT_NW_TRACE_IPC) || (nw_trace_type >= DLT_NW_TRACE_MAX)) {
3221 0 : dlt_vlog(LOG_ERR, "Network trace type %u is outside valid range", nw_trace_type);
3222 0 : return DLT_RETURN_WRONG_PARAMETER;
3223 : }
3224 :
3225 0 : if (dlt_user.dlt_ll_ts == NULL)
3226 : return DLT_RETURN_ERROR;
3227 :
3228 0 : if (handle->trace_status_ptr && (*(handle->trace_status_ptr) == DLT_TRACE_STATUS_ON)) {
3229 : /* initialize values */
3230 0 : if (dlt_user_log_init(handle, &log) < DLT_RETURN_OK)
3231 : return DLT_RETURN_ERROR;
3232 :
3233 : /* initialize values */
3234 0 : if (log.buffer == NULL) {
3235 0 : log.buffer = calloc(sizeof(unsigned char), dlt_user.log_buf_len);
3236 :
3237 0 : if (log.buffer == NULL) {
3238 0 : dlt_vlog(LOG_ERR, "Cannot allocate buffer for DLT Log message\n");
3239 0 : return DLT_RETURN_ERROR;
3240 : }
3241 : }
3242 :
3243 0 : log.args_num = 0;
3244 0 : log.trace_status = nw_trace_type;
3245 0 : log.size = 0;
3246 :
3247 : /* Write identifier */
3248 0 : if (dlt_user_log_write_string(&log, DLT_TRACE_NW_END) < DLT_RETURN_OK) {
3249 : dlt_user_free_buffer(&(log.buffer));
3250 0 : return DLT_RETURN_ERROR;
3251 : }
3252 :
3253 : /* Write stream handle */
3254 0 : if (dlt_user_log_write_uint32(&log, id) < DLT_RETURN_OK) {
3255 : dlt_user_free_buffer(&(log.buffer));
3256 0 : return DLT_RETURN_ERROR;
3257 : }
3258 :
3259 0 : ret = dlt_user_log_send_log(&log, DLT_TYPE_NW_TRACE, NULL);
3260 : /* Send log */
3261 :
3262 : dlt_user_free_buffer(&(log.buffer));
3263 :
3264 0 : return ret;
3265 :
3266 : }
3267 :
3268 : return DLT_RETURN_OK;
3269 : }
3270 :
3271 22517 : void dlt_user_trace_network_segmented_thread(void *unused)
3272 : {
3273 : /* Unused on purpose. */
3274 : (void)unused;
3275 : #ifdef DLT_USE_PTHREAD_SETNAME_NP
3276 22517 : if (pthread_setname_np(dlt_user.dlt_segmented_nwt_handle, "dlt_segmented"))
3277 0 : dlt_log(LOG_WARNING, "Failed to rename segmented thread!\n");
3278 : #elif linux
3279 : if (prctl(PR_SET_NAME, "dlt_segmented", 0, 0, 0) < 0)
3280 : dlt_log(LOG_WARNING, "Failed to rename segmented thread!\n");
3281 : #endif
3282 45034 : pthread_cleanup_push(dlt_user_cleanup_handler, NULL);
3283 :
3284 : s_segmented_data *data;
3285 :
3286 : while (1) {
3287 : /* Wait until message queue is initialized */
3288 22517 : dlt_lock_mutex(&mq_mutex);
3289 :
3290 22543 : while (dlt_user.dlt_segmented_queue_read_handle < 0)
3291 : {
3292 22543 : pthread_cond_wait(&mq_init_condition, &mq_mutex);
3293 : }
3294 :
3295 0 : dlt_unlock_mutex(&mq_mutex);
3296 :
3297 0 : ssize_t read = mq_receive(dlt_user.dlt_segmented_queue_read_handle, (char *)&data,
3298 : sizeof(s_segmented_data *), NULL);
3299 :
3300 0 : if (read < 0) {
3301 0 : if (errno != EINTR) {
3302 : struct timespec req;
3303 : long sec = (DLT_USER_MQ_ERROR_RETRY_INTERVAL / 1000000);
3304 0 : dlt_vlog(LOG_WARNING, "NWTSegmented: Error while reading queue: %s\n", strerror(errno));
3305 0 : req.tv_sec = sec;
3306 0 : req.tv_nsec = (DLT_USER_MQ_ERROR_RETRY_INTERVAL - sec * 1000000) * 1000;
3307 0 : nanosleep(&req, NULL);
3308 : }
3309 :
3310 0 : continue;
3311 : }
3312 :
3313 0 : if (read != sizeof(s_segmented_data *)) {
3314 : /* This case will not happen. */
3315 : /* When this thread is interrupted by signal, mq_receive() will not return */
3316 : /* partial read length and will return -1. And also no data is removed from mq. */
3317 0 : dlt_vlog(LOG_WARNING, "NWTSegmented: Could not read data fully from queue: %zd\n", read);
3318 0 : continue;
3319 : }
3320 :
3321 0 : dlt_user_trace_network_segmented_thread_segmenter(data);
3322 :
3323 : /* Send the end message */
3324 0 : DltReturnValue err = dlt_user_trace_network_segmented_end(data->id, data->handle, data->nw_trace_type);
3325 :
3326 0 : if ((err == DLT_RETURN_BUFFER_FULL) || (err == DLT_RETURN_ERROR))
3327 0 : dlt_log(LOG_WARNING, "NWTSegmented: Could not send end segment.\n");
3328 :
3329 : /* Free resources */
3330 0 : free(data->header);
3331 0 : free(data->payload);
3332 0 : free(data);
3333 : }
3334 :
3335 : pthread_cleanup_pop(1);
3336 : }
3337 :
3338 0 : void dlt_user_trace_network_segmented_thread_segmenter(s_segmented_data *data)
3339 : {
3340 : /* Segment the data and send the chunks */
3341 : void *ptr = NULL;
3342 : uint32_t offset = 0;
3343 : uint16_t sequence = 0;
3344 :
3345 : do {
3346 : uint16_t len = 0;
3347 :
3348 0 : if (offset + DLT_MAX_TRACE_SEGMENT_SIZE > data->payload_len)
3349 0 : len = (uint16_t) (data->payload_len - offset);
3350 : else
3351 : len = DLT_MAX_TRACE_SEGMENT_SIZE;
3352 :
3353 : /* If payload size aligns perfectly with segment size, avoid sending empty segment */
3354 0 : if (len == 0)
3355 : break;
3356 :
3357 0 : ptr = data->payload + offset;
3358 0 : DltReturnValue err = dlt_user_trace_network_segmented_segment(data->id,
3359 : data->handle,
3360 : data->nw_trace_type,
3361 0 : sequence++,
3362 : len,
3363 : ptr);
3364 :
3365 0 : if ((err == DLT_RETURN_BUFFER_FULL) || (err == DLT_RETURN_ERROR)) {
3366 0 : dlt_log(LOG_ERR, "NWTSegmented: Could not send segment. Aborting.\n");
3367 0 : break; /* loop */
3368 : }
3369 :
3370 0 : offset += len;
3371 0 : } while (ptr < data->payload + data->payload_len);
3372 0 : }
3373 :
3374 :
3375 7 : DltReturnValue dlt_user_trace_network_segmented(DltContext *handle,
3376 : DltNetworkTraceType nw_trace_type,
3377 : uint16_t header_len,
3378 : void *header,
3379 : uint16_t payload_len,
3380 : void *payload)
3381 : {
3382 : /* forbid dlt usage in child after fork */
3383 7 : if (g_dlt_is_child)
3384 : return DLT_RETURN_ERROR;
3385 :
3386 : /* Send as normal trace if possible */
3387 7 : if (header_len + payload_len + sizeof(uint16_t) < dlt_user.log_buf_len)
3388 7 : return dlt_user_trace_network(handle, nw_trace_type, header_len, header, payload_len, payload);
3389 :
3390 : /* Allocate Memory */
3391 0 : s_segmented_data *thread_data = malloc(sizeof(s_segmented_data));
3392 :
3393 0 : if (thread_data == NULL)
3394 : return DLT_RETURN_ERROR;
3395 :
3396 0 : thread_data->header = malloc(header_len);
3397 :
3398 0 : if (thread_data->header == NULL) {
3399 0 : free(thread_data);
3400 0 : return DLT_RETURN_ERROR;
3401 : }
3402 :
3403 0 : thread_data->payload = malloc(payload_len);
3404 :
3405 0 : if (thread_data->payload == NULL) {
3406 0 : free(thread_data->header);
3407 0 : free(thread_data);
3408 0 : return DLT_RETURN_ERROR;
3409 : }
3410 :
3411 : /* Copy data */
3412 0 : thread_data->handle = handle;
3413 0 : thread_data->nw_trace_type = nw_trace_type;
3414 0 : thread_data->header_len = header_len;
3415 : memcpy(thread_data->header, header, header_len);
3416 0 : thread_data->payload_len = payload_len;
3417 : memcpy(thread_data->payload, payload, payload_len);
3418 :
3419 : /* Send start message */
3420 0 : DltReturnValue err = dlt_user_trace_network_segmented_start(&(thread_data->id),
3421 : thread_data->handle,
3422 : thread_data->nw_trace_type,
3423 : (uint16_t) thread_data->header_len,
3424 : thread_data->header,
3425 : (uint16_t) thread_data->payload_len);
3426 :
3427 0 : if ((err == DLT_RETURN_BUFFER_FULL) || (err == DLT_RETURN_ERROR)) {
3428 0 : dlt_log(LOG_ERR, "NWTSegmented: Could not send start segment. Aborting.\n");
3429 0 : free(thread_data->header);
3430 0 : free(thread_data->payload);
3431 0 : free(thread_data);
3432 0 : return DLT_RETURN_ERROR;
3433 : }
3434 :
3435 : /* Open queue if it is not open */
3436 0 : if (dlt_init_message_queue() < 0) {
3437 0 : dlt_log(LOG_ERR, "NWTSegmented: Could not open queue.\n");
3438 0 : free(thread_data->header);
3439 0 : free(thread_data->payload);
3440 0 : free(thread_data);
3441 :
3442 0 : return DLT_RETURN_ERROR;
3443 : }
3444 :
3445 : /* Add to queue */
3446 0 : if (mq_send(dlt_user.dlt_segmented_queue_write_handle,
3447 : (char *)&thread_data, sizeof(s_segmented_data *), 1) < 0) {
3448 0 : if (errno == EAGAIN)
3449 0 : dlt_log(LOG_WARNING, "NWTSegmented: Queue full. Message discarded.\n");
3450 :
3451 0 : free(thread_data->header);
3452 0 : free(thread_data->payload);
3453 0 : free(thread_data);
3454 0 : dlt_vnlog(LOG_WARNING, 256, "NWTSegmented: Could not write into queue: %s \n", strerror(errno));
3455 0 : return DLT_RETURN_ERROR;
3456 : }
3457 :
3458 : /*thread_data will be freed by the receiver function */
3459 : /*coverity[leaked_storage] */
3460 : return DLT_RETURN_OK;
3461 : }
3462 :
3463 14 : DltReturnValue dlt_user_trace_network(DltContext *handle,
3464 : DltNetworkTraceType nw_trace_type,
3465 : uint16_t header_len,
3466 : void *header,
3467 : uint16_t payload_len,
3468 : void *payload)
3469 : {
3470 14 : return dlt_user_trace_network_truncated(handle, nw_trace_type, header_len, header, payload_len, payload, 1);
3471 : }
3472 :
3473 21 : DltReturnValue dlt_user_trace_network_truncated(DltContext *handle,
3474 : DltNetworkTraceType nw_trace_type,
3475 : uint16_t header_len,
3476 : void *header,
3477 : uint16_t payload_len,
3478 : void *payload,
3479 : int allow_truncate)
3480 : {
3481 : int ret = DLT_RETURN_ERROR;
3482 21 : DltContextData log = { 0 };
3483 :
3484 21 : if ((payload == NULL) && (payload_len > 0))
3485 : return DLT_RETURN_WRONG_PARAMETER;
3486 :
3487 15 : if ((nw_trace_type < DLT_NW_TRACE_IPC) || (nw_trace_type >= DLT_NW_TRACE_MAX)) {
3488 0 : dlt_vlog(LOG_ERR, "Network trace type %u is outside valid range", nw_trace_type);
3489 0 : return DLT_RETURN_WRONG_PARAMETER;
3490 : }
3491 :
3492 15 : if (dlt_user.dlt_ll_ts == NULL)
3493 : return DLT_RETURN_ERROR;
3494 :
3495 15 : if (handle->trace_status_ptr && (*(handle->trace_status_ptr) == DLT_TRACE_STATUS_ON)) {
3496 0 : if ((dlt_user_log_init(handle, &log) < DLT_RETURN_OK) || (dlt_user.dlt_ll_ts == NULL))
3497 : return DLT_RETURN_ERROR;
3498 :
3499 : /* initialize values */
3500 0 : if (log.buffer == NULL) {
3501 0 : log.buffer = calloc(sizeof(unsigned char), dlt_user.log_buf_len);
3502 :
3503 0 : if (log.buffer == NULL) {
3504 0 : dlt_vlog(LOG_ERR, "Cannot allocate buffer for DLT Log message\n");
3505 0 : return DLT_RETURN_ERROR;
3506 : }
3507 : }
3508 :
3509 0 : log.args_num = 0;
3510 0 : log.trace_status = nw_trace_type;
3511 0 : log.size = 0;
3512 :
3513 0 : if (header == NULL)
3514 : header_len = 0;
3515 :
3516 : /* If truncation is allowed, check if we must do it */
3517 0 : if ((allow_truncate > 0) && ((header_len + payload_len + sizeof(uint16_t)) > dlt_user.log_buf_len)) {
3518 : /* Identify as truncated */
3519 0 : if (dlt_user_log_write_string(&log, DLT_TRACE_NW_TRUNCATED) < DLT_RETURN_OK) {
3520 : dlt_user_free_buffer(&(log.buffer));
3521 0 : return DLT_RETURN_ERROR;
3522 : }
3523 :
3524 : /* Write header and its length */
3525 0 : if (dlt_user_log_write_raw(&log, header, header_len) < DLT_RETURN_OK) {
3526 : dlt_user_free_buffer(&(log.buffer));
3527 0 : return DLT_RETURN_ERROR;
3528 : }
3529 :
3530 : /* Write original size of payload */
3531 0 : if (dlt_user_log_write_uint32(&log, payload_len) < DLT_RETURN_OK) {
3532 : dlt_user_free_buffer(&(log.buffer));
3533 0 : return DLT_RETURN_ERROR;
3534 : }
3535 :
3536 : /**
3537 : * Calculate maximum available space in sending buffer after headers.
3538 : */
3539 :
3540 0 : uint16_t truncated_payload_len = (uint16_t) (dlt_user.log_buf_len - log.size - sizeof(uint16_t) - sizeof(uint32_t));
3541 :
3542 : /* Write truncated payload */
3543 0 : if (dlt_user_log_write_raw(&log, payload, truncated_payload_len) < DLT_RETURN_OK) {
3544 : dlt_user_free_buffer(&(log.buffer));
3545 0 : return DLT_RETURN_ERROR;
3546 : }
3547 : }
3548 : else { /* Truncation not allowed or data short enough */
3549 :
3550 : /* Write header and its length */
3551 0 : if (dlt_user_log_write_raw(&log, header, header_len) < DLT_RETURN_OK) {
3552 : dlt_user_free_buffer(&(log.buffer));
3553 0 : return DLT_RETURN_ERROR;
3554 : }
3555 :
3556 0 : if (payload == NULL)
3557 : payload_len = 0;
3558 :
3559 : /* Write payload and its length */
3560 0 : if (dlt_user_log_write_raw(&log, payload, payload_len) < DLT_RETURN_OK) {
3561 : dlt_user_free_buffer(&(log.buffer));
3562 0 : return DLT_RETURN_ERROR;
3563 : }
3564 : }
3565 :
3566 0 : ret = dlt_user_log_send_log(&log, DLT_TYPE_NW_TRACE, NULL);
3567 :
3568 : dlt_user_free_buffer(&(log.buffer));
3569 :
3570 : /* Send log */
3571 0 : return ret;
3572 : }
3573 :
3574 : return DLT_RETURN_OK;
3575 : }
3576 : #else /* DLT_NETWORK_TRACE_ENABLE not set */
3577 : DltReturnValue dlt_user_trace_network_segmented(DltContext *handle,
3578 : DltNetworkTraceType nw_trace_type,
3579 : uint16_t header_len,
3580 : void *header,
3581 : uint16_t payload_len,
3582 : void *payload)
3583 : {
3584 : /**
3585 : * vsomeip uses the DLT_TRACE_NETWORK_SEGMENTED macro that calls this function.
3586 : * It's not possible to rewrite this macro directly to a no-op,
3587 : * because the macro is used on vsomeip side and there our defines are not set.
3588 : * Add an empty function to the dlt-lib to avoid a broken build.
3589 : */
3590 : (void)handle;
3591 : (void)nw_trace_type;
3592 : (void)header_len;
3593 : (void)header;
3594 : (void)payload_len;
3595 : (void)payload;
3596 : return DLT_RETURN_LOGGING_DISABLED;
3597 : }
3598 :
3599 : DltReturnValue dlt_user_trace_network_truncated(DltContext *handle,
3600 : DltNetworkTraceType nw_trace_type,
3601 : uint16_t header_len,
3602 : void *header,
3603 : uint16_t payload_len,
3604 : void *payload,
3605 : int allow_truncate)
3606 : {
3607 : /**
3608 : * vsomeip uses the DLT_TRACE_NETWORK_TRUNCATED macro that calls this function.
3609 : * It's not possible to rewrite this macro directly to a no-op,
3610 : * because the macro is used on vsomeip side and there our defines are not set.
3611 : * Add an empty function to the dlt-lib to avoid a broken build.
3612 : */
3613 : (void)handle;
3614 : (void)nw_trace_type;
3615 : (void)header_len;
3616 : (void)header;
3617 : (void)payload_len;
3618 : (void)payload;
3619 : (void)allow_truncate;
3620 : return DLT_RETURN_LOGGING_DISABLED;
3621 : }
3622 :
3623 : #endif /* DLT_NETWORK_TRACE_ENABLE */
3624 :
3625 18 : DltReturnValue dlt_log_string(DltContext *handle, DltLogLevelType loglevel, const char *text)
3626 : {
3627 36 : if (!is_verbose_mode(dlt_user.verbose_mode, NULL))
3628 : return DLT_RETURN_ERROR;
3629 :
3630 18 : if ((handle == NULL) || (text == NULL))
3631 : return DLT_RETURN_WRONG_PARAMETER;
3632 :
3633 : DltReturnValue ret = DLT_RETURN_OK;
3634 : DltContextData log;
3635 :
3636 15 : if (dlt_user_log_write_start(handle, &log, loglevel) == DLT_RETURN_TRUE) {
3637 11 : ret = dlt_user_log_write_string(&log, text);
3638 :
3639 11 : if (dlt_user_log_write_finish(&log) < DLT_RETURN_OK)
3640 : ret = DLT_RETURN_ERROR;
3641 : }
3642 :
3643 : return ret;
3644 : }
3645 :
3646 25 : DltReturnValue dlt_log_string_int(DltContext *handle, DltLogLevelType loglevel, const char *text, int data)
3647 : {
3648 50 : if (!is_verbose_mode(dlt_user.verbose_mode, NULL))
3649 : return DLT_RETURN_ERROR;
3650 :
3651 25 : if ((handle == NULL) || (text == NULL))
3652 : return DLT_RETURN_WRONG_PARAMETER;
3653 :
3654 : DltReturnValue ret = DLT_RETURN_OK;
3655 : DltContextData log;
3656 :
3657 22 : if (dlt_user_log_write_start(handle, &log, loglevel) == DLT_RETURN_TRUE) {
3658 16 : ret = dlt_user_log_write_string(&log, text);
3659 16 : dlt_user_log_write_int(&log, data);
3660 :
3661 16 : if (dlt_user_log_write_finish(&log) < DLT_RETURN_OK)
3662 : ret = DLT_RETURN_ERROR;
3663 : }
3664 :
3665 : return ret;
3666 : }
3667 :
3668 25 : DltReturnValue dlt_log_string_uint(DltContext *handle, DltLogLevelType loglevel, const char *text, unsigned int data)
3669 : {
3670 50 : if (!is_verbose_mode(dlt_user.verbose_mode, NULL))
3671 : return DLT_RETURN_ERROR;
3672 :
3673 25 : if ((handle == NULL) || (text == NULL))
3674 : return DLT_RETURN_WRONG_PARAMETER;
3675 :
3676 : DltReturnValue ret = DLT_RETURN_OK;
3677 : DltContextData log;
3678 :
3679 22 : if (dlt_user_log_write_start(handle, &log, loglevel) == DLT_RETURN_TRUE) {
3680 16 : ret = dlt_user_log_write_string(&log, text);
3681 16 : dlt_user_log_write_uint(&log, data);
3682 :
3683 16 : if (dlt_user_log_write_finish(&log) < DLT_RETURN_OK)
3684 : ret = DLT_RETURN_ERROR;
3685 : }
3686 :
3687 : return ret;
3688 : }
3689 :
3690 22 : DltReturnValue dlt_log_int(DltContext *handle, DltLogLevelType loglevel, int data)
3691 : {
3692 44 : if (!is_verbose_mode(dlt_user.verbose_mode, NULL))
3693 : return DLT_RETURN_ERROR;
3694 :
3695 22 : if (handle == NULL)
3696 : return DLT_RETURN_ERROR;
3697 :
3698 : DltContextData log;
3699 :
3700 21 : if (dlt_user_log_write_start(handle, &log, loglevel) == DLT_RETURN_TRUE) {
3701 15 : dlt_user_log_write_int(&log, data);
3702 :
3703 15 : if (dlt_user_log_write_finish(&log) < DLT_RETURN_OK)
3704 : return DLT_RETURN_ERROR;
3705 : }
3706 :
3707 : return DLT_RETURN_OK;
3708 : }
3709 :
3710 22 : DltReturnValue dlt_log_uint(DltContext *handle, DltLogLevelType loglevel, unsigned int data)
3711 : {
3712 44 : if (!is_verbose_mode(dlt_user.verbose_mode, NULL))
3713 : return DLT_RETURN_ERROR;
3714 :
3715 22 : if (handle == NULL)
3716 : return DLT_RETURN_WRONG_PARAMETER;
3717 :
3718 : DltContextData log;
3719 :
3720 21 : if (dlt_user_log_write_start(handle, &log, loglevel) == DLT_RETURN_TRUE) {
3721 15 : dlt_user_log_write_uint(&log, data);
3722 :
3723 15 : if (dlt_user_log_write_finish(&log) < DLT_RETURN_OK)
3724 : return DLT_RETURN_ERROR;
3725 : }
3726 :
3727 : return DLT_RETURN_OK;
3728 : }
3729 :
3730 11 : DltReturnValue dlt_log_raw(DltContext *handle, DltLogLevelType loglevel, void *data, uint16_t length)
3731 : {
3732 22 : if (!is_verbose_mode(dlt_user.verbose_mode, NULL))
3733 : return DLT_RETURN_ERROR;
3734 :
3735 11 : if (handle == NULL)
3736 : return DLT_RETURN_WRONG_PARAMETER;
3737 :
3738 : DltContextData log;
3739 : DltReturnValue ret = DLT_RETURN_OK;
3740 :
3741 9 : if (dlt_user_log_write_start(handle, &log, loglevel) > 0) {
3742 7 : if ((ret = dlt_user_log_write_raw(&log, data, length)) < DLT_RETURN_OK) {
3743 : dlt_user_free_buffer(&(log.buffer));
3744 2 : return ret;
3745 : }
3746 :
3747 5 : if (dlt_user_log_write_finish(&log) < DLT_RETURN_OK)
3748 : return DLT_RETURN_ERROR;
3749 : }
3750 :
3751 : return DLT_RETURN_OK;
3752 : }
3753 :
3754 1 : DltReturnValue dlt_log_marker()
3755 : {
3756 1 : if (!DLT_USER_INITIALIZED) {
3757 0 : if (dlt_init() < DLT_RETURN_OK) {
3758 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
3759 0 : return DLT_RETURN_ERROR;
3760 : }
3761 : }
3762 :
3763 1 : return dlt_user_log_send_marker();
3764 : }
3765 :
3766 10 : DltReturnValue dlt_verbose_mode(void)
3767 : {
3768 10 : if (!DLT_USER_INITIALIZED) {
3769 0 : if (dlt_init() < DLT_RETURN_OK) {
3770 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
3771 0 : return DLT_RETURN_ERROR;
3772 : }
3773 : }
3774 :
3775 : /* Switch to verbose mode */
3776 10 : dlt_user.verbose_mode = 1;
3777 :
3778 10 : return DLT_RETURN_OK;
3779 : }
3780 :
3781 10 : DltReturnValue dlt_nonverbose_mode(void)
3782 : {
3783 10 : if (!DLT_USER_INITIALIZED) {
3784 0 : if (dlt_init() < DLT_RETURN_OK) {
3785 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
3786 0 : return DLT_RETURN_ERROR;
3787 : }
3788 : }
3789 :
3790 : /* Switch to non-verbose mode */
3791 10 : dlt_user.verbose_mode = 0;
3792 :
3793 10 : return DLT_RETURN_OK;
3794 : }
3795 :
3796 2 : DltReturnValue dlt_use_extended_header_for_non_verbose(int8_t use_extended_header_for_non_verbose)
3797 : {
3798 2 : if (!DLT_USER_INITIALIZED) {
3799 0 : if (dlt_init() < DLT_RETURN_OK) {
3800 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
3801 0 : return DLT_RETURN_ERROR;
3802 : }
3803 : }
3804 :
3805 : /* Set use_extended_header_for_non_verbose */
3806 2 : dlt_user.use_extended_header_for_non_verbose = use_extended_header_for_non_verbose;
3807 :
3808 2 : return DLT_RETURN_OK;
3809 : }
3810 :
3811 0 : DltReturnValue dlt_with_session_id(int8_t with_session_id)
3812 : {
3813 0 : if (!DLT_USER_INITIALIZED) {
3814 0 : if (dlt_init() < DLT_RETURN_OK) {
3815 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
3816 0 : return DLT_RETURN_ERROR;
3817 : }
3818 : }
3819 :
3820 : /* Set use_extended_header_for_non_verbose */
3821 0 : dlt_user.with_session_id = with_session_id;
3822 :
3823 0 : return DLT_RETURN_OK;
3824 : }
3825 :
3826 0 : DltReturnValue dlt_with_timestamp(int8_t with_timestamp)
3827 : {
3828 0 : if (!DLT_USER_INITIALIZED) {
3829 0 : if (dlt_init() < DLT_RETURN_OK) {
3830 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
3831 0 : return DLT_RETURN_ERROR;
3832 : }
3833 : }
3834 :
3835 : /* Set with_timestamp */
3836 0 : dlt_user.with_timestamp = with_timestamp;
3837 :
3838 0 : return DLT_RETURN_OK;
3839 : }
3840 :
3841 0 : DltReturnValue dlt_with_ecu_id(int8_t with_ecu_id)
3842 : {
3843 0 : if (!DLT_USER_INITIALIZED) {
3844 0 : if (dlt_init() < DLT_RETURN_OK) {
3845 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
3846 0 : return DLT_RETURN_ERROR;
3847 : }
3848 : }
3849 :
3850 : /* Set with_timestamp */
3851 0 : dlt_user.with_ecu_id = with_ecu_id;
3852 :
3853 0 : return DLT_RETURN_OK;
3854 : }
3855 :
3856 0 : DltReturnValue dlt_enable_local_print(void)
3857 : {
3858 0 : if (!DLT_USER_INITIALIZED) {
3859 0 : if (dlt_init() < DLT_RETURN_OK) {
3860 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
3861 0 : return DLT_RETURN_ERROR;
3862 : }
3863 : }
3864 :
3865 0 : dlt_user.enable_local_print = 1;
3866 :
3867 0 : return DLT_RETURN_OK;
3868 : }
3869 :
3870 0 : DltReturnValue dlt_disable_local_print(void)
3871 : {
3872 0 : if (!DLT_USER_INITIALIZED) {
3873 0 : if (dlt_init() < DLT_RETURN_OK) {
3874 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
3875 0 : return DLT_RETURN_ERROR;
3876 : }
3877 : }
3878 :
3879 0 : dlt_user.enable_local_print = 0;
3880 :
3881 0 : return DLT_RETURN_OK;
3882 : }
3883 :
3884 : /* Cleanup on thread cancellation, thread may hold lock release it here */
3885 45034 : static void dlt_user_cleanup_handler(void *arg)
3886 : {
3887 : DLT_UNUSED(arg); /* Satisfy compiler */
3888 :
3889 : #ifdef DLT_NETWORK_TRACE_ENABLE
3890 : /* Unlock the message queue */
3891 45034 : dlt_unlock_mutex(&mq_mutex);
3892 : #endif
3893 : /* unlock DLT (dlt_mutex) */
3894 45034 : dlt_mutex_free();
3895 45034 : }
3896 :
3897 22517 : void dlt_user_housekeeperthread_function(void *ptr)
3898 : {
3899 : struct timespec ts;
3900 : bool in_loop = true;
3901 : int signal_status = 0;
3902 : atomic_bool* dlt_housekeeper_running = (atomic_bool*)ptr;
3903 :
3904 : #ifdef __ANDROID_API__
3905 : sigset_t set;
3906 : sigset_t pset;
3907 : /*
3908 : * bionic is not supporting pthread_cancel so
3909 : * use SIGUSR1 to kill thread properly.
3910 : */
3911 : sigemptyset(&set);
3912 : sigaddset(&set, SIGUSR1);
3913 : if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
3914 : dlt_vlog(LOG_ERR, "Failed to block signal with error [%s]\n",
3915 : strerror(errno));
3916 : in_loop = false;
3917 : }
3918 : #endif
3919 :
3920 : #ifdef DLT_USE_PTHREAD_SETNAME_NP
3921 22517 : if (pthread_setname_np(dlt_housekeeperthread_handle, "dlt_housekeeper"))
3922 0 : dlt_log(LOG_WARNING, "Failed to rename housekeeper thread!\n");
3923 : #elif linux
3924 : if (prctl(PR_SET_NAME, "dlt_housekeeper", 0, 0, 0) < 0)
3925 : dlt_log(LOG_WARNING, "Failed to rename housekeeper thread!\n");
3926 : #endif
3927 :
3928 45034 : pthread_cleanup_push(dlt_user_cleanup_handler, NULL);
3929 :
3930 :
3931 22517 : pthread_mutex_lock(&dlt_housekeeper_running_mutex);
3932 :
3933 : // signal dlt thread to be running
3934 22517 : *dlt_housekeeper_running = true;
3935 22517 : signal_status = pthread_cond_signal(&dlt_housekeeper_running_cond);
3936 22517 : if (signal_status != 0) {
3937 0 : dlt_log(LOG_CRIT, "Housekeeper thread failed to signal running state\n");
3938 : }
3939 :
3940 22517 : pthread_mutex_unlock(&dlt_housekeeper_running_mutex);
3941 :
3942 : while (in_loop) {
3943 : /* Check for new messages from DLT daemon */
3944 22533 : if (!dlt_user.disable_injection_msg)
3945 22533 : if (dlt_user_log_check_user_message() < DLT_RETURN_OK)
3946 : /* Critical error */
3947 0 : dlt_log(LOG_CRIT, "Housekeeper thread encountered error condition\n");
3948 :
3949 : /* Reattach to daemon if neccesary */
3950 21 : dlt_user_log_reattach_to_daemon();
3951 :
3952 : /* flush buffer to DLT daemon if possible */
3953 21 : if (dlt_user.dlt_log_handle != DLT_FD_INIT)
3954 10 : dlt_user_log_resend_buffer();
3955 :
3956 : #ifdef __ANDROID_API__
3957 : if (sigpending(&pset)) {
3958 : dlt_vlog(LOG_ERR, "sigpending failed with error [%s]!\n", strerror(errno));
3959 : break;
3960 : }
3961 :
3962 : if (sigismember(&pset, SIGUSR1)) {
3963 : dlt_log(LOG_NOTICE, "Received SIGUSR1! Stop thread\n");
3964 : break;
3965 : }
3966 : #endif
3967 :
3968 : /* delay */
3969 21 : ts.tv_sec = 0;
3970 21 : ts.tv_nsec = DLT_USER_RECEIVE_NDELAY;
3971 21 : nanosleep(&ts, NULL);
3972 : }
3973 :
3974 : pthread_cleanup_pop(1);
3975 : }
3976 :
3977 : /* Private functions of user library */
3978 :
3979 6411 : DltReturnValue dlt_user_log_init(DltContext *handle, DltContextData *log)
3980 : {
3981 : int ret = DLT_RETURN_OK;
3982 :
3983 6411 : if ((handle == NULL) || (log == NULL))
3984 : return DLT_RETURN_WRONG_PARAMETER;
3985 :
3986 6411 : if (!DLT_USER_INITIALIZED) {
3987 0 : ret = dlt_init();
3988 :
3989 0 : if (ret < DLT_RETURN_OK) {
3990 0 : if (ret != DLT_RETURN_LOGGING_DISABLED)
3991 0 : dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
3992 :
3993 0 : return ret;
3994 : }
3995 : }
3996 :
3997 6411 : log->handle = handle;
3998 6411 : log->buffer = NULL;
3999 6411 : return ret;
4000 : }
4001 :
4002 6008 : DltReturnValue dlt_user_log_send_log(DltContextData *log, const int mtype, int *const sent_size)
4003 : {
4004 : DltMessage msg;
4005 : DltUserHeader userheader;
4006 : int32_t len;
4007 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
4008 : uint32_t time_stamp;
4009 : #else
4010 : // shut up warning
4011 : (void)sent_size;
4012 : #endif
4013 :
4014 : DltReturnValue ret = DLT_RETURN_OK;
4015 :
4016 6008 : if (!DLT_USER_INITIALIZED_NOT_FREEING) {
4017 0 : dlt_vlog(LOG_WARNING, "%s dlt_user_init_state=%i (expected INIT_DONE), dlt_user_freeing=%i\n", __FUNCTION__, dlt_user_init_state, dlt_user_freeing);
4018 0 : return DLT_RETURN_ERROR;
4019 : }
4020 :
4021 6008 : dlt_mutex_lock();
4022 6008 : if ((log == NULL) ||
4023 6008 : (log->handle == NULL) ||
4024 5999 : (log->handle->contextID[0] == '\0') ||
4025 5999 : (mtype < DLT_TYPE_LOG) || (mtype > DLT_TYPE_CONTROL)
4026 : ) {
4027 9 : dlt_mutex_free();
4028 9 : return DLT_RETURN_WRONG_PARAMETER;
4029 : }
4030 :
4031 : /* also for Trace messages */
4032 5999 : if (dlt_user_set_userheader(&userheader, DLT_USER_MESSAGE_LOG) < DLT_RETURN_OK) {
4033 0 : dlt_mutex_free();
4034 0 : return DLT_RETURN_ERROR;
4035 : }
4036 :
4037 5999 : if (dlt_message_init(&msg, 0) == DLT_RETURN_ERROR) {
4038 0 : dlt_mutex_free();
4039 0 : return DLT_RETURN_ERROR;
4040 : }
4041 :
4042 5999 : msg.storageheader = (DltStorageHeader *)msg.headerbuffer;
4043 :
4044 5999 : if (dlt_set_storageheader(msg.storageheader, dlt_user.ecuID) == DLT_RETURN_ERROR) {
4045 0 : dlt_mutex_free();
4046 0 : return DLT_RETURN_ERROR;
4047 : }
4048 :
4049 5999 : msg.standardheader = (DltStandardHeader *)(msg.headerbuffer + sizeof(DltStorageHeader));
4050 5999 : msg.standardheader->htyp = DLT_HTYP_PROTOCOL_VERSION1;
4051 :
4052 : /* send ecu id */
4053 5999 : if (dlt_user.with_ecu_id)
4054 5999 : msg.standardheader->htyp |= DLT_HTYP_WEID;
4055 :
4056 : /* send timestamp */
4057 5999 : if (dlt_user.with_timestamp)
4058 5999 : msg.standardheader->htyp |= DLT_HTYP_WTMS;
4059 :
4060 : /* send session id */
4061 5999 : if (dlt_user.with_session_id) {
4062 5999 : msg.standardheader->htyp |= DLT_HTYP_WSID;
4063 5999 : if (__builtin_expect(!!(dlt_user.local_pid == -1), false)) {
4064 19 : dlt_user.local_pid = getpid();
4065 : }
4066 5999 : msg.headerextra.seid = (uint32_t) dlt_user.local_pid;
4067 : }
4068 :
4069 5999 : if (is_verbose_mode(dlt_user.verbose_mode, log))
4070 : /* In verbose mode, send extended header */
4071 5996 : msg.standardheader->htyp = (msg.standardheader->htyp | DLT_HTYP_UEH);
4072 : else
4073 : /* In non-verbose, send extended header if desired */
4074 3 : if (dlt_user.use_extended_header_for_non_verbose)
4075 2 : msg.standardheader->htyp = (msg.standardheader->htyp | DLT_HTYP_UEH);
4076 :
4077 : #if (BYTE_ORDER == BIG_ENDIAN)
4078 : msg.standardheader->htyp = (msg.standardheader->htyp | DLT_HTYP_MSBF);
4079 : #endif
4080 :
4081 5999 : msg.standardheader->mcnt = log->handle->mcnt++;
4082 :
4083 : /* Set header extra parameters */
4084 5999 : dlt_set_id(msg.headerextra.ecu, dlt_user.ecuID);
4085 :
4086 : /*msg.headerextra.seid = 0; */
4087 5999 : if (log->use_timestamp == DLT_AUTO_TIMESTAMP) {
4088 5998 : msg.headerextra.tmsp = dlt_uptime();
4089 : }
4090 : else {
4091 1 : msg.headerextra.tmsp = log->user_timestamp;
4092 : }
4093 :
4094 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
4095 : time_stamp = msg.headerextra.tmsp;
4096 : #endif
4097 :
4098 5999 : if (dlt_message_set_extraparameters(&msg, 0) == DLT_RETURN_ERROR) {
4099 0 : dlt_mutex_free();
4100 0 : return DLT_RETURN_ERROR;
4101 : }
4102 :
4103 : /* Fill out extended header, if extended header should be provided */
4104 5999 : if (DLT_IS_HTYP_UEH(msg.standardheader->htyp)) {
4105 : /* with extended header */
4106 5998 : msg.extendedheader =
4107 5998 : (DltExtendedHeader *)(msg.headerbuffer + sizeof(DltStorageHeader) + sizeof(DltStandardHeader) +
4108 5998 : DLT_STANDARD_HEADER_EXTRA_SIZE(msg.standardheader->htyp));
4109 :
4110 5998 : switch (mtype) {
4111 5998 : case DLT_TYPE_LOG:
4112 : {
4113 5998 : msg.extendedheader->msin = (uint8_t) (DLT_TYPE_LOG << DLT_MSIN_MSTP_SHIFT |
4114 5998 : ((log->log_level << DLT_MSIN_MTIN_SHIFT) & DLT_MSIN_MTIN));
4115 5998 : break;
4116 : }
4117 0 : case DLT_TYPE_NW_TRACE:
4118 : {
4119 0 : msg.extendedheader->msin = (uint8_t) (DLT_TYPE_NW_TRACE << DLT_MSIN_MSTP_SHIFT |
4120 0 : ((log->trace_status << DLT_MSIN_MTIN_SHIFT) & DLT_MSIN_MTIN));
4121 0 : break;
4122 : }
4123 0 : default:
4124 : {
4125 : /* This case should not occur */
4126 0 : dlt_mutex_free();
4127 0 : return DLT_RETURN_ERROR;
4128 : break;
4129 : }
4130 : }
4131 :
4132 : /* If in verbose mode, set flag in header for verbose mode */
4133 5998 : if (is_verbose_mode(dlt_user.verbose_mode, log))
4134 5996 : msg.extendedheader->msin |= DLT_MSIN_VERB;
4135 :
4136 5998 : msg.extendedheader->noar = (uint8_t) log->args_num; /* number of arguments */
4137 5998 : dlt_set_id(msg.extendedheader->apid, dlt_user.appID); /* application id */
4138 5998 : dlt_set_id(msg.extendedheader->ctid, log->handle->contextID); /* context id */
4139 :
4140 5998 : msg.headersize = (uint32_t) (sizeof(DltStorageHeader) + sizeof(DltStandardHeader) + sizeof(DltExtendedHeader) +
4141 5998 : DLT_STANDARD_HEADER_EXTRA_SIZE(msg.standardheader->htyp));
4142 : }
4143 : else {
4144 : /* without extended header */
4145 1 : msg.headersize = (uint32_t) (sizeof(DltStorageHeader) + sizeof(DltStandardHeader) + DLT_STANDARD_HEADER_EXTRA_SIZE(
4146 : msg.standardheader->htyp));
4147 : }
4148 :
4149 5999 : len = (int32_t) (msg.headersize - sizeof(DltStorageHeader) + log->size);
4150 :
4151 5999 : if (len > UINT16_MAX) {
4152 0 : dlt_log(LOG_WARNING, "Huge message discarded!\n");
4153 0 : dlt_mutex_free();
4154 0 : return DLT_RETURN_ERROR;
4155 : }
4156 :
4157 5999 : msg.standardheader->len = DLT_HTOBE_16(len);
4158 :
4159 : /* print to std out, if enabled */
4160 5999 : if ((dlt_user.local_print_mode != DLT_PM_FORCE_OFF) &&
4161 : (dlt_user.local_print_mode != DLT_PM_AUTOMATIC)) {
4162 5999 : if ((dlt_user.enable_local_print) || (dlt_user.local_print_mode == DLT_PM_FORCE_ON))
4163 0 : if (dlt_user_print_msg(&msg, log) == DLT_RETURN_ERROR) {
4164 0 : dlt_mutex_free();
4165 0 : return DLT_RETURN_ERROR;
4166 : }
4167 : }
4168 :
4169 5999 : if (dlt_user.dlt_is_file) {
4170 0 : if (dlt_user_file_reach_max) {
4171 0 : dlt_mutex_free();
4172 0 : return DLT_RETURN_FILESZERR;
4173 : }
4174 : else {
4175 : /* Get file size */
4176 : struct stat st;
4177 0 : if(fstat(dlt_user.dlt_log_handle, &st) != 0) {
4178 0 : dlt_vlog(LOG_WARNING,
4179 0 : "%s: Cannot get file information (errno=%d)\n", __func__, errno);
4180 0 : dlt_mutex_free();
4181 0 : return DLT_RETURN_ERROR;
4182 : }
4183 :
4184 0 : dlt_vlog(LOG_DEBUG, "%s: Current file size=[%ld]\n", __func__,
4185 : st.st_size);
4186 : /* Check filesize */
4187 : /* Return error if the file size has reached to maximum */
4188 0 : unsigned int msg_size = st.st_size + (unsigned int) msg.headersize +
4189 0 : (unsigned int) log->size;
4190 0 : if (msg_size > dlt_user.filesize_max) {
4191 0 : dlt_user_file_reach_max = true;
4192 0 : dlt_vlog(LOG_ERR,
4193 : "%s: File size (%ld bytes) reached to defined maximum size (%d bytes)\n",
4194 : __func__, st.st_size, dlt_user.filesize_max);
4195 0 : dlt_mutex_free();
4196 0 : return DLT_RETURN_FILESZERR;
4197 : }
4198 : else {
4199 : /* log to file */
4200 0 : ret = dlt_user_log_out2(dlt_user.dlt_log_handle,
4201 : msg.headerbuffer, msg.headersize,
4202 0 : log->buffer, log->size);
4203 0 : dlt_mutex_free();
4204 0 : return ret;
4205 : }
4206 : }
4207 : } else {
4208 5999 : if (dlt_user.overflow_counter) {
4209 0 : if (dlt_user_log_send_overflow() == DLT_RETURN_OK) {
4210 0 : dlt_vnlog(LOG_WARNING, DLT_USER_BUFFER_LENGTH, "%u messages discarded!\n", dlt_user.overflow_counter);
4211 0 : dlt_user.overflow_counter = 0;
4212 : }
4213 : }
4214 :
4215 : /* try to resent old data first */
4216 : ret = DLT_RETURN_OK;
4217 :
4218 5999 : if ((dlt_user.dlt_log_handle != -1) && (dlt_user.appID[0] != '\0')) {
4219 5812 : dlt_mutex_lock();
4220 5812 : ret = dlt_user_log_resend_buffer();
4221 5812 : dlt_mutex_free();
4222 : }
4223 :
4224 5999 : if ((ret == DLT_RETURN_OK) && (dlt_user.appID[0] != '\0')) {
4225 : /* resend ok or nothing to resent */
4226 : #ifdef DLT_SHM_ENABLE
4227 :
4228 : if (dlt_user.dlt_log_handle != -1)
4229 : dlt_shm_push(&dlt_user.dlt_shm, msg.headerbuffer + sizeof(DltStorageHeader),
4230 : msg.headersize - sizeof(DltStorageHeader),
4231 : log->buffer, log->size, 0, 0);
4232 :
4233 : ret = dlt_user_log_out3(dlt_user.dlt_log_handle,
4234 : &(userheader), sizeof(DltUserHeader),
4235 : 0, 0,
4236 : 0, 0);
4237 : #else
4238 : # ifdef DLT_TEST_ENABLE
4239 :
4240 : if (dlt_user.corrupt_user_header) {
4241 : userheader.pattern[0] = (char) 0xff;
4242 : userheader.pattern[1] = (char) 0xff;
4243 : userheader.pattern[2] = (char) 0xff;
4244 : userheader.pattern[3] = (char) 0xff;
4245 : }
4246 :
4247 : if (dlt_user.corrupt_message_size)
4248 : msg.standardheader->len = DLT_HTOBE_16(dlt_user.corrupt_message_size_size);
4249 :
4250 : # endif
4251 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
4252 : /* Check trace load before output */
4253 : if (!sent_size)
4254 : {
4255 : int pos = log->handle->log_level_pos;
4256 : char ctxid[DLT_ID_SIZE];
4257 : memcpy(ctxid, log->handle->contextID, DLT_ID_SIZE);
4258 :
4259 : if ((uint32_t)pos > dlt_user.dlt_ll_ts_num_entries) {
4260 : char msg[255];
4261 : sprintf(msg, "log handle has invalid log level pos %d, current entries: %u, dropping message\n",
4262 : log->handle->log_level_pos, dlt_user.dlt_ll_ts_num_entries);
4263 : dlt_mutex_free();
4264 : dlt_user_output_internal_msg(LOG_ERR, msg, NULL);
4265 : return DLT_RETURN_ERROR;
4266 : }
4267 : dlt_mutex_free();
4268 :
4269 : pthread_rwlock_rdlock(&trace_load_rw_lock);
4270 : DltTraceLoadSettings *computed_settings = dlt_find_runtime_trace_load_settings(
4271 : trace_load_settings, trace_load_settings_count, dlt_user.appID, ctxid);
4272 : pthread_rwlock_unlock(&trace_load_rw_lock);
4273 :
4274 : dlt_mutex_lock();
4275 : if ((uint32_t)pos < dlt_user.dlt_ll_ts_num_entries) {
4276 : dlt_ll_ts_type* ll_ts = &dlt_user.dlt_ll_ts[pos];
4277 : if (ll_ts->trace_load_settings == NULL) {
4278 : ll_ts->trace_load_settings = computed_settings;
4279 : }
4280 : }
4281 : dlt_mutex_free();
4282 : const bool trace_load_in_limits = dlt_check_trace_load(
4283 : computed_settings,
4284 : log->log_level,
4285 : time_stamp,
4286 : sizeof(DltUserHeader)
4287 : + msg.headersize - sizeof(DltStorageHeader)
4288 : + log->size,
4289 : dlt_user_output_internal_msg,
4290 : NULL);
4291 :
4292 : if (!trace_load_in_limits){
4293 : return DLT_RETURN_LOAD_EXCEEDED;
4294 : }
4295 : dlt_mutex_lock();
4296 : }
4297 : else
4298 : {
4299 : *sent_size = (sizeof(DltUserHeader) + msg.headersize - sizeof(DltStorageHeader) + log->size);
4300 : }
4301 : #endif
4302 :
4303 5998 : ret = dlt_user_log_out3(dlt_user.dlt_log_handle,
4304 : &(userheader), sizeof(DltUserHeader),
4305 : msg.headerbuffer + sizeof(DltStorageHeader),
4306 5998 : msg.headersize - sizeof(DltStorageHeader),
4307 5998 : log->buffer, log->size);
4308 : #endif
4309 : }
4310 :
4311 : DltReturnValue process_error_ret = DLT_RETURN_OK;
4312 : /* store message in ringbuffer, if an error has occurred */
4313 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
4314 : if (((ret!=DLT_RETURN_OK) || (dlt_user.appID[0] == '\0')) && !sent_size)
4315 : #else
4316 5998 : if ((ret != DLT_RETURN_OK) || (dlt_user.appID[0] == '\0'))
4317 : #endif
4318 189 : process_error_ret = dlt_user_log_out_error_handling(&(userheader),
4319 : sizeof(DltUserHeader),
4320 : msg.headerbuffer + sizeof(DltStorageHeader),
4321 189 : msg.headersize - sizeof(DltStorageHeader),
4322 189 : log->buffer,
4323 189 : log->size);
4324 :
4325 189 : if (process_error_ret == DLT_RETURN_OK) {
4326 5999 : dlt_mutex_free();
4327 5999 : return DLT_RETURN_OK;
4328 : }
4329 0 : if (process_error_ret == DLT_RETURN_BUFFER_FULL) {
4330 : /* Buffer full */
4331 0 : dlt_user.overflow_counter += 1;
4332 0 : dlt_mutex_free();
4333 0 : return DLT_RETURN_BUFFER_FULL;
4334 : }
4335 :
4336 : /* handle return value of function dlt_user_log_out3() when process_error_ret < 0*/
4337 0 : switch (ret) {
4338 0 : case DLT_RETURN_PIPE_FULL:
4339 : {
4340 : /* data could not be written */
4341 0 : dlt_mutex_free();
4342 0 : return DLT_RETURN_PIPE_FULL;
4343 : }
4344 0 : case DLT_RETURN_PIPE_ERROR:
4345 : {
4346 : /* handle not open or pipe error */
4347 0 : close(dlt_user.dlt_log_handle);
4348 0 : dlt_user.dlt_log_handle = -1;
4349 : #if defined DLT_LIB_USE_UNIX_SOCKET_IPC || defined DLT_LIB_USE_VSOCK_IPC
4350 : dlt_user.connection_state = DLT_USER_RETRY_CONNECT;
4351 : #endif
4352 :
4353 : #ifdef DLT_SHM_ENABLE
4354 : /* free shared memory */
4355 : dlt_shm_free_client(&dlt_user.dlt_shm);
4356 : #endif
4357 :
4358 0 : if (dlt_user.local_print_mode == DLT_PM_AUTOMATIC)
4359 0 : dlt_user_print_msg(&msg, log);
4360 :
4361 0 : dlt_mutex_free();
4362 0 : return DLT_RETURN_PIPE_ERROR;
4363 : }
4364 0 : case DLT_RETURN_ERROR:
4365 : {
4366 : /* other error condition */
4367 0 : dlt_mutex_free();
4368 0 : return DLT_RETURN_ERROR;
4369 : }
4370 0 : case DLT_RETURN_OK:
4371 : {
4372 0 : dlt_mutex_free();
4373 0 : return DLT_RETURN_OK;
4374 : }
4375 0 : default:
4376 : {
4377 : /* This case should never occur. */
4378 0 : dlt_mutex_free();
4379 0 : return DLT_RETURN_ERROR;
4380 : }
4381 : }
4382 : }
4383 :
4384 : dlt_mutex_free();
4385 : return DLT_RETURN_OK;
4386 : }
4387 :
4388 171 : DltReturnValue dlt_user_log_send_register_application(void)
4389 : {
4390 : DltUserHeader userheader;
4391 : DltUserControlMsgRegisterApplication usercontext;
4392 :
4393 : DltReturnValue ret;
4394 :
4395 171 : if (dlt_user.appID[0] == '\0')
4396 : return DLT_RETURN_ERROR;
4397 :
4398 : /* set userheader */
4399 171 : if (dlt_user_set_userheader(&userheader, DLT_USER_MESSAGE_REGISTER_APPLICATION) < DLT_RETURN_OK)
4400 : return DLT_RETURN_ERROR;
4401 :
4402 : /* set usercontext */
4403 171 : dlt_set_id(usercontext.apid, dlt_user.appID); /* application id */
4404 171 : usercontext.pid = getpid();
4405 :
4406 171 : if (dlt_user.application_description != NULL)
4407 171 : usercontext.description_length = (uint32_t) strlen(dlt_user.application_description);
4408 : else
4409 0 : usercontext.description_length = 0;
4410 :
4411 171 : if (dlt_user.dlt_is_file)
4412 : return DLT_RETURN_OK;
4413 :
4414 171 : ret = dlt_user_log_out3(dlt_user.dlt_log_handle,
4415 : &(userheader), sizeof(DltUserHeader),
4416 : &(usercontext), sizeof(DltUserControlMsgRegisterApplication),
4417 171 : dlt_user.application_description, usercontext.description_length);
4418 :
4419 : /* store message in ringbuffer, if an error has occured */
4420 171 : if (ret < DLT_RETURN_OK)
4421 164 : return dlt_user_log_out_error_handling(&(userheader),
4422 : sizeof(DltUserHeader),
4423 : &(usercontext),
4424 : sizeof(DltUserControlMsgRegisterApplication),
4425 164 : dlt_user.application_description,
4426 164 : usercontext.description_length);
4427 :
4428 : return DLT_RETURN_OK;
4429 : }
4430 :
4431 181 : DltReturnValue dlt_user_log_send_unregister_application(void)
4432 : {
4433 : DltUserHeader userheader;
4434 : DltUserControlMsgUnregisterApplication usercontext;
4435 : DltReturnValue ret = DLT_RETURN_OK;
4436 :
4437 181 : if (dlt_user.appID[0] == '\0')
4438 : return DLT_RETURN_ERROR;
4439 :
4440 : /* set userheader */
4441 172 : if (dlt_user_set_userheader(&userheader, DLT_USER_MESSAGE_UNREGISTER_APPLICATION) < DLT_RETURN_OK)
4442 : return DLT_RETURN_ERROR;
4443 :
4444 : /* set usercontext */
4445 172 : dlt_set_id(usercontext.apid, dlt_user.appID); /* application id */
4446 172 : usercontext.pid = getpid();
4447 :
4448 172 : if (dlt_user.dlt_is_file)
4449 : return DLT_RETURN_OK;
4450 :
4451 172 : ret = dlt_user_log_out2(dlt_user.dlt_log_handle,
4452 : &(userheader), sizeof(DltUserHeader),
4453 : &(usercontext), sizeof(DltUserControlMsgUnregisterApplication));
4454 :
4455 : /* store message in ringbuffer, if an error has occured */
4456 172 : if (ret < DLT_RETURN_OK)
4457 166 : return dlt_user_log_out_error_handling(&(userheader),
4458 : sizeof(DltUserHeader),
4459 : &(usercontext),
4460 : sizeof(DltUserControlMsgUnregisterApplication),
4461 : NULL,
4462 : 0);
4463 :
4464 : return DLT_RETURN_OK;
4465 : }
4466 :
4467 205 : DltReturnValue dlt_user_log_send_register_context(DltContextData *log)
4468 : {
4469 : DltUserHeader userheader;
4470 : DltUserControlMsgRegisterContext usercontext;
4471 : DltReturnValue ret = DLT_RETURN_ERROR;
4472 :
4473 205 : if (log == NULL)
4474 : return DLT_RETURN_WRONG_PARAMETER;
4475 :
4476 205 : if (log->handle == NULL)
4477 : return DLT_RETURN_ERROR;
4478 :
4479 205 : if (log->handle->contextID[0] == '\0')
4480 : return DLT_RETURN_ERROR;
4481 :
4482 : /* set userheader */
4483 205 : if (dlt_user_set_userheader(&userheader, DLT_USER_MESSAGE_REGISTER_CONTEXT) < DLT_RETURN_OK)
4484 : return DLT_RETURN_ERROR;
4485 :
4486 : /* set usercontext */
4487 205 : dlt_set_id(usercontext.apid, dlt_user.appID); /* application id */
4488 205 : dlt_set_id(usercontext.ctid, log->handle->contextID); /* context id */
4489 205 : usercontext.log_level_pos = log->handle->log_level_pos;
4490 205 : usercontext.pid = getpid();
4491 :
4492 205 : usercontext.log_level = (int8_t) log->log_level;
4493 205 : usercontext.trace_status = (int8_t) log->trace_status;
4494 :
4495 205 : if (log->context_description != NULL)
4496 205 : usercontext.description_length = (uint32_t) strlen(log->context_description);
4497 : else
4498 0 : usercontext.description_length = 0;
4499 :
4500 205 : if (dlt_user.dlt_is_file)
4501 : return DLT_RETURN_OK;
4502 :
4503 205 : if (dlt_user.appID[0] != '\0')
4504 : ret =
4505 205 : dlt_user_log_out3(dlt_user.dlt_log_handle,
4506 : &(userheader),
4507 : sizeof(DltUserHeader),
4508 : &(usercontext),
4509 : sizeof(DltUserControlMsgRegisterContext),
4510 : log->context_description,
4511 205 : usercontext.description_length);
4512 :
4513 : /* store message in ringbuffer, if an error has occured */
4514 205 : if ((ret != DLT_RETURN_OK) || (dlt_user.appID[0] == '\0'))
4515 167 : return dlt_user_log_out_error_handling(&(userheader),
4516 : sizeof(DltUserHeader),
4517 : &(usercontext),
4518 : sizeof(DltUserControlMsgRegisterContext),
4519 167 : log->context_description,
4520 167 : usercontext.description_length);
4521 :
4522 : return DLT_RETURN_OK;
4523 : }
4524 :
4525 204 : DltReturnValue dlt_user_log_send_unregister_context(DltContextData *log)
4526 : {
4527 : DltUserHeader userheader;
4528 : DltUserControlMsgUnregisterContext usercontext;
4529 : DltReturnValue ret;
4530 :
4531 204 : if (log == NULL)
4532 : return DLT_RETURN_WRONG_PARAMETER;
4533 :
4534 204 : if (log->handle == NULL)
4535 : return DLT_RETURN_WRONG_PARAMETER;
4536 :
4537 204 : if (log->handle->contextID[0] == '\0')
4538 : return DLT_RETURN_ERROR;
4539 :
4540 : /* set userheader */
4541 204 : if (dlt_user_set_userheader(&userheader, DLT_USER_MESSAGE_UNREGISTER_CONTEXT) < DLT_RETURN_OK)
4542 : return DLT_RETURN_ERROR;
4543 :
4544 : /* set usercontext */
4545 204 : dlt_set_id(usercontext.apid, dlt_user.appID); /* application id */
4546 204 : dlt_set_id(usercontext.ctid, log->handle->contextID); /* context id */
4547 204 : usercontext.pid = getpid();
4548 :
4549 204 : if (dlt_user.dlt_is_file)
4550 : return DLT_RETURN_OK;
4551 :
4552 204 : ret = dlt_user_log_out2(dlt_user.dlt_log_handle,
4553 : &(userheader),
4554 : sizeof(DltUserHeader),
4555 : &(usercontext),
4556 : sizeof(DltUserControlMsgUnregisterContext));
4557 :
4558 : /* store message in ringbuffer, if an error has occured */
4559 204 : if (ret < DLT_RETURN_OK)
4560 167 : return dlt_user_log_out_error_handling(&(userheader),
4561 : sizeof(DltUserHeader),
4562 : &(usercontext),
4563 : sizeof(DltUserControlMsgUnregisterContext),
4564 : NULL,
4565 : 0);
4566 :
4567 : return DLT_RETURN_OK;
4568 : }
4569 :
4570 0 : DltReturnValue dlt_send_app_ll_ts_limit(const char *apid, DltLogLevelType loglevel, DltTraceStatusType tracestatus)
4571 : {
4572 : DltUserHeader userheader;
4573 : DltUserControlMsgAppLogLevelTraceStatus usercontext;
4574 : DltReturnValue ret;
4575 :
4576 0 : if ((loglevel < DLT_USER_LOG_LEVEL_NOT_SET) || (loglevel >= DLT_LOG_MAX)) {
4577 0 : dlt_vlog(LOG_ERR, "Loglevel %d is outside valid range", loglevel);
4578 0 : return DLT_RETURN_ERROR;
4579 : }
4580 :
4581 0 : if ((tracestatus < DLT_USER_TRACE_STATUS_NOT_SET) || (tracestatus >= DLT_TRACE_STATUS_MAX)) {
4582 0 : dlt_vlog(LOG_ERR, "Tracestatus %d is outside valid range", tracestatus);
4583 0 : return DLT_RETURN_ERROR;
4584 : }
4585 :
4586 0 : if ((apid == NULL) || (apid[0] == '\0'))
4587 : return DLT_RETURN_ERROR;
4588 :
4589 : /* set userheader */
4590 0 : if (dlt_user_set_userheader(&userheader, DLT_USER_MESSAGE_APP_LL_TS) < DLT_RETURN_OK)
4591 : return DLT_RETURN_ERROR;
4592 :
4593 : /* set usercontext */
4594 0 : dlt_set_id(usercontext.apid, apid); /* application id */
4595 0 : usercontext.log_level = loglevel;
4596 0 : usercontext.trace_status = tracestatus;
4597 :
4598 0 : if (dlt_user.dlt_is_file)
4599 : return DLT_RETURN_OK;
4600 :
4601 0 : ret = dlt_user_log_out2(dlt_user.dlt_log_handle,
4602 : &(userheader), sizeof(DltUserHeader),
4603 : &(usercontext), sizeof(DltUserControlMsgAppLogLevelTraceStatus));
4604 :
4605 : /* store message in ringbuffer, if an error has occured */
4606 0 : if (ret < DLT_RETURN_OK)
4607 0 : return dlt_user_log_out_error_handling(&(userheader),
4608 : sizeof(DltUserHeader),
4609 : &(usercontext),
4610 : sizeof(DltUserControlMsgAppLogLevelTraceStatus),
4611 : NULL,
4612 : 0);
4613 :
4614 : return DLT_RETURN_OK;
4615 : }
4616 :
4617 4 : DltReturnValue dlt_user_log_send_log_mode(DltUserLogMode mode)
4618 : {
4619 : DltUserHeader userheader;
4620 : DltUserControlMsgLogMode logmode;
4621 : DltReturnValue ret;
4622 :
4623 4 : if ((mode < DLT_USER_MODE_UNDEFINED) || (mode >= DLT_USER_MODE_MAX)) {
4624 0 : dlt_vlog(LOG_ERR, "User log mode %d is outside valid range", mode);
4625 0 : return DLT_RETURN_WRONG_PARAMETER;
4626 : }
4627 :
4628 : /* set userheader */
4629 4 : if (dlt_user_set_userheader(&userheader, DLT_USER_MESSAGE_LOG_MODE) < DLT_RETURN_OK)
4630 : return DLT_RETURN_ERROR;
4631 :
4632 : /* set data */
4633 4 : logmode.log_mode = (unsigned char)mode;
4634 :
4635 4 : if (dlt_user.dlt_is_file)
4636 : return DLT_RETURN_OK;
4637 :
4638 4 : ret = dlt_user_log_out2(dlt_user.dlt_log_handle,
4639 : &(userheader), sizeof(DltUserHeader),
4640 : &(logmode), sizeof(DltUserControlMsgLogMode));
4641 :
4642 : /* store message in ringbuffer, if an error has occured */
4643 4 : if (ret < DLT_RETURN_OK)
4644 4 : return dlt_user_log_out_error_handling(&(userheader),
4645 : sizeof(DltUserHeader),
4646 : &(logmode),
4647 : sizeof(DltUserControlMsgLogMode),
4648 : NULL,
4649 : 0);
4650 :
4651 : return DLT_RETURN_OK;
4652 : }
4653 :
4654 1 : DltReturnValue dlt_user_log_send_marker()
4655 : {
4656 : DltUserHeader userheader;
4657 : DltReturnValue ret;
4658 :
4659 : /* set userheader */
4660 1 : if (dlt_user_set_userheader(&userheader, DLT_USER_MESSAGE_MARKER) < DLT_RETURN_OK)
4661 : return DLT_RETURN_ERROR;
4662 :
4663 1 : if (dlt_user.dlt_is_file)
4664 : return DLT_RETURN_OK;
4665 :
4666 : /* log to FIFO */
4667 1 : ret = dlt_user_log_out2(dlt_user.dlt_log_handle,
4668 : &(userheader), sizeof(DltUserHeader), 0, 0);
4669 :
4670 : /* store message in ringbuffer, if an error has occured */
4671 1 : if (ret < DLT_RETURN_OK)
4672 1 : return dlt_user_log_out_error_handling(&(userheader),
4673 : sizeof(DltUserHeader),
4674 : NULL,
4675 : 0,
4676 : NULL,
4677 : 0);
4678 :
4679 : return DLT_RETURN_OK;
4680 : }
4681 :
4682 0 : DltReturnValue dlt_user_print_msg(DltMessage *msg, DltContextData *log)
4683 : {
4684 : uint8_t *databuffer_tmp;
4685 : uint32_t datasize_tmp;
4686 : uint32_t databuffersize_tmp;
4687 : static char text[DLT_USER_TEXT_LENGTH];
4688 :
4689 0 : if ((msg == NULL) || (log == NULL))
4690 : return DLT_RETURN_WRONG_PARAMETER;
4691 :
4692 : /* Save variables before print */
4693 0 : databuffer_tmp = msg->databuffer;
4694 0 : datasize_tmp = msg->datasize;
4695 0 : databuffersize_tmp = msg->databuffersize;
4696 :
4697 : /* Act like a receiver, convert header back to host format */
4698 0 : msg->standardheader->len = DLT_BETOH_16(msg->standardheader->len);
4699 0 : dlt_message_get_extraparameters(msg, 0);
4700 :
4701 0 : msg->databuffer = log->buffer;
4702 0 : msg->datasize = (uint32_t) log->size;
4703 0 : msg->databuffersize = (uint32_t) log->size;
4704 :
4705 : /* Print message as ASCII */
4706 0 : if (dlt_message_print_ascii(msg, text, DLT_USER_TEXT_LENGTH, 0) == DLT_RETURN_ERROR)
4707 : return DLT_RETURN_ERROR;
4708 :
4709 : /* Restore variables and set len to BE*/
4710 0 : msg->databuffer = databuffer_tmp;
4711 0 : msg->databuffersize = databuffersize_tmp;
4712 0 : msg->datasize = datasize_tmp;
4713 :
4714 0 : msg->standardheader->len = DLT_HTOBE_16(msg->standardheader->len);
4715 :
4716 0 : return DLT_RETURN_OK;
4717 : }
4718 :
4719 22533 : DltReturnValue dlt_user_log_check_user_message(void)
4720 : {
4721 : int offset = 0;
4722 : int leave_while = 0;
4723 : int ret = 0;
4724 :
4725 : uint32_t i;
4726 : int fd;
4727 : struct pollfd nfd[1];
4728 :
4729 : DltUserHeader *userheader;
4730 : DltReceiver *receiver = &(dlt_user.receiver);
4731 :
4732 : DltUserControlMsgLogLevel *usercontextll;
4733 : DltUserControlMsgInjection *usercontextinj;
4734 : DltUserControlMsgLogState *userlogstate;
4735 : unsigned char *userbuffer;
4736 :
4737 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
4738 : DltUserControlMsgTraceSettingMsg *trace_load_settings_user_messages;
4739 : uint32_t trace_load_settings_user_messages_count = 0;
4740 : uint32_t trace_load_settings_user_message_bytes_required = 0;
4741 : unsigned long trace_load_settings_alloc_size = 0;
4742 : #endif
4743 :
4744 : /* For delayed calling of injection callback, to avoid deadlock */
4745 : DltUserInjectionCallback delayed_injection_callback;
4746 : DltUserLogLevelChangedCallback delayed_log_level_changed_callback;
4747 : unsigned char *delayed_inject_buffer = 0;
4748 : uint32_t delayed_inject_data_length = 0;
4749 :
4750 : /* Ensure that callback is null before searching for it */
4751 : delayed_injection_callback.injection_callback = 0;
4752 : delayed_injection_callback.injection_callback_with_id = 0;
4753 : delayed_injection_callback.service_id = 0;
4754 22533 : delayed_log_level_changed_callback.log_level_changed_callback = 0;
4755 : delayed_injection_callback.data = 0;
4756 :
4757 : #if defined DLT_LIB_USE_UNIX_SOCKET_IPC || defined DLT_LIB_USE_VSOCK_IPC
4758 : fd = dlt_user.dlt_log_handle;
4759 : #else /* DLT_LIB_USE_FIFO_IPC */
4760 22533 : fd = dlt_user.dlt_user_handle;
4761 : #endif
4762 22533 : nfd[0].events = POLLIN;
4763 22533 : nfd[0].fd = fd;
4764 :
4765 22533 : if (fd >= 0) {
4766 : ret = poll(nfd, 1, DLT_USER_RECEIVE_MDELAY);
4767 21 : if (ret) {
4768 9 : if (nfd[0].revents & (POLLHUP | POLLNVAL | POLLERR)) {
4769 0 : dlt_user.dlt_log_handle = DLT_FD_INIT;
4770 0 : return DLT_RETURN_ERROR;
4771 : }
4772 :
4773 9 : if (dlt_receiver_receive(receiver) <= 0)
4774 : /* No new message available */
4775 : return DLT_RETURN_OK;
4776 :
4777 : /* look through buffer as long as data is in there */
4778 : while (1) {
4779 21 : if (receiver->bytesRcvd < (int32_t) sizeof(DltUserHeader))
4780 : break;
4781 :
4782 : /* resync if necessary */
4783 : offset = 0;
4784 :
4785 : do {
4786 12 : userheader = (DltUserHeader *)(receiver->buf + offset);
4787 :
4788 : /* Check for user header pattern */
4789 12 : if (dlt_user_check_userheader(userheader))
4790 : break;
4791 :
4792 0 : offset++;
4793 :
4794 0 : } while (((int32_t) (sizeof(DltUserHeader)) + offset) <= receiver->bytesRcvd);
4795 :
4796 : /* Check for user header pattern */
4797 24 : if ((dlt_user_check_userheader(userheader) < 0) ||
4798 12 : (dlt_user_check_userheader(userheader) == 0))
4799 : break;
4800 :
4801 : /* Set new start offset */
4802 12 : if (offset > 0) {
4803 0 : receiver->buf += offset;
4804 0 : receiver->bytesRcvd -= offset;
4805 : }
4806 :
4807 12 : switch (userheader->message) {
4808 5 : case DLT_USER_MESSAGE_LOG_LEVEL:
4809 : {
4810 5 : if (receiver->bytesRcvd < (int32_t) (sizeof(DltUserHeader) + sizeof(DltUserControlMsgLogLevel))) {
4811 : leave_while = 1;
4812 : break;
4813 : }
4814 :
4815 5 : usercontextll = (DltUserControlMsgLogLevel *)(receiver->buf + sizeof(DltUserHeader));
4816 :
4817 : /* Update log level and trace status */
4818 : if (usercontextll != NULL) {
4819 5 : dlt_mutex_lock();
4820 :
4821 5 : if ((usercontextll->log_level_pos >= 0) &&
4822 5 : (usercontextll->log_level_pos < (int32_t)dlt_user.dlt_ll_ts_num_entries)) {
4823 5 : if (dlt_user.dlt_ll_ts) {
4824 5 : dlt_user.dlt_ll_ts[usercontextll->log_level_pos].log_level = (int8_t) usercontextll->log_level;
4825 5 : dlt_user.dlt_ll_ts[usercontextll->log_level_pos].trace_status =
4826 5 : (int8_t) usercontextll->trace_status;
4827 :
4828 5 : if (dlt_user.dlt_ll_ts[usercontextll->log_level_pos].log_level_ptr)
4829 0 : *(dlt_user.dlt_ll_ts[usercontextll->log_level_pos].log_level_ptr) =
4830 : (int8_t) usercontextll->log_level;
4831 :
4832 5 : if (dlt_user.dlt_ll_ts[usercontextll->log_level_pos].trace_status_ptr)
4833 0 : *(dlt_user.dlt_ll_ts[usercontextll->log_level_pos].trace_status_ptr) =
4834 0 : (int8_t) usercontextll->trace_status;
4835 :
4836 5 : delayed_log_level_changed_callback.log_level_changed_callback =
4837 5 : dlt_user.dlt_ll_ts[usercontextll->log_level_pos].log_level_changed_callback;
4838 : memcpy(delayed_log_level_changed_callback.contextID,
4839 : dlt_user.dlt_ll_ts[usercontextll->log_level_pos].contextID, DLT_ID_SIZE);
4840 5 : delayed_log_level_changed_callback.log_level = (int8_t) usercontextll->log_level;
4841 5 : delayed_log_level_changed_callback.trace_status = (int8_t) usercontextll->trace_status;
4842 : }
4843 : }
4844 :
4845 5 : dlt_mutex_free();
4846 : }
4847 :
4848 : /* call callback outside of semaphore */
4849 5 : if (delayed_log_level_changed_callback.log_level_changed_callback != 0)
4850 0 : delayed_log_level_changed_callback.log_level_changed_callback(
4851 : delayed_log_level_changed_callback.contextID,
4852 0 : (uint8_t) delayed_log_level_changed_callback.log_level,
4853 0 : (uint8_t) delayed_log_level_changed_callback.trace_status);
4854 :
4855 : /* keep not read data in buffer */
4856 5 : if (dlt_receiver_remove(receiver,
4857 : sizeof(DltUserHeader) + sizeof(DltUserControlMsgLogLevel)) ==
4858 : DLT_RETURN_ERROR)
4859 : return DLT_RETURN_ERROR;
4860 : }
4861 : break;
4862 0 : case DLT_USER_MESSAGE_INJECTION:
4863 : {
4864 : /* At least, user header, user context, and service id and data_length of injected message is available */
4865 0 : if (receiver->bytesRcvd < (int32_t) (sizeof(DltUserHeader) + sizeof(DltUserControlMsgInjection))) {
4866 : leave_while = 1;
4867 : break;
4868 : }
4869 :
4870 0 : usercontextinj = (DltUserControlMsgInjection *)(receiver->buf + sizeof(DltUserHeader));
4871 0 : userbuffer =
4872 : (unsigned char *)(receiver->buf + sizeof(DltUserHeader) + sizeof(DltUserControlMsgInjection));
4873 :
4874 : if (userbuffer != NULL) {
4875 :
4876 0 : if (receiver->bytesRcvd <
4877 0 : (int32_t) (sizeof(DltUserHeader) + sizeof(DltUserControlMsgInjection) +
4878 0 : usercontextinj->data_length_inject)) {
4879 : leave_while = 1;
4880 : break;
4881 : }
4882 :
4883 0 : dlt_mutex_lock();
4884 :
4885 0 : if ((usercontextinj->data_length_inject > 0) && (dlt_user.dlt_ll_ts))
4886 : /* Check if injection callback is registered for this context */
4887 0 : for (i = 0; i < dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].nrcallbacks; i++)
4888 0 : if ((dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].injection_table) &&
4889 0 : (dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].injection_table[i].service_id ==
4890 0 : usercontextinj->service_id)) {
4891 : /* Prepare delayed injection callback call */
4892 0 : if (dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].injection_table[i].
4893 : injection_callback != NULL) {
4894 : delayed_injection_callback.injection_callback =
4895 : dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].injection_table[i].
4896 : injection_callback;
4897 : }
4898 0 : else if (dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].injection_table[i].
4899 : injection_callback_with_id != NULL)
4900 : {
4901 : delayed_injection_callback.injection_callback_with_id =
4902 : dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].injection_table[i].
4903 : injection_callback_with_id;
4904 : delayed_injection_callback.data =
4905 0 : dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].injection_table[i].data;
4906 : }
4907 :
4908 : delayed_injection_callback.service_id = usercontextinj->service_id;
4909 : delayed_inject_data_length = usercontextinj->data_length_inject;
4910 0 : delayed_inject_buffer = malloc(delayed_inject_data_length);
4911 :
4912 0 : if (delayed_inject_buffer != NULL) {
4913 : memcpy(delayed_inject_buffer, userbuffer, delayed_inject_data_length);
4914 : }
4915 : else {
4916 0 : dlt_mutex_free();
4917 0 : dlt_log(LOG_WARNING, "malloc failed!\n");
4918 0 : return DLT_RETURN_ERROR;
4919 : }
4920 :
4921 : break;
4922 : }
4923 :
4924 0 : dlt_mutex_free();
4925 :
4926 : /* Delayed injection callback call */
4927 0 : if ((delayed_inject_buffer != NULL) &&
4928 : (delayed_injection_callback.injection_callback != NULL)) {
4929 0 : delayed_injection_callback.injection_callback(delayed_injection_callback.service_id,
4930 : delayed_inject_buffer,
4931 : delayed_inject_data_length);
4932 0 : delayed_injection_callback.injection_callback = NULL;
4933 : }
4934 0 : else if ((delayed_inject_buffer != NULL) &&
4935 : (delayed_injection_callback.injection_callback_with_id != NULL))
4936 : {
4937 0 : delayed_injection_callback.injection_callback_with_id(delayed_injection_callback.service_id,
4938 : delayed_inject_buffer,
4939 : delayed_inject_data_length,
4940 : delayed_injection_callback.data);
4941 : delayed_injection_callback.injection_callback_with_id = NULL;
4942 : }
4943 :
4944 0 : free(delayed_inject_buffer);
4945 : delayed_inject_buffer = NULL;
4946 :
4947 : /* keep not read data in buffer */
4948 0 : if (dlt_receiver_remove(receiver,
4949 : (int) (sizeof(DltUserHeader) +
4950 0 : sizeof(DltUserControlMsgInjection) +
4951 0 : usercontextinj->data_length_inject)) != DLT_RETURN_OK)
4952 : return DLT_RETURN_ERROR;
4953 : }
4954 : }
4955 : break;
4956 7 : case DLT_USER_MESSAGE_LOG_STATE:
4957 : {
4958 : /* At least, user header, user context, and service id and data_length of injected message is available */
4959 7 : if (receiver->bytesRcvd < (int32_t) (sizeof(DltUserHeader) + sizeof(DltUserControlMsgLogState))) {
4960 : leave_while = 1;
4961 : break;
4962 : }
4963 :
4964 7 : userlogstate = (DltUserControlMsgLogState *)(receiver->buf + sizeof(DltUserHeader));
4965 7 : dlt_user.log_state = userlogstate->log_state;
4966 :
4967 : /* keep not read data in buffer */
4968 7 : if (dlt_receiver_remove(receiver,
4969 : (sizeof(DltUserHeader) + sizeof(DltUserControlMsgLogState))) ==
4970 : DLT_RETURN_ERROR)
4971 : return DLT_RETURN_ERROR;
4972 : }
4973 : break;
4974 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
4975 : case DLT_USER_MESSAGE_TRACE_LOAD:
4976 : {
4977 : /*
4978 : * at least user header and message length is available
4979 : */
4980 : trace_load_settings_user_message_bytes_required =
4981 : (int32_t) (sizeof(DltUserHeader) + sizeof(uint32_t ));
4982 : if (receiver->bytesRcvd < (int32_t)trace_load_settings_user_message_bytes_required) {
4983 : // Not enough data to read the message length
4984 : leave_while = 1;
4985 : break;
4986 : }
4987 :
4988 : // Read trace settings count from buffer.
4989 : trace_load_settings_user_messages_count = (uint32_t)(*(receiver->buf + sizeof(DltUserHeader)));
4990 : trace_load_settings_user_message_bytes_required +=
4991 : trace_load_settings_user_messages_count * sizeof(DltUserControlMsgTraceSettingMsg);
4992 : if (receiver->bytesRcvd < (int32_t)trace_load_settings_user_message_bytes_required) {
4993 : // Not enough data to read trace settings
4994 : leave_while = 1;
4995 : break;
4996 : }
4997 :
4998 : trace_load_settings_user_messages =
4999 : (DltUserControlMsgTraceSettingMsg *)(receiver->buf + sizeof(DltUserHeader) + sizeof(uint32_t));
5000 :
5001 : pthread_rwlock_wrlock(&trace_load_rw_lock);
5002 :
5003 : // Remove the default created at startup
5004 : if (trace_load_settings != NULL) {
5005 : free(trace_load_settings);
5006 : trace_load_settings_count = 0;
5007 : trace_load_settings = NULL;
5008 : }
5009 :
5010 : trace_load_settings_alloc_size = sizeof(DltTraceLoadSettings) * trace_load_settings_user_messages_count;
5011 : trace_load_settings = malloc(trace_load_settings_alloc_size);
5012 : if (trace_load_settings == NULL) {
5013 : pthread_rwlock_unlock(&trace_load_rw_lock);
5014 : dlt_vlog(LOG_EMERG, "Unable to allocate memory for trace load settings, no logging will be possible\n");
5015 : } else {
5016 : memset(trace_load_settings, 0, trace_load_settings_alloc_size);
5017 : for (i = 0; i < trace_load_settings_user_messages_count; i++) {
5018 : strncpy(trace_load_settings[i].apid, dlt_user.appID, DLT_ID_SIZE);
5019 : strncpy(trace_load_settings[i].ctid, trace_load_settings_user_messages[i].ctid, DLT_ID_SIZE);
5020 : trace_load_settings[i].soft_limit = trace_load_settings_user_messages[i].soft_limit;
5021 : trace_load_settings[i].hard_limit = trace_load_settings_user_messages[i].hard_limit;
5022 : }
5023 :
5024 : /* Publish the newly installed trace_load_settings (protected by rwlock)
5025 : * and then update the per-context pointer while holding the DLT mutex to
5026 : * avoid races with concurrent context registration/unregistration.
5027 : */
5028 : trace_load_settings_count = trace_load_settings_user_messages_count;
5029 : pthread_rwlock_unlock(&trace_load_rw_lock);
5030 :
5031 : dlt_mutex_lock();
5032 : for (i = 0; i < dlt_user.dlt_ll_ts_num_entries; ++i) {
5033 : dlt_ll_ts_type* ctx_entry = &dlt_user.dlt_ll_ts[i];
5034 : ctx_entry->trace_load_settings = dlt_find_runtime_trace_load_settings(
5035 : trace_load_settings, trace_load_settings_count, dlt_user.appID, ctx_entry->contextID);
5036 : }
5037 : dlt_mutex_free();
5038 :
5039 : char **messages = malloc(trace_load_settings_count * sizeof(char *));
5040 : if (messages == NULL) {
5041 : pthread_rwlock_unlock(&trace_load_rw_lock);
5042 : dlt_vlog(LOG_ERR, "unable to allocate memory for trace load message buffer\n");
5043 : } else {
5044 : uint32_t msg_count = 0U;
5045 : for (i = 0U; i < trace_load_settings_count; i++) {
5046 : messages[i] = malloc(255 * sizeof(char));
5047 : if (messages[i] == NULL) {
5048 : dlt_vlog(LOG_ERR, "unable to allocate memory for trace load message buffer, index: %u, skipping remaining entries\n", i);
5049 : break;
5050 : }
5051 : ++msg_count;
5052 : snprintf(messages[i], 255, "Received trace load settings: apid=%.4s%s%.4s, soft_limit=%u, hard_limit=%u\n",
5053 : trace_load_settings[i].apid,
5054 : trace_load_settings[i].ctid[0] == '\0' ? "" : ", ctid=",
5055 : trace_load_settings[i].ctid[0] == '\0' ? "" : trace_load_settings[i].ctid,
5056 : trace_load_settings[i].soft_limit,
5057 : trace_load_settings[i].hard_limit);
5058 : }
5059 : /* Messages are emitted outside of both the rwlock and the DLT mutex */
5060 : for (i = 0U; i < msg_count; i++) {
5061 : dlt_user_output_internal_msg(DLT_LOG_INFO, messages[i], NULL);
5062 : free(messages[i]);
5063 : }
5064 : free(messages);
5065 : }
5066 : /* continue outer flow, rwlock already unlocked */
5067 : }
5068 :
5069 : /* keep not read data in buffer */
5070 : if (dlt_receiver_remove(receiver, trace_load_settings_user_message_bytes_required)
5071 : == DLT_RETURN_ERROR) {
5072 : return DLT_RETURN_ERROR;
5073 : }
5074 : }
5075 : #endif
5076 0 : default:
5077 : {
5078 0 : dlt_log(LOG_WARNING, "Invalid user message type received!\n");
5079 : /* Ignore result */
5080 0 : if (dlt_receiver_remove(receiver, sizeof(DltUserHeader)) == -1)
5081 0 : dlt_log(LOG_WARNING, "Can't remove bytes from receiver\n");
5082 : /* In next invocation of while loop, a resync will be triggered if additional data was received */
5083 : }
5084 : break;
5085 : } /* switch() */
5086 :
5087 12 : if (leave_while == 1) {
5088 : leave_while = 0;
5089 : break;
5090 : }
5091 : } /* while buffer*/
5092 :
5093 9 : if (dlt_receiver_move_to_begin(receiver) == DLT_RETURN_ERROR)
5094 : return DLT_RETURN_ERROR;
5095 : } /* while receive */
5096 :
5097 : } /* if */
5098 :
5099 : return DLT_RETURN_OK;
5100 : }
5101 :
5102 5835 : DltReturnValue dlt_user_log_resend_buffer(void)
5103 : {
5104 : int num, count;
5105 : int size;
5106 : DltReturnValue ret;
5107 :
5108 5835 : dlt_mutex_lock();
5109 :
5110 5835 : if (dlt_user.appID[0] == '\0') {
5111 4 : dlt_mutex_free();
5112 4 : return 0;
5113 : }
5114 :
5115 : /* Send content of ringbuffer */
5116 5831 : count = dlt_buffer_get_message_count(&(dlt_user.startup_buffer));
5117 5831 : dlt_mutex_free();
5118 :
5119 5831 : for (num = 0; num < count; num++) {
5120 :
5121 1 : dlt_mutex_lock();
5122 1 : size = dlt_buffer_copy(&(dlt_user.startup_buffer), dlt_user.resend_buffer, dlt_user.log_buf_len);
5123 :
5124 1 : if (size > 0) {
5125 1 : DltUserHeader *userheader = (DltUserHeader *)(dlt_user.resend_buffer);
5126 :
5127 : /* Add application id to the messages of needed*/
5128 1 : if (dlt_user_check_userheader(userheader)) {
5129 1 : switch (userheader->message) {
5130 0 : case DLT_USER_MESSAGE_REGISTER_CONTEXT:
5131 : {
5132 : DltUserControlMsgRegisterContext *usercontext =
5133 0 : (DltUserControlMsgRegisterContext *)(dlt_user.resend_buffer + sizeof(DltUserHeader));
5134 :
5135 0 : if ((usercontext != 0) && (usercontext->apid[0] == '\0'))
5136 0 : dlt_set_id(usercontext->apid, dlt_user.appID);
5137 :
5138 : break;
5139 : }
5140 1 : case DLT_USER_MESSAGE_LOG:
5141 : {
5142 : DltExtendedHeader *extendedHeader =
5143 1 : (DltExtendedHeader *)(dlt_user.resend_buffer + sizeof(DltUserHeader) +
5144 : sizeof(DltStandardHeader) +
5145 : sizeof(DltStandardHeaderExtra));
5146 :
5147 1 : if (((extendedHeader) != 0) && (extendedHeader->apid[0] == '\0')) /* if application id is empty, add it */
5148 0 : dlt_set_id(extendedHeader->apid, dlt_user.appID);
5149 :
5150 : break;
5151 : }
5152 : default:
5153 : {
5154 : break;
5155 : }
5156 : }
5157 : }
5158 :
5159 : #ifdef DLT_SHM_ENABLE
5160 : dlt_shm_push(&dlt_user.dlt_shm,
5161 : dlt_user.resend_buffer + sizeof(DltUserHeader),
5162 : size - sizeof(DltUserHeader),
5163 : 0,
5164 : 0,
5165 : 0,
5166 : 0);
5167 :
5168 : ret = dlt_user_log_out3(dlt_user.dlt_log_handle, dlt_user.resend_buffer, sizeof(DltUserHeader), 0, 0, 0, 0);
5169 : #else
5170 1 : ret = dlt_user_log_out3(dlt_user.dlt_log_handle, dlt_user.resend_buffer, (size_t) size, 0, 0, 0, 0);
5171 : #endif
5172 :
5173 : /* in case of error, keep message in ringbuffer */
5174 1 : if (ret == DLT_RETURN_OK) {
5175 0 : dlt_buffer_remove(&(dlt_user.startup_buffer));
5176 : }
5177 : else {
5178 1 : if (ret == DLT_RETURN_PIPE_ERROR) {
5179 : /* handle not open or pipe error */
5180 1 : close(dlt_user.dlt_log_handle);
5181 1 : dlt_user.dlt_log_handle = -1;
5182 : }
5183 :
5184 : /* keep message in ringbuffer */
5185 1 : dlt_mutex_free();
5186 1 : return ret;
5187 : }
5188 : }
5189 :
5190 0 : dlt_mutex_free();
5191 : }
5192 :
5193 : return DLT_RETURN_OK;
5194 : }
5195 :
5196 121 : void dlt_user_log_reattach_to_daemon(void)
5197 : {
5198 : uint32_t num;
5199 : DltContext handle;
5200 : DltContextData log_new;
5201 :
5202 121 : if (!DLT_USER_INITIALIZED_NOT_FREEING) {
5203 111 : return;
5204 : }
5205 :
5206 :
5207 121 : if (dlt_user.dlt_log_handle < 0) {
5208 111 : dlt_user.dlt_log_handle = DLT_FD_INIT;
5209 :
5210 : #ifdef DLT_LIB_USE_UNIX_SOCKET_IPC
5211 : /* try to open connection to dlt daemon */
5212 : dlt_initialize_socket_connection();
5213 :
5214 : if (dlt_user.connection_state != DLT_USER_CONNECTED)
5215 : /* return if not connected */
5216 : return;
5217 :
5218 : #elif defined DLT_LIB_USE_VSOCK_IPC
5219 : dlt_initialize_vsock_connection();
5220 :
5221 : if (dlt_user.connection_state != DLT_USER_CONNECTED)
5222 : return;
5223 :
5224 : #else /* DLT_LIB_USE_FIFO_IPC */
5225 : /* try to open pipe to dlt daemon */
5226 : int fd = open(dlt_daemon_fifo, O_WRONLY | O_NONBLOCK);
5227 :
5228 111 : if (fd < 0)
5229 : return;
5230 :
5231 0 : dlt_user.dlt_log_handle = fd;
5232 : #endif
5233 :
5234 0 : if (dlt_user_log_init(&handle, &log_new) < DLT_RETURN_OK)
5235 : return;
5236 :
5237 : #ifdef DLT_SHM_ENABLE
5238 :
5239 : /* init shared memory */
5240 : if (dlt_shm_init_client(&dlt_user.dlt_shm, dltShmName) < DLT_RETURN_OK)
5241 : dlt_vnlog(LOG_WARNING, DLT_USER_BUFFER_LENGTH, "Logging disabled,"
5242 : " Shared memory %s cannot be created!\n", dltShmName);
5243 :
5244 : #endif
5245 :
5246 0 : dlt_log(LOG_NOTICE, "Logging (re-)enabled!\n");
5247 :
5248 : /* Re-register application */
5249 0 : if (dlt_user_log_send_register_application() < DLT_RETURN_ERROR)
5250 : return;
5251 :
5252 0 : dlt_mutex_lock();
5253 :
5254 : /* Re-register all stored contexts */
5255 0 : for (num = 0; num < dlt_user.dlt_ll_ts_num_entries; num++)
5256 : /* Re-register stored context */
5257 0 : if ((dlt_user.appID[0] != '\0') && (dlt_user.dlt_ll_ts) && (dlt_user.dlt_ll_ts[num].contextID[0] != '\0')) {
5258 : /*dlt_set_id(log_new.appID, dlt_user.appID); */
5259 0 : dlt_set_id(handle.contextID, dlt_user.dlt_ll_ts[num].contextID);
5260 0 : handle.log_level_pos = (int32_t) num;
5261 0 : log_new.context_description = dlt_user.dlt_ll_ts[num].context_description;
5262 :
5263 : /* Release the mutex for sending context registration: */
5264 : /* function dlt_user_log_send_register_context() can take the mutex to write to the DLT buffer. => dead lock */
5265 0 : dlt_mutex_free();
5266 :
5267 0 : log_new.log_level = DLT_USER_LOG_LEVEL_NOT_SET;
5268 0 : log_new.trace_status = DLT_USER_TRACE_STATUS_NOT_SET;
5269 :
5270 0 : if (dlt_user_log_send_register_context(&log_new) < DLT_RETURN_ERROR)
5271 : return;
5272 :
5273 : /* Lock again the mutex */
5274 : /* it is necessary in the for(;;) test, in order to have coherent dlt_user data all over the critical section. */
5275 0 : dlt_mutex_lock();
5276 : }
5277 0 : dlt_mutex_free();
5278 : }
5279 : }
5280 :
5281 0 : DltReturnValue dlt_user_log_send_overflow(void)
5282 : {
5283 : DltUserHeader userheader;
5284 : DltUserControlMsgBufferOverflow userpayload;
5285 :
5286 : /* set userheader */
5287 0 : if (dlt_user_set_userheader(&userheader, DLT_USER_MESSAGE_OVERFLOW) < DLT_RETURN_OK)
5288 : return DLT_RETURN_ERROR;
5289 :
5290 0 : if (dlt_user.dlt_is_file)
5291 : return DLT_RETURN_OK;
5292 :
5293 : /* set user message parameters */
5294 0 : userpayload.overflow_counter = dlt_user.overflow_counter;
5295 0 : dlt_set_id(userpayload.apid, dlt_user.appID);
5296 :
5297 0 : return dlt_user_log_out2(dlt_user.dlt_log_handle,
5298 : &(userheader), sizeof(DltUserHeader),
5299 : &(userpayload), sizeof(DltUserControlMsgBufferOverflow));
5300 : }
5301 :
5302 0 : DltReturnValue dlt_user_check_buffer(int *total_size, int *used_size)
5303 : {
5304 0 : if ((total_size == NULL) || (used_size == NULL))
5305 : return DLT_RETURN_WRONG_PARAMETER;
5306 :
5307 0 : dlt_mutex_lock();
5308 :
5309 : #ifdef DLT_SHM_ENABLE
5310 : *total_size = dlt_shm_get_total_size(&(dlt_user.dlt_shm));
5311 : *used_size = dlt_shm_get_used_size(&(dlt_user.dlt_shm));
5312 : #else
5313 0 : *total_size = (int) dlt_buffer_get_total_size(&(dlt_user.startup_buffer));
5314 0 : *used_size = dlt_buffer_get_used_size(&(dlt_user.startup_buffer));
5315 : #endif
5316 :
5317 0 : dlt_mutex_free();
5318 0 : return DLT_RETURN_OK; /* ok */
5319 : }
5320 :
5321 : #ifdef DLT_TEST_ENABLE
5322 : void dlt_user_test_corrupt_user_header(int enable)
5323 : {
5324 : dlt_user.corrupt_user_header = enable;
5325 : }
5326 : void dlt_user_test_corrupt_message_size(int enable, int16_t size)
5327 : {
5328 : dlt_user.corrupt_message_size = enable;
5329 : dlt_user.corrupt_message_size_size = size;
5330 : }
5331 : #endif
5332 :
5333 :
5334 22517 : int dlt_start_threads()
5335 : {
5336 : struct timespec time_to_wait, single_wait;
5337 : struct timespec now;
5338 : int signal_status = 1;
5339 22517 : atomic_bool dlt_housekeeper_running = false;
5340 :
5341 : /*
5342 : * Configure the condition varibale to use CLOCK_MONOTONIC.
5343 : * This makes sure we're protected against changes in the system clock
5344 : */
5345 : pthread_condattr_t attr;
5346 22517 : pthread_condattr_init(&attr);
5347 22517 : pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
5348 22517 : pthread_cond_init(&dlt_housekeeper_running_cond, &attr);
5349 :
5350 22517 : if (pthread_create(&(dlt_housekeeperthread_handle),
5351 : 0,
5352 : (void *)&dlt_user_housekeeperthread_function,
5353 : &dlt_housekeeper_running) != 0) {
5354 0 : dlt_log(LOG_CRIT, "Can't create housekeeper thread!\n");
5355 0 : return -1;
5356 : }
5357 :
5358 22517 : clock_gettime(CLOCK_MONOTONIC, &now);
5359 : /* wait at most 10s */
5360 22517 : time_to_wait.tv_sec = now.tv_sec + 10;
5361 : time_to_wait.tv_nsec = now.tv_nsec;
5362 :
5363 : /*
5364 : * wait until the house keeper is up and running
5365 : * Even though the condition variable and the while are
5366 : * using the same time out the while loop is not a no op.
5367 : * This is due to the fact that the pthread_cond_timedwait
5368 : * can be woken before time is up and dlt_housekeeper_running is not true yet.
5369 : * (spurious wakeup)
5370 : * To protect against this, a while loop with a timeout is added
5371 : * */
5372 :
5373 : // pthread_cond_timedwait has to be called on a locked mutex
5374 22517 : pthread_mutex_lock(&dlt_housekeeper_running_mutex);
5375 :
5376 22517 : while (!dlt_housekeeper_running
5377 22517 : && now.tv_sec <= time_to_wait.tv_sec) {
5378 :
5379 : /*
5380 : * wait 500ms at a time
5381 : * this makes sure we don't block too long
5382 : * even if we missed the signal
5383 : */
5384 22459 : clock_gettime(CLOCK_MONOTONIC, &now);
5385 22459 : if (now.tv_nsec >= 500000000) {
5386 11190 : single_wait.tv_sec = now.tv_sec + 1;
5387 11190 : single_wait.tv_nsec = now.tv_nsec - 500000000;
5388 : } else {
5389 11269 : single_wait.tv_sec = now.tv_sec;
5390 11269 : single_wait.tv_nsec = now.tv_nsec + 500000000;
5391 : }
5392 :
5393 22459 : signal_status = pthread_cond_timedwait(
5394 : &dlt_housekeeper_running_cond,
5395 : &dlt_housekeeper_running_mutex,
5396 : &single_wait);
5397 :
5398 : /* otherwise it might be a spurious wakeup, try again until the time is over */
5399 22459 : if (signal_status == 0) {
5400 : break;
5401 : }
5402 : }
5403 :
5404 22517 : pthread_mutex_unlock(&dlt_housekeeper_running_mutex);
5405 :
5406 22517 : if (signal_status != 0 && !dlt_housekeeper_running) {
5407 0 : dlt_log(LOG_CRIT, "Failed to wait for house keeper thread!\n");
5408 0 : dlt_stop_threads();
5409 0 : return -1;
5410 : }
5411 :
5412 : #ifdef DLT_NETWORK_TRACE_ENABLE
5413 : /* Start the segmented thread */
5414 22517 : if (pthread_create(&(dlt_user.dlt_segmented_nwt_handle), NULL,
5415 : (void *)dlt_user_trace_network_segmented_thread, NULL)) {
5416 0 : dlt_log(LOG_CRIT, "Can't start segmented thread!\n");
5417 0 : return -1;
5418 : }
5419 : #endif
5420 : return 0;
5421 : }
5422 :
5423 22517 : void dlt_stop_threads()
5424 : {
5425 : int dlt_housekeeperthread_result = 0;
5426 : int joined = 0;
5427 :
5428 22517 : if (dlt_housekeeperthread_handle) {
5429 : /* do not ignore return value */
5430 : #ifndef __ANDROID_API__
5431 22517 : dlt_housekeeperthread_result = pthread_cancel(dlt_housekeeperthread_handle);
5432 : #else
5433 :
5434 : #ifdef DLT_NETWORK_TRACE_ENABLE
5435 : dlt_lock_mutex(&mq_mutex);
5436 : #endif /* DLT_NETWORK_TRACE_ENABLE */
5437 : dlt_housekeeperthread_result = pthread_kill(dlt_housekeeperthread_handle, SIGUSR1);
5438 : dlt_user_cleanup_handler(NULL);
5439 : #endif
5440 :
5441 :
5442 22517 : if (dlt_housekeeperthread_result != 0)
5443 0 : dlt_vlog(LOG_ERR,
5444 : "ERROR %s(dlt_housekeeperthread_handle): %s\n",
5445 : #ifndef __ANDROID_API__
5446 : "pthread_cancel",
5447 : #else
5448 : "pthread_kill",
5449 : #endif
5450 : strerror(dlt_housekeeperthread_result));
5451 : }
5452 :
5453 : #ifdef DLT_NETWORK_TRACE_ENABLE
5454 : int dlt_segmented_nwt_result = 0;
5455 :
5456 22517 : if (dlt_user.dlt_segmented_nwt_handle) {
5457 22517 : dlt_lock_mutex(&mq_mutex);
5458 22517 : pthread_cond_signal(&mq_init_condition);
5459 22517 : dlt_unlock_mutex(&mq_mutex);
5460 :
5461 22517 : dlt_segmented_nwt_result = pthread_cancel(dlt_user.dlt_segmented_nwt_handle);
5462 :
5463 22517 : if (dlt_segmented_nwt_result != 0)
5464 0 : dlt_vlog(LOG_ERR,
5465 : "ERROR pthread_cancel(dlt_user.dlt_segmented_nwt_handle): %s\n",
5466 : strerror(dlt_segmented_nwt_result));
5467 : }
5468 : #endif /* DLT_NETWORK_TRACE_ENABLE */
5469 : /* make sure that the threads really finished working */
5470 22517 : if ((dlt_housekeeperthread_result == 0) && dlt_housekeeperthread_handle) {
5471 22517 : joined = pthread_join(dlt_housekeeperthread_handle, NULL);
5472 :
5473 22517 : if (joined != 0)
5474 0 : dlt_vlog(LOG_ERR,
5475 : "ERROR pthread_join(dlt_housekeeperthread_handle, NULL): %s\n",
5476 : strerror(joined));
5477 :
5478 22517 : dlt_housekeeperthread_handle = 0; /* set to invalid */
5479 : }
5480 :
5481 : #ifdef DLT_NETWORK_TRACE_ENABLE
5482 22517 : if ((dlt_segmented_nwt_result == 0) && dlt_user.dlt_segmented_nwt_handle) {
5483 22517 : joined = pthread_join(dlt_user.dlt_segmented_nwt_handle, NULL);
5484 :
5485 22517 : if (joined != 0)
5486 0 : dlt_vlog(LOG_ERR,
5487 : "ERROR pthread_join(dlt_user.dlt_segmented_nwt_handle, NULL): %s\n",
5488 : strerror(joined));
5489 :
5490 22517 : dlt_user.dlt_segmented_nwt_handle = 0; /* set to invalid */
5491 : }
5492 : #endif /* DLT_NETWORK_TRACE_ENABLE */
5493 22517 : }
5494 :
5495 0 : static void dlt_fork_child_fork_handler()
5496 : {
5497 0 : g_dlt_is_child = 1;
5498 0 : dlt_user_init_state = INIT_UNITIALIZED;
5499 0 : dlt_user.dlt_log_handle = -1;
5500 0 : dlt_user.local_pid = -1;
5501 : #ifdef DLT_TRACE_LOAD_CTRL_ENABLE
5502 : pthread_rwlock_unlock(&trace_load_rw_lock);
5503 : #endif
5504 0 : }
5505 :
5506 :
5507 : #if defined(DLT_TRACE_LOAD_CTRL_ENABLE)
5508 : static DltReturnValue dlt_user_output_internal_msg(
5509 : const DltLogLevelType loglevel, const char *const text, void* const params)
5510 : {
5511 : (void)params; // parameter is not needed
5512 : DltContextData log;
5513 : int ret;
5514 : int sent_size = 0;
5515 :
5516 : if (dlt_user.verbose_mode == 0)
5517 : {
5518 : return DLT_RETURN_ERROR;
5519 : }
5520 :
5521 : if (loglevel < DLT_USER_LOG_LEVEL_NOT_SET || loglevel >= DLT_LOG_MAX)
5522 : {
5523 : dlt_vlog(LOG_ERR, "Loglevel %d is outside valid range", loglevel);
5524 : return DLT_RETURN_WRONG_PARAMETER;
5525 : }
5526 :
5527 : if (text == NULL)
5528 : {
5529 : return DLT_RETURN_WRONG_PARAMETER;
5530 : }
5531 :
5532 : ret = dlt_user_log_write_start(&trace_load_context, &log, loglevel);
5533 :
5534 : // Ok means below threshold
5535 : // see src/dlt-qnx-system/dlt-qnx-slogger2-adapter.cpp::sloggerinfo_callback for reference
5536 : if (ret == DLT_RETURN_OK)
5537 : {
5538 : return ret;
5539 : }
5540 :
5541 : if (ret != DLT_RETURN_TRUE)
5542 : {
5543 : dlt_vlog(LOG_ERR, "Loglevel %d is disabled", loglevel);
5544 : }
5545 :
5546 :
5547 : if (log.buffer == NULL)
5548 : {
5549 : return DLT_RETURN_LOGGING_DISABLED;
5550 : }
5551 :
5552 : ret = dlt_user_log_write_string(&log, text);
5553 : if (ret < DLT_RETURN_OK)
5554 : {
5555 : return ret;
5556 : }
5557 :
5558 : ret = dlt_user_log_send_log(&log, DLT_TYPE_LOG, &sent_size);
5559 :
5560 : /* Return number of bytes if message was successfully sent */
5561 : return (ret == DLT_RETURN_OK) ? sent_size : ret;
5562 : }
5563 : #endif
5564 :
5565 858 : DltReturnValue dlt_user_log_out_error_handling(void *ptr1, size_t len1, void *ptr2, size_t len2, void *ptr3,
5566 : size_t len3)
5567 : {
5568 : DltReturnValue ret = DLT_RETURN_ERROR;
5569 858 : size_t msg_size = len1 + len2 + len3;
5570 :
5571 : /* Original mutex-protected buffer implementation */
5572 858 : dlt_mutex_lock();
5573 858 : ret = dlt_buffer_check_size(&(dlt_user.startup_buffer), (int)msg_size);
5574 858 : dlt_mutex_free();
5575 :
5576 858 : dlt_mutex_lock();
5577 :
5578 858 : if (dlt_buffer_push3(&(dlt_user.startup_buffer),
5579 : ptr1, (unsigned int)len1,
5580 : ptr2, (unsigned int)len2,
5581 : ptr3, (unsigned int)len3) == DLT_RETURN_ERROR) {
5582 0 : if (dlt_user.overflow_counter == 0)
5583 0 : dlt_log(LOG_WARNING, "Buffer full! Messages will be discarded.\n");
5584 :
5585 : ret = DLT_RETURN_BUFFER_FULL;
5586 : }
5587 :
5588 858 : dlt_mutex_free();
5589 858 : return ret;
5590 : }
5591 :
5592 6061 : DltReturnValue dlt_user_is_logLevel_enabled(DltContext *handle, DltLogLevelType loglevel)
5593 : {
5594 6061 : if ((loglevel < DLT_LOG_DEFAULT) || (loglevel >= DLT_LOG_MAX)) {
5595 : return DLT_RETURN_WRONG_PARAMETER;
5596 : }
5597 :
5598 6057 : dlt_mutex_lock();
5599 6057 : if ((handle == NULL) || (handle->log_level_ptr == NULL)) {
5600 10 : dlt_mutex_free();
5601 10 : return DLT_RETURN_WRONG_PARAMETER;
5602 : }
5603 :
5604 6047 : if ((loglevel <= (DltLogLevelType)(*(handle->log_level_ptr))) && (loglevel != DLT_LOG_OFF)) {
5605 6005 : dlt_mutex_free();
5606 6005 : return DLT_RETURN_TRUE;
5607 : }
5608 :
5609 42 : dlt_mutex_free();
5610 42 : return DLT_RETURN_LOGGING_DISABLED;
5611 : }
|