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