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