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