Line data Source code
1 : /**
2 : * Copyright (C) 2015 Advanced Driver Information Technology.
3 : * This code is developed by Advanced Driver Information Technology.
4 : * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
5 : *
6 : * This file is part of COVESA Project Dlt - Diagnostic Log and Trace console apps.
7 : *
8 : *
9 : * \copyright
10 : * This Source Code Form is subject to the terms of the
11 : * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with
12 : * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
13 : *
14 : *
15 : * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015
16 : * \author Frederic Berat <fberat@de.adit-jv.com> ADIT 2015
17 : *
18 : * \file dlt-control-common.c
19 : * For further information see http://www.covesa.org/.
20 : */
21 :
22 : /*******************************************************************************
23 : ** **
24 : ** SRC-MODULE: dlt-control-common.c **
25 : ** **
26 : ** TARGET : linux **
27 : ** **
28 : ** PROJECT : DLT **
29 : ** **
30 : ** AUTHOR : Christoph Lipka clipka@jp.adit-jv.com **
31 : ** PURPOSE : **
32 : ** **
33 : ** REMARKS : **
34 : ** **
35 : ** PLATFORM DEPENDANT [yes/no]: yes **
36 : ** **
37 : ** TO BE CHANGED BY USER [yes/no]: no **
38 : ** **
39 : *******************************************************************************/
40 :
41 : /*******************************************************************************
42 : ** Author Identity **
43 : ********************************************************************************
44 : ** **
45 : ** Initials Name Company **
46 : ** -------- ------------------------- ---------------------------------- **
47 : ** cl Christoph Lipka ADIT **
48 : ** fb Frederic Berat ADIT **
49 : *******************************************************************************/
50 : #define pr_fmt(fmt) "Common control: "fmt
51 :
52 : #include <errno.h>
53 : #include <dirent.h>
54 : #include <stdio.h>
55 : #include <stdlib.h>
56 : #include <string.h>
57 : #include <pthread.h>
58 : #include <sys/types.h>
59 : #include <sys/socket.h>
60 :
61 : #include "dlt_common.h"
62 : #include "dlt_protocol.h"
63 : #include "dlt_client.h"
64 :
65 : #include "dlt-control-common.h"
66 :
67 : #ifdef EXTENDED_FILTERING
68 : # if defined(__linux__) || defined(__ANDROID_API__)
69 : # include <json-c/json.h> /* for json filter parsing on Linux and Android */
70 : # endif
71 : # ifdef __QNX__
72 : # include <sys/json.h> /* for json filter parsing on QNX */
73 : # endif
74 : #endif
75 :
76 : #define DLT_CTRL_APID "DLTC"
77 : #define DLT_CTRL_CTID "DLTC"
78 :
79 : /** @brief Analyze the daemon answer
80 : *
81 : * This function as to be provided by the user of the connection.
82 : *
83 : * @param answer The textual answer of the daemon
84 : * @param payload The daemons answer payload
85 : * @param length The daemons answer payload length
86 : *
87 : * @return User defined.
88 : */
89 : static int (*response_analyzer_cb)(char *, void *, int);
90 :
91 : static pthread_t daemon_connect_thread;
92 : static DltClient g_client;
93 : static int callback_return = -1;
94 : static pthread_mutex_t answer_lock = PTHREAD_MUTEX_INITIALIZER;
95 : static pthread_cond_t answer_cond = PTHREAD_COND_INITIALIZER;
96 :
97 : static int local_verbose;
98 : static char local_ecuid[DLT_CTRL_ECUID_LEN]; /* Name of ECU */
99 : static int local_timeout;
100 : static char local_filename[DLT_MOUNT_PATH_MAX]= {0}; /* Path to dlt.conf */
101 :
102 18 : int get_verbosity(void)
103 : {
104 46 : return local_verbose;
105 : }
106 :
107 0 : void set_verbosity(int v)
108 : {
109 2 : local_verbose = !!v;
110 0 : }
111 :
112 4 : char *get_ecuid(void)
113 : {
114 4 : return local_ecuid;
115 : }
116 :
117 2 : void set_ecuid(char *ecuid)
118 : {
119 2 : char *ecuid_conf = NULL;
120 :
121 2 : if (local_ecuid != ecuid) {
122 : /* If user pass NULL, read ECUId from dlt.conf */
123 0 : if (ecuid == NULL) {
124 0 : if (dlt_parse_config_param("ECUId", &ecuid_conf) == 0) {
125 : memset(local_ecuid, 0, DLT_CTRL_ECUID_LEN);
126 0 : strncpy(local_ecuid, ecuid_conf, DLT_CTRL_ECUID_LEN);
127 0 : local_ecuid[DLT_CTRL_ECUID_LEN -1] = '\0';
128 : if (ecuid_conf !=NULL)
129 0 : free(ecuid_conf);
130 : }
131 : else {
132 0 : pr_error("Cannot read ECUid from dlt.conf\n");
133 : }
134 : }
135 : else {
136 : /* Set user passed ECUID */
137 : memset(local_ecuid, 0, DLT_CTRL_ECUID_LEN);
138 : strncpy(local_ecuid, ecuid, DLT_CTRL_ECUID_LEN);
139 0 : local_ecuid[DLT_CTRL_ECUID_LEN - 1] = '\0';
140 : }
141 : }
142 2 : }
143 :
144 2 : void set_conf(char *file_path)
145 : {
146 2 : if (file_path != NULL) {
147 : memset(local_filename, 0, DLT_MOUNT_PATH_MAX);
148 : strncpy(local_filename, file_path, DLT_MOUNT_PATH_MAX);
149 2 : local_filename[DLT_MOUNT_PATH_MAX - 1] = '\0';
150 : }
151 : else {
152 0 : pr_error("Argument is NULL\n");
153 : }
154 2 : }
155 :
156 2 : int get_timeout(void)
157 : {
158 2 : return local_timeout;
159 : }
160 :
161 2 : void set_timeout(int t)
162 : {
163 2 : local_timeout = DLT_CTRL_TIMEOUT;
164 :
165 2 : if (t > 1)
166 2 : local_timeout = t;
167 : else
168 0 : pr_error("Timeout to small. Set to default: %d",
169 : DLT_CTRL_TIMEOUT);
170 2 : }
171 :
172 2 : void set_send_serial_header(const int value)
173 : {
174 2 : g_client.send_serial_header = value;
175 2 : }
176 :
177 2 : void set_resync_serial_header(const int value)
178 : {
179 2 : g_client.resync_serial_header = value;
180 2 : }
181 :
182 2 : int dlt_parse_config_param(char *config_id, char **config_data)
183 : {
184 : FILE *pFile = NULL;
185 : int value_length = DLT_LINE_LEN;
186 2 : char line[DLT_LINE_LEN - 1] = { 0 };
187 2 : char token[DLT_LINE_LEN] = { 0 };
188 2 : char value[DLT_LINE_LEN] = { 0 };
189 : char *pch = NULL;
190 : const char *filename = NULL;
191 :
192 2 : if (*config_data != NULL)
193 0 : *config_data = NULL;
194 :
195 : /* open configuration file */
196 2 : if (local_filename[0] != 0) {
197 : filename = local_filename;
198 : } else {
199 : filename = CONFIGURATION_FILES_DIR "/dlt.conf";
200 : }
201 2 : pFile = fopen(filename, "r");
202 :
203 2 : if (pFile != NULL) {
204 : while (1) {
205 : /* fetch line from configuration file */
206 14 : if (fgets(line, value_length - 1, pFile) != NULL) {
207 12 : if (strncmp(line, config_id, strlen(config_id)) == 0) {
208 2 : pch = strtok(line, " =\r\n");
209 2 : token[0] = 0;
210 2 : value[0] = 0;
211 :
212 4 : while (pch != NULL) {
213 4 : if (token[0] == 0) {
214 : strncpy(token, pch, sizeof(token) - 1);
215 : token[sizeof(token) - 1] = 0;
216 : }
217 : else {
218 : strncpy(value, pch, sizeof(value) - 1);
219 : value[sizeof(value) - 1] = 0;
220 2 : break;
221 : }
222 :
223 2 : pch = strtok(NULL, " =\r\n");
224 : }
225 :
226 2 : if (token[0] && value[0]) {
227 2 : if (strcmp(token, config_id) == 0) {
228 2 : *(config_data) = (char *)
229 2 : calloc(DLT_DAEMON_FLAG_MAX, sizeof(char));
230 : memcpy(*config_data,
231 : value,
232 : DLT_DAEMON_FLAG_MAX - 1);
233 : }
234 : }
235 : }
236 : }
237 : else {
238 : break;
239 : }
240 : }
241 :
242 2 : fclose (pFile);
243 : }
244 : else {
245 0 : fprintf(stderr, "Cannot open configuration file: %s\n", filename);
246 : }
247 :
248 2 : if (*config_data == NULL)
249 0 : return -1;
250 :
251 : return 0;
252 : }
253 :
254 : /** @brief Prepare the extra headers of a DLT message
255 : *
256 : * Modifies the extra headers of the message so that it can be sent.
257 : *
258 : * @param msg The message to be prepared
259 : * @param header The base header to be used.
260 : *
261 : * @return 0 on success, -1 otherwise.
262 : */
263 2 : static int prepare_extra_headers(DltMessage *msg, uint8_t *header)
264 : {
265 : uint32_t shift = 0;
266 :
267 2 : pr_verbose("Preparing extra headers.\n");
268 :
269 2 : if (!msg || !header)
270 : return -1;
271 :
272 2 : shift = (uint32_t) (sizeof(DltStorageHeader) +
273 : sizeof(DltStandardHeader) +
274 2 : DLT_STANDARD_HEADER_EXTRA_SIZE(msg->standardheader->htyp));
275 :
276 : /* Set header extra parameters */
277 2 : dlt_set_id(msg->headerextra.ecu, get_ecuid());
278 :
279 2 : msg->headerextra.tmsp = dlt_uptime();
280 :
281 : /* Copy header extra parameters to header buffer */
282 2 : if (dlt_message_set_extraparameters(msg, get_verbosity()) == -1) {
283 0 : pr_error("Cannot copy header extra parameter\n");
284 0 : return -1;
285 : }
286 :
287 : /* prepare extended header */
288 2 : msg->extendedheader = (DltExtendedHeader *)(header + shift);
289 :
290 2 : msg->extendedheader->msin = DLT_MSIN_CONTROL_REQUEST;
291 :
292 2 : msg->extendedheader->noar = 1; /* one payload packet */
293 :
294 : /* Dummy values have to be set */
295 2 : dlt_set_id(msg->extendedheader->apid, DLT_CTRL_APID);
296 2 : dlt_set_id(msg->extendedheader->ctid, DLT_CTRL_CTID);
297 :
298 2 : return 0;
299 : }
300 :
301 : /** @brief Prepare the headers of a DLT message
302 : *
303 : * Modifies the headers of the message so that it can be sent.
304 : *
305 : * @param msg The message to be prepared
306 : * @param header The base header to be used.
307 : *
308 : * @return 0 on success, -1 otherwise.
309 : */
310 2 : static int prepare_headers(DltMessage *msg, uint8_t *header)
311 : {
312 : uint32_t len = 0;
313 :
314 2 : pr_verbose("Preparing headers.\n");
315 :
316 2 : if (!msg || !header)
317 : return -1;
318 :
319 2 : msg->storageheader = (DltStorageHeader *)header;
320 :
321 2 : if (dlt_set_storageheader(msg->storageheader, "") == -1) {
322 0 : pr_error("Storage header initialization failed.\n");
323 0 : return -1;
324 : }
325 :
326 : /* prepare standard header */
327 2 : msg->standardheader =
328 2 : (DltStandardHeader *)(header + sizeof(DltStorageHeader));
329 :
330 2 : msg->standardheader->htyp = DLT_HTYP_WEID |
331 : DLT_HTYP_WTMS | DLT_HTYP_UEH | DLT_HTYP_PROTOCOL_VERSION1;
332 :
333 : #if (BYTE_ORDER == BIG_ENDIAN)
334 : msg->standardheader->htyp = (msg->standardheader->htyp | DLT_HTYP_MSBF);
335 : #endif
336 :
337 2 : msg->standardheader->mcnt = 0;
338 :
339 : /* prepare length information */
340 2 : msg->headersize = (int32_t)(sizeof(DltStorageHeader) +
341 : sizeof(DltStandardHeader) +
342 : sizeof(DltExtendedHeader) +
343 : DLT_STANDARD_HEADER_EXTRA_SIZE(msg->standardheader->htyp));
344 :
345 2 : len = (uint32_t)(msg->headersize - (int32_t)sizeof(DltStorageHeader) + msg->datasize);
346 :
347 2 : if (len > UINT16_MAX) {
348 0 : pr_error("Message header is too long.\n");
349 0 : return -1;
350 : }
351 :
352 2 : msg->standardheader->len = DLT_HTOBE_16(len);
353 :
354 2 : return 0;
355 : }
356 :
357 : /** @brief Prepare a DLT message.
358 : *
359 : * The DLT message is built using the data given by the user.
360 : * The data is basically composed of a buffer and a size.
361 : *
362 : * @param data The message body to be used to build the DLT message.
363 : *
364 : * @return 0 on success, -1 otherwise.
365 : */
366 2 : static DltMessage *dlt_control_prepare_message(DltControlMsgBody *data)
367 : {
368 : DltMessage *msg = NULL;
369 :
370 2 : pr_verbose("Preparing message.\n");
371 :
372 2 : if (data == NULL) {
373 0 : pr_error("Data for message body is NULL\n");
374 0 : return NULL;
375 : }
376 :
377 2 : msg = calloc(1, sizeof(DltMessage));
378 :
379 2 : if (msg == NULL) {
380 0 : pr_error("Cannot allocate memory for Dlt Message\n");
381 0 : return NULL;
382 : }
383 :
384 2 : if (dlt_message_init(msg, get_verbosity()) == -1) {
385 0 : pr_error("Cannot initialize Dlt Message\n");
386 0 : free(msg);
387 0 : return NULL;
388 : }
389 :
390 : /* prepare payload of data */
391 2 : msg->databuffersize = msg->datasize = (int32_t)data->size;
392 :
393 : /* Allocate memory for Dlt Message's buffer */
394 2 : msg->databuffer = (uint8_t *)calloc(1, data->size);
395 :
396 2 : if (msg->databuffer == NULL) {
397 0 : pr_error("Cannot allocate memory for data buffer\n");
398 0 : free(msg);
399 0 : return NULL;
400 : }
401 :
402 : /* copy data into message */
403 2 : memcpy(msg->databuffer, data->data, data->size);
404 :
405 : /* prepare storage header */
406 2 : if (prepare_headers(msg, msg->headerbuffer)) {
407 0 : dlt_message_free(msg, get_verbosity());
408 0 : free(msg);
409 0 : return NULL;
410 : }
411 :
412 : /* prepare extra headers */
413 2 : if (prepare_extra_headers(msg, msg->headerbuffer)) {
414 0 : dlt_message_free(msg, get_verbosity());
415 0 : free(msg);
416 0 : return NULL;
417 : }
418 :
419 : return msg;
420 : }
421 :
422 : /** @brief Initialize the connection with the daemon
423 : *
424 : * The connection is initialized using an internal callback. The user's
425 : * response analyzer will be finally executed by this callback.
426 : * The client pointer is used to established the connection.
427 : *
428 : * @param client A pointer to a valid client structure
429 : * @param cb The internal callback to be executed while receiving a new message
430 : *
431 : * @return 0 on success, -1 otherwise.
432 : */
433 2 : static int dlt_control_init_connection(DltClient *client, void *cb)
434 : {
435 : union {
436 : void *ptr;
437 : int (*callback)(DltMessage *message, void *data);
438 : } callback_converter;
439 : int (*callback)(DltMessage *message, void *data);
440 :
441 : callback_converter.ptr = cb;
442 2 : callback = callback_converter.callback;
443 :
444 2 : if (!cb || !client) {
445 0 : pr_error("%s: Invalid parameters\n", __func__);
446 0 : return -1;
447 : }
448 :
449 2 : pr_verbose("Initializing the connection.\n");
450 :
451 2 : if (dlt_client_init(client, get_verbosity()) != 0) {
452 0 : pr_error("Failed to register callback (NULL)\n");
453 0 : return -1;
454 : }
455 :
456 2 : dlt_client_register_message_callback(callback);
457 :
458 2 : client->socketPath = NULL;
459 :
460 2 : if (dlt_parse_config_param("ControlSocketPath", &client->socketPath) != 0) {
461 : /* Failed to read from conf, copy default */
462 0 : if (dlt_client_set_socket_path(client, DLT_DAEMON_DEFAULT_CTRL_SOCK_PATH) == -1) {
463 0 : pr_error("set socket path didn't succeed\n");
464 0 : return -1;
465 : }
466 : }
467 :
468 2 : client->mode = DLT_CLIENT_MODE_UNIX;
469 :
470 2 : return dlt_client_connect(client, get_verbosity());
471 : }
472 :
473 : /** @brief Daemon listener function
474 : *
475 : * This function will continuously read on the DLT socket, until an error occurs
476 : * or the thread executing this function is canceled.
477 : *
478 : * @param data Thread parameter
479 : *
480 : * @return The thread parameter given as argument.
481 : */
482 2 : static void *dlt_control_listen_to_daemon(void *data)
483 : {
484 2 : pr_verbose("Ready to receive DLT answers.\n");
485 2 : dlt_client_main_loop(&g_client, NULL, get_verbosity());
486 2 : return data;
487 : }
488 :
489 : /** @brief Internal callback for DLT response
490 : *
491 : * This function is called by the dlt_client_main_loop once a response is read
492 : * from the DLT socket.
493 : * After some basic checks, the user's response analyzer is called. The return
494 : * value of the analyzer is then provided back to the dlt_control_send_message
495 : * function to be given back as a return value.
496 : * As this function is called in a dedicated thread, the return value is
497 : * provided using a global variable.
498 : * Access to this variable is controlled through a dedicated mutex.
499 : * New values are signaled using a dedicated condition variable.
500 : *
501 : * @param message The DLT answer
502 : * @param data Unused
503 : *
504 : * @return The analyzer return value or -1 on early errors.
505 : */
506 2 : static int dlt_control_callback(DltMessage *message, void *data)
507 : {
508 2 : char text[DLT_RECEIVE_BUFSIZE] = { 0 };
509 : (void)data;
510 :
511 2 : if (message == NULL) {
512 0 : pr_error("Received message is null\n");
513 0 : return -1;
514 : }
515 :
516 : /* prepare storage header */
517 2 : if (DLT_IS_HTYP_WEID(message->standardheader->htyp))
518 2 : dlt_set_storageheader(message->storageheader, message->headerextra.ecu);
519 : else
520 0 : dlt_set_storageheader(message->storageheader, "LCTL");
521 :
522 2 : dlt_message_header(message, text, DLT_RECEIVE_BUFSIZE, get_verbosity());
523 :
524 : /* Extracting payload */
525 2 : dlt_message_payload(message, text,
526 : DLT_RECEIVE_BUFSIZE,
527 : DLT_OUTPUT_ASCII,
528 : get_verbosity());
529 :
530 : /*
531 : * Checking payload with the provided callback and return the result
532 : */
533 2 : pthread_mutex_lock(&answer_lock);
534 4 : callback_return = response_analyzer_cb(text,
535 2 : message->databuffer,
536 2 : (int) message->datasize);
537 2 : pthread_cond_signal(&answer_cond);
538 2 : pthread_mutex_unlock(&answer_lock);
539 :
540 2 : return callback_return;
541 : }
542 :
543 : /** @brief Send a message to the daemon and wait for the asynchronous answer.
544 : *
545 : * The answer is received and analyzed by a dedicated thread. Thus we need
546 : * to wait for the signal from this thread and then read the return value
547 : * to be provided to the user.
548 : * In case of timeout, this function fails.
549 : * The message provided by the user is formated in DLT format before sending.
550 : *
551 : * @param body The message provided by the user
552 : * @param timeout The time to wait before considering that no answer will come
553 : *
554 : * @return The user response analyzer return value, -1 in case of early error.
555 : */
556 2 : int dlt_control_send_message(DltControlMsgBody *body, int timeout)
557 : {
558 : struct timespec t;
559 : DltMessage *msg = NULL;
560 :
561 2 : if (!body) {
562 0 : pr_error("%s: Invalid input.\n", __func__);
563 0 : return -1;
564 : }
565 :
566 2 : if (clock_gettime(CLOCK_REALTIME, &t) == -1) {
567 0 : pr_error("Cannot read system time.\n");
568 0 : return -1;
569 : }
570 :
571 2 : t.tv_sec += timeout;
572 :
573 : /* send command to daemon here */
574 2 : msg = dlt_control_prepare_message(body);
575 :
576 2 : if (msg == NULL) {
577 0 : pr_error("Control message preparation failed\n");
578 0 : return -1;
579 : }
580 :
581 2 : pthread_mutex_lock(&answer_lock);
582 :
583 : /* Re-init the return value */
584 2 : callback_return = -1;
585 :
586 2 : if (dlt_client_send_message_to_socket(&g_client, msg) != DLT_RETURN_OK)
587 : {
588 0 : pr_error("Sending message to daemon failed\n");
589 0 : dlt_message_free(msg, get_verbosity());
590 0 : free(msg);
591 :
592 : /* make sure the mutex is unlocked to prevent deadlocks */
593 0 : pthread_mutex_unlock(&answer_lock);
594 0 : return -1;
595 : }
596 :
597 : /*
598 : * When a timeouts occurs, pthread_cond_timedwait()
599 : * shall nonetheless release and re-acquire the mutex referenced by mutex
600 : */
601 2 : pthread_cond_timedwait(&answer_cond, &answer_lock, &t);
602 2 : pthread_mutex_unlock(&answer_lock);
603 :
604 : /* Destroying the message */
605 2 : dlt_message_free(msg, get_verbosity());
606 2 : free(msg);
607 :
608 : /* At this point either the value is already correct, either it's still -1.
609 : * Then, we don't care to lock the access.
610 : */
611 2 : return callback_return;
612 : }
613 :
614 : /** @brief Control communication initialization
615 : *
616 : * This will prepare the DLT connection and the thread dedicated to the
617 : * response listening.
618 : *
619 : * @param response_analyzer User defined function used to analyze the response
620 : * @param ecuid The ECUID to provide to the daemon
621 : * @param verbosity The verbosity level
622 : *
623 : * @return 0 on success, -1 otherwise.
624 : */
625 2 : int dlt_control_init(int (*response_analyzer)(char *, void *, int),
626 : char *ecuid,
627 : int verbosity)
628 : {
629 2 : if (!response_analyzer || !ecuid) {
630 0 : pr_error("%s: Invalid input.\n", __func__);
631 0 : return -1;
632 : }
633 :
634 : union {
635 : void *ptr;
636 : int (*callback)(DltMessage *message, void *data);
637 : } callback_converter;
638 :
639 2 : response_analyzer_cb = response_analyzer;
640 2 : set_ecuid(ecuid);
641 : set_verbosity(verbosity);
642 : callback_converter.callback = dlt_control_callback;
643 :
644 : /* Initialize DLT connection */
645 2 : if (dlt_control_init_connection(&g_client, callback_converter.ptr) != 0) {
646 0 : pr_error("Connection initialization failed\n");
647 0 : dlt_client_cleanup(&g_client, get_verbosity());
648 0 : return -1;
649 : }
650 :
651 : /* Contact DLT daemon */
652 2 : if (pthread_create(&daemon_connect_thread,
653 : NULL,
654 : dlt_control_listen_to_daemon,
655 : NULL) != 0) {
656 0 : pr_error("Cannot create thread to communicate with DLT daemon.\n");
657 0 : return -1;
658 : }
659 :
660 : return 0;
661 : }
662 :
663 : /** @brief Control communication clean-up
664 : *
665 : * Cancels the listener thread and clean=up the dlt client structure.
666 : *
667 : * @return 0 on success, -1 otherwise.
668 : */
669 2 : int dlt_control_deinit(void)
670 : {
671 : /* At this stage, we want to stop sending/receiving
672 : * from dlt-daemon. So in order to avoid cancellation
673 : * at recv(), shutdown and close the socket
674 : */
675 2 : if (g_client.receiver.fd) {
676 2 : shutdown(g_client.receiver.fd, SHUT_RDWR);
677 2 : close(g_client.receiver.fd);
678 2 : g_client.receiver.fd = -1;
679 : }
680 :
681 2 : if (pthread_join(daemon_connect_thread, NULL)) {
682 0 : pr_error("Unable to join the thread with ERRNO=%s\n", strerror(errno));
683 : }
684 :
685 : /* Closing the socket */
686 2 : return dlt_client_cleanup(&g_client, get_verbosity());
687 : }
688 :
689 :
690 : #ifdef EXTENDED_FILTERING /* EXTENDED_FILTERING */
691 : # if defined(__linux__) || defined(__ANDROID_API__)
692 : DltReturnValue dlt_json_filter_load(DltFilter *filter, const char *filename, int verbose)
693 : {
694 : if ((filter == NULL) || (filename == NULL))
695 : return DLT_RETURN_WRONG_PARAMETER;
696 :
697 : if(verbose)
698 : pr_verbose("dlt_json_filter_load()\n");
699 :
700 : FILE *handle;
701 : char buffer[JSON_FILTER_SIZE*DLT_FILTER_MAX];
702 : struct json_object *j_parsed_json;
703 : struct json_object *j_app_id;
704 : struct json_object *j_context_id;
705 : struct json_object *j_log_level;
706 : struct json_object *j_payload_min;
707 : struct json_object *j_payload_max;
708 : enum json_tokener_error jerr;
709 :
710 : char app_id[DLT_ID_SIZE + 1] = "";
711 : char context_id[DLT_ID_SIZE + 1] = "";
712 : int32_t log_level = 0;
713 : int32_t payload_max = INT32_MAX;
714 : int32_t payload_min = 0;
715 :
716 : handle = fopen(filename, "r");
717 :
718 : if (handle == NULL) {
719 : pr_error("Filter file %s cannot be opened!\n", filename);
720 : return DLT_RETURN_ERROR;
721 : }
722 :
723 : if (fread(buffer, sizeof(buffer), 1, handle) != 0) {
724 : if (!feof(handle)) {
725 : pr_error("Filter file %s is to big for reading it with current buffer!\n", filename);
726 : return DLT_RETURN_ERROR;
727 : }
728 : }
729 :
730 : j_parsed_json = json_tokener_parse_verbose(buffer, &jerr);
731 :
732 : if (jerr != json_tokener_success) {
733 : pr_error("Faild to parse given filter %s: %s\n", filename, json_tokener_error_desc(jerr));
734 : return DLT_RETURN_ERROR;
735 : }
736 :
737 : printf("The following filter(s) are applied: \n");
738 : pr_verbose("The following filter(s) are applied: \n");
739 : int iterator = 0;
740 : json_object_object_foreach(j_parsed_json, key, val)
741 : {
742 : if (iterator >= DLT_FILTER_MAX) {
743 : pr_error("Maximum number (%d) of allowed filters reached, ignoring rest of filters!\n",
744 : DLT_FILTER_MAX);
745 : break;
746 : }
747 :
748 : printf("%s:\n", key);
749 : pr_verbose("%s:\n", key);
750 :
751 : if (json_object_object_get_ex(val, "AppId", &j_app_id))
752 : strncpy(app_id, json_object_get_string(j_app_id), DLT_ID_SIZE);
753 : else
754 : dlt_set_id(app_id, "");
755 :
756 : if (json_object_object_get_ex(val, "ContextId", &j_context_id))
757 : strncpy(context_id, json_object_get_string(j_context_id), DLT_ID_SIZE);
758 : else
759 : dlt_set_id(context_id, "");
760 :
761 : if (json_object_object_get_ex(val, "LogLevel", &j_log_level))
762 : log_level = json_object_get_int(j_log_level);
763 : else
764 : log_level = 0;
765 :
766 : if (json_object_object_get_ex(val, "PayloadMin", &j_payload_min))
767 : payload_min = json_object_get_int(j_payload_min);
768 : else
769 : payload_min = 0;
770 :
771 : if (json_object_object_get_ex(val, "PayloadMax", &j_payload_max))
772 : payload_max = json_object_get_int(j_payload_max);
773 : else
774 : payload_max = INT32_MAX;
775 :
776 : dlt_filter_add(filter, app_id, context_id, log_level, payload_min, payload_max, verbose);
777 :
778 : printf("\tAppId: %.*s\n", DLT_ID_SIZE, app_id);
779 : pr_verbose("\tAppId: %.*s\n", DLT_ID_SIZE, app_id);
780 : printf("\tConextId: %.*s\n", DLT_ID_SIZE, context_id);
781 : pr_verbose("\tConextId: %.*s\n", DLT_ID_SIZE, context_id);
782 : printf("\tLogLevel: %i\n", log_level);
783 : pr_verbose("\tLogLevel: %i\n", log_level);
784 : printf("\tPayloadMin: %i\n", payload_min);
785 : pr_verbose("\tPayloadMin: %i\n", payload_min);
786 : printf("\tPayloadMax: %i\n", payload_max);
787 : pr_verbose("\tPayloadMax: %i\n", payload_max);
788 :
789 : iterator++;
790 : }
791 :
792 : fclose(handle);
793 :
794 : return DLT_RETURN_OK;
795 : }
796 : # endif /* __Linux__ */
797 :
798 : # ifdef __QNX__
799 : DltReturnValue dlt_json_filter_load(DltFilter *filter, const char *filename, int verbose)
800 : {
801 : if ((filter == NULL) || (filename == NULL))
802 : return DLT_RETURN_WRONG_PARAMETER;
803 :
804 : if(verbose)
805 : pr_verbose("dlt_json_filter_load()\n");
806 :
807 : json_decoder_t *j_decoder = json_decoder_create();
808 :
809 : const char *s_app_id;
810 : const char *s_context_id;
811 : int32_t log_level = 0;
812 : int32_t payload_max = INT32_MAX;
813 : int32_t payload_min = 0;
814 :
815 : json_decoder_error_t ret = json_decoder_parse_file(j_decoder, filename);
816 :
817 : if (ret != JSON_DECODER_OK) {
818 : pr_error("Faild to parse given filter %s: json_decoder_error_t is %i\n", filename, ret);
819 : return DLT_RETURN_ERROR;
820 : }
821 :
822 : json_decoder_push_object(j_decoder, NULL, true);
823 :
824 : int iterator = 0;
825 : bool end_of_json = false;
826 :
827 : while (!end_of_json) {
828 : if (iterator >= DLT_FILTER_MAX) {
829 : pr_error("Maximum number (%d) of allowed filters reached, ignoring rest of filters!\n",
830 : DLT_FILTER_MAX);
831 : break;
832 : }
833 :
834 : if (json_decoder_next(j_decoder) == JSON_DECODER_NOT_FOUND)
835 : end_of_json = true;
836 :
837 : json_decoder_previous(j_decoder);
838 :
839 : printf("%s:\n", json_decoder_name(j_decoder));
840 : json_decoder_push_object(j_decoder, NULL, true);
841 :
842 : if (json_decoder_get_string(j_decoder, "AppId", &s_app_id, true) != JSON_DECODER_OK)
843 : s_app_id = "";
844 :
845 : if (json_decoder_get_string(j_decoder, "ContextId", &s_context_id, true) != JSON_DECODER_OK)
846 : s_context_id = "";
847 :
848 : if (json_decoder_get_int(j_decoder, "LogLevel", &log_level, true) != JSON_DECODER_OK)
849 : log_level = 0;
850 :
851 : if (json_decoder_get_int(j_decoder, "PayloadMin", &payload_min, true) != JSON_DECODER_OK)
852 : payload_min = 0;
853 :
854 : if (json_decoder_get_int(j_decoder, "PayloadMax", &payload_max, true) != JSON_DECODER_OK)
855 : payload_max = INT32_MAX;
856 :
857 : char app_id[DLT_ID_SIZE];
858 : char context_id[DLT_ID_SIZE];
859 :
860 : #pragma GCC diagnostic push
861 : #pragma GCC diagnostic ignored "-Wstringop-truncation"
862 : strncpy(app_id, s_app_id, DLT_ID_SIZE);
863 : strncpy(context_id, s_context_id, DLT_ID_SIZE);
864 : #pragma GCC diagnostic pop
865 :
866 : dlt_filter_add(filter, app_id, context_id, log_level, payload_min, payload_max, verbose);
867 :
868 : printf("\tAppId: %.*s\n", DLT_ID_SIZE, app_id);
869 : printf("\tConextId: %.*s\n", DLT_ID_SIZE, context_id);
870 : printf("\tLogLevel: %i\n", log_level);
871 : printf("\tPayloadMin: %i\n", payload_min);
872 : printf("\tPayloadMax: %i\n", payload_max);
873 :
874 : json_decoder_pop(j_decoder);
875 :
876 : iterator++;
877 : }
878 :
879 : json_decoder_destroy(j_decoder);
880 :
881 : return DLT_RETURN_OK;
882 : }
883 : # endif /* __QNX__ */
884 : #endif /* EXTENDED_FILTERING */
885 :
886 : #ifdef EXTENDED_FILTERING /* EXTENDED_FILTERING */
887 : # if defined(__linux__) || defined(__ANDROID_API__)
888 : DltReturnValue dlt_json_filter_save(DltFilter *filter, const char *filename, int verbose)
889 : {
890 : if ((filter == NULL) || (filename == NULL))
891 : return DLT_RETURN_WRONG_PARAMETER;
892 :
893 : if(verbose)
894 : pr_verbose("dlt_json_filter_save()\n");
895 :
896 : struct json_object *json_filter_obj = json_object_new_object();
897 :
898 : for (int num = 0; num < filter->counter; num++) {
899 : struct json_object *tmp_json_obj = json_object_new_object();
900 : char filter_name[JSON_FILTER_NAME_SIZE];
901 : sprintf(filter_name, "filter%i", num);
902 :
903 : if (filter->apid[num][DLT_ID_SIZE - 1] != 0)
904 : json_object_object_add(tmp_json_obj, "AppId", json_object_new_string_len(filter->apid[num], DLT_ID_SIZE));
905 : else
906 : json_object_object_add(tmp_json_obj, "AppId", json_object_new_string(filter->apid[num]));
907 :
908 : if (filter->ctid[num][DLT_ID_SIZE - 1] != 0)
909 : json_object_object_add(tmp_json_obj, "ContextId",
910 : json_object_new_string_len(filter->ctid[num], DLT_ID_SIZE));
911 : else
912 : json_object_object_add(tmp_json_obj, "ContextId", json_object_new_string(filter->ctid[num]));
913 :
914 : json_object_object_add(tmp_json_obj, "LogLevel", json_object_new_int(filter->log_level[num]));
915 : json_object_object_add(tmp_json_obj, "PayloadMin", json_object_new_int(filter->payload_min[num]));
916 : json_object_object_add(tmp_json_obj, "PayloadMax", json_object_new_int(filter->payload_max[num]));
917 :
918 : json_object_object_add(json_filter_obj, filter_name, tmp_json_obj);
919 : }
920 :
921 : printf("Saving current filter into '%s'\n", filename);
922 : json_object_to_file((char*)filename, json_filter_obj);
923 :
924 : return DLT_RETURN_OK;
925 : }
926 : # endif /* __Linux__ */
927 :
928 : # ifdef __QNX__
929 : DltReturnValue dlt_json_filter_save(DltFilter *filter, const char *filename, int verbose)
930 : {
931 : if ((filter == NULL) || (filename == NULL))
932 : return DLT_RETURN_WRONG_PARAMETER;
933 :
934 : if(verbose)
935 : pr_verbose("dlt_json_filter_save()\n");
936 :
937 : char s_app_id[DLT_ID_SIZE + 1];
938 : char s_context_id[DLT_ID_SIZE + 1];
939 :
940 : json_encoder_t *j_encoder = json_encoder_create();
941 : json_encoder_start_object(j_encoder, NULL);
942 :
943 : for (int num = 0; num < filter->counter; num++) {
944 : char filter_name[JSON_FILTER_NAME_SIZE];
945 : sprintf(filter_name, "filter%i", num);
946 : json_encoder_start_object(j_encoder, filter_name);
947 :
948 : strncpy(s_app_id, filter->apid[num], DLT_ID_SIZE);
949 :
950 : if (filter->apid[num][DLT_ID_SIZE - 1] != 0)
951 : s_app_id[DLT_ID_SIZE] = '\0';
952 :
953 : strncpy(s_context_id, filter->ctid[num], DLT_ID_SIZE);
954 :
955 : if (filter->ctid[num][DLT_ID_SIZE - 1] != 0)
956 : s_context_id[DLT_ID_SIZE] = '\0';
957 :
958 : json_encoder_add_string(j_encoder, "AppId", s_app_id);
959 : json_encoder_add_string(j_encoder, "ContextId", s_context_id);
960 : json_encoder_add_int(j_encoder, "LogLevel", filter->log_level[num]);
961 : json_encoder_add_int(j_encoder, "PayloadMin", filter->payload_min[num]);
962 : json_encoder_add_int(j_encoder, "PayloadMax", filter->payload_max[num]);
963 :
964 : json_encoder_end_object(j_encoder);
965 : }
966 :
967 : json_encoder_end_object(j_encoder);
968 :
969 : printf("Saving current filter into '%s'\n", filename);
970 : FILE *handle = fopen(filename, "w");
971 : int filter_buffer_size = 100 * (filter->counter);
972 : char filter_buffer[filter_buffer_size];
973 : snprintf(filter_buffer, filter_buffer_size, json_encoder_buffer(j_encoder));
974 : fprintf(handle, filter_buffer);
975 :
976 : fclose(handle);
977 : json_encoder_destroy(j_encoder);
978 :
979 : return DLT_RETURN_OK;
980 : }
981 : # endif /* __QNX__ */
982 : #endif /* EXTENDED_FILTERING */
|