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