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