X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Flib%2Fdlt_user.c;h=1f43801edc70dcffb26fc9ad4064381a43e40478;hb=244c56f9ba0c412b20d2bd9590ae6d07a799cbc9;hp=c1bcba4a9b7aa6d0121b39362fd94183bbfb0bea;hpb=760fb8a4daba3e403376099ce38aca8f88d695d3;p=profile%2Fivi%2Fdlt-daemon.git diff --git a/src/lib/dlt_user.c b/src/lib/dlt_user.c old mode 100755 new mode 100644 index c1bcba4..1f43801 --- a/src/lib/dlt_user.c +++ b/src/lib/dlt_user.c @@ -1,39 +1,24 @@ -/* -* Dlt- Diagnostic Log and Trace user library -* @licence app begin@ +/** + * @licence app begin@ + * Copyright (C) 2012 BMW AG + * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * Contributions are licensed to the GENIVI Alliance under one or more + * Contribution License Agreements. + * + * \copyright + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with + * this file, You can obtain one at http://mozilla.org/MPL/2.0/. * - * Copyright (C) 2011, BMW AG - Alexander Wenzel - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU Lesser General Public License, version 2.1, as published by the Free Software Foundation. - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General - * Public License, version 2.1, for more details. - * - * You should have received a copy of the GNU Lesser General Public License, version 2.1, along - * with this program; if not, see . - * - * Note that the copyright holders assume that the GNU Lesser General Public License, version 2.1, may - * also be applicable to programs even in cases in which the program is not a library in the technical sense. - * - * Linking DLT statically or dynamically with other modules is making a combined work based on DLT. You may - * license such other modules under the GNU Lesser General Public License, version 2.1. If you do not want to - * license your linked modules under the GNU Lesser General Public License, version 2.1, you - * may use the program under the following exception. - * - * As a special exception, the copyright holders of DLT give you permission to combine DLT - * with software programs or libraries that are released under any license unless such a combination is not - * permitted by the license of such a software program or library. You may copy and distribute such a - * system following the terms of the GNU Lesser General Public License, version 2.1, including this - * special exception, for DLT and the licenses of the other code concerned. - * - * Note that people who make modified versions of DLT are not obligated to grant this special exception - * for their modified versions; it is their choice whether to do so. The GNU Lesser General Public License, - * version 2.1, gives permission to release a modified version without this exception; this exception - * also makes it possible to release a modified version which carries forward this exception. * + * \author Alexander Wenzel BMW 2011-2012 + * + * \file dlt_user.c + * For further information see http://www.genivi.org/. * @licence end@ -*/ + */ /******************************************************************************* @@ -78,7 +63,6 @@ Initials Date Comment aw 13.01.2010 initial */ - #include /* for getenv(), free(), atexit() */ #include /* for strcmp(), strncmp(), strlen(), memset(), memcpy() */ #include /* for signal(), SIGPIPE, SIG_IGN */ @@ -89,12 +73,17 @@ #include /* POSIX Threads */ #endif +#include +#include + #include #include #include #include /* writev() */ +#include + #include "dlt_user.h" #include "dlt_user_shared.h" #include "dlt_user_shared_cfg.h" @@ -104,26 +93,67 @@ static DltUser dlt_user; static int dlt_user_initialised = 0; static char str[DLT_USER_BUFFER_LENGTH]; -static char text[DLT_USER_TEXT_LENGTH]; static sem_t dlt_mutex; static pthread_t dlt_receiverthread_handle; static pthread_attr_t dlt_receiverthread_attr; +/* Segmented Network Trace */ +#define DLT_MAX_TRACE_SEGMENT_SIZE 1024 +#define DLT_MESSAGE_QUEUE_NAME "/dlt_message_queue" +#define DLT_DELAYED_RESEND_INDICATOR_PATTERN 0xFFFF + +/* Mutex to wait on while message queue is not initialized */ +pthread_mutex_t mq_mutex; +pthread_cond_t mq_init_condition; + +/* Structure to pass data to segmented thread */ +typedef struct { + DltContext *handle; + uint16_t id; + DltNetworkTraceType nw_trace_type; + uint16_t header_len; + void *header; + uint16_t payload_len; + void *payload; +} s_segmented_data; + /* Function prototypes for internally used functions */ static void dlt_user_receiverthread_function(void *ptr); static void dlt_user_atexit_handler(void); static int dlt_user_log_init(DltContext *handle, DltContextData *log); -static int dlt_user_log_send_log(DltContextData *log, int mtype); +static DltReturnValue dlt_user_log_send_log(DltContextData *log, int mtype); static int dlt_user_log_send_register_application(void); static int dlt_user_log_send_unregister_application(void); static int dlt_user_log_send_register_context(DltContextData *log); static int dlt_user_log_send_unregister_context(DltContextData *log); static int dlt_send_app_ll_ts_limit(const char *appid, DltLogLevelType loglevel, DltTraceStatusType tracestatus); +static int dlt_user_log_send_log_mode(DltUserLogMode mode); static int dlt_user_print_msg(DltMessage *msg, DltContextData *log); static int dlt_user_log_check_user_message(void); static void dlt_user_log_reattach_to_daemon(void); static int dlt_user_log_send_overflow(void); +static void dlt_user_trace_network_segmented_thread(void *unused); +static void dlt_user_trace_network_segmented_thread_segmenter(s_segmented_data *data); +static int dlt_user_queue_resend(void); + +int dlt_user_check_library_version(const char *user_major_version,const char *user_minor_version){ + + char str[200]; + char lib_major_version[DLT_USER_MAX_LIB_VERSION_LENGTH]; + char lib_minor_version[DLT_USER_MAX_LIB_VERSION_LENGTH]; + + dlt_get_major_version( lib_major_version); + dlt_get_minor_version( lib_minor_version); + + if( (strcmp(lib_major_version,user_major_version)!=0) || (strcmp(lib_minor_version,user_minor_version)!=0)) + { + sprintf(str,"DLT Library version check failed! Installed DLT library version is %s.%s - Application using DLT library version %s.%s\n",lib_major_version,lib_minor_version,user_major_version,user_minor_version); + dlt_log(LOG_WARNING, str); + return -1; + } + return 0; +} int dlt_init(void) { @@ -141,10 +171,13 @@ int dlt_init(void) dlt_user.dlt_is_file = 0; dlt_user.overflow = 0; +#ifdef DLT_SHM_ENABLE + memset(&(dlt_user.dlt_shm),0,sizeof(DltShm)); +#endif /* create and open DLT user FIFO */ sprintf(filename,"%s/dlt%d",DLT_USER_DIR,getpid()); - + /* Try to delete existing pipe, ignore result of unlink */ unlink(filename); @@ -156,8 +189,8 @@ int dlt_init(void) /* return 0; */ /* removed to prevent error, when FIFO already exists */ } - dlt_user.dlt_user_handle = open(filename, O_RDWR); - if (dlt_user.dlt_user_handle == -1) + dlt_user.dlt_user_handle = open(filename, O_RDWR | O_CLOEXEC); + if (dlt_user.dlt_user_handle == DLT_FD_INIT) { sprintf(str,"Loging disabled, FIFO user %s cannot be opened!\n",filename); dlt_log(LOG_WARNING, str); @@ -166,13 +199,26 @@ int dlt_init(void) } /* open DLT output FIFO */ - dlt_user.dlt_log_handle = open(DLT_USER_FIFO, O_WRONLY | O_NONBLOCK); + dlt_user.dlt_log_handle = open(DLT_USER_FIFO, O_WRONLY | O_NONBLOCK | O_CLOEXEC ); if (dlt_user.dlt_log_handle==-1) { sprintf(str,"Loging disabled, FIFO %s cannot be opened with open()!\n",DLT_USER_FIFO); dlt_log(LOG_WARNING, str); - return 0; + //return 0; } + else + { +#ifdef DLT_SHM_ENABLE + /* init shared memory */ + if (dlt_shm_init_client(&(dlt_user.dlt_shm),DLT_SHM_KEY) < 0) + { + sprintf(str,"Loging disabled, Shared memory %d cannot be created!\n",DLT_SHM_KEY); + dlt_log(LOG_WARNING, str); + //return 0; + } +#endif + } + if (dlt_receiver_init(&(dlt_user.receiver),dlt_user.dlt_user_handle, DLT_USER_RCVBUF_MAX_SIZE)==-1) { @@ -180,22 +226,9 @@ int dlt_init(void) return -1; } - /* Set default thread stack size */ - if (pthread_attr_init(&dlt_receiverthread_attr)<0) - { - dlt_log(LOG_WARNING, "Initialization of default thread stack size failed!\n"); - } - else - { - if (pthread_attr_setstacksize(&dlt_receiverthread_attr,DLT_USER_RECEIVERTHREAD_STACKSIZE)<0) - { - dlt_log(LOG_WARNING, "Setting of default thread stack size failed!\n"); - } - } - /* Start receiver thread */ if (pthread_create(&(dlt_receiverthread_handle), - &dlt_receiverthread_attr, + 0, (void *) &dlt_user_receiverthread_function, 0)!=0) { @@ -214,7 +247,23 @@ int dlt_init(void) dlt_log(LOG_WARNING, "Can't destroy thread attributes!\n"); } - return 0; + /* These will be lazy initialized only when needed */ + dlt_user.dlt_segmented_queue_read_handle = -1; + dlt_user.dlt_segmented_queue_write_handle = -1; + + /* Wait mutext for segmented thread */ + pthread_mutex_init(&mq_mutex, NULL); + pthread_cond_init(&mq_init_condition, NULL); + + /* Start the segmented thread */ + if(pthread_create(&(dlt_user.dlt_segmented_nwt_handle), NULL, + (void *)dlt_user_trace_network_segmented_thread, NULL)) + { + dlt_log(LOG_CRIT, "Can't start segmented thread!\n"); + return -1; + } + + return 0; } int dlt_init_file(const char *name) @@ -242,6 +291,77 @@ int dlt_init_file(const char *name) return 0; } +int dlt_init_message_queue(void) +{ + pthread_mutex_lock(&mq_mutex); + if(dlt_user.dlt_segmented_queue_read_handle >= 0 && + dlt_user.dlt_segmented_queue_write_handle >= 0) + { + // Already intialized + pthread_mutex_unlock(&mq_mutex); + return 0; + } + + /* Generate per process name for queue */ + char queue_name[NAME_MAX]; + sprintf(queue_name, "%s.%d", DLT_MESSAGE_QUEUE_NAME, getpid()); + + /* Maximum queue size is 10, limit to size of pointers */ + struct mq_attr mqatr; + mqatr.mq_flags = 0; + mqatr.mq_maxmsg = 10; + mqatr.mq_msgsize = sizeof(s_segmented_data *); + mqatr.mq_curmsgs = 0; + + /** + * Create the message queue. It must be newly created + * if old one was left by a crashing process. + * */ + dlt_user.dlt_segmented_queue_read_handle = mq_open(queue_name, O_CREAT| O_RDONLY | O_EXCL, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, &mqatr); + if(dlt_user.dlt_segmented_queue_read_handle < 0) + { + if(errno == EEXIST) + { + dlt_log(LOG_WARNING, "Old message queue exists, trying to delete.\n"); + if(mq_unlink(queue_name) < 0) + { + char str[256]; + snprintf(str,255,"Could not delete existing message queue!: %s \n",strerror(errno)); + dlt_log(LOG_CRIT, str); + } + else // Retry + { + dlt_user.dlt_segmented_queue_read_handle = mq_open(queue_name, O_CREAT| O_RDONLY | O_EXCL, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, &mqatr); + } + } + if(dlt_user.dlt_segmented_queue_read_handle < 0) + { + char str[256]; + snprintf(str,255,"Can't create message queue read handle!: %s \n",strerror(errno)); + dlt_log(LOG_CRIT, str); + pthread_mutex_unlock(&mq_mutex); + return -1; + } + } + + dlt_user.dlt_segmented_queue_write_handle = mq_open(queue_name, O_WRONLY|O_NONBLOCK); + if(dlt_user.dlt_segmented_queue_write_handle < 0) + { + + char str[256]; + snprintf(str,255,"Can't open message queue write handle!: %s \n",strerror(errno)); + dlt_log(LOG_CRIT, str); + pthread_mutex_unlock(&mq_mutex); + return -1; + } + + pthread_cond_signal(&mq_init_condition); + pthread_mutex_unlock(&mq_mutex); + return 0; +} + int dlt_init_common(void) { char *env_local_print; @@ -253,8 +373,11 @@ int dlt_init_common(void) return -1; } + /* set to unknown state of connected client */ + dlt_user.log_state = -1; + dlt_user.dlt_log_handle=-1; - dlt_user.dlt_user_handle=-1; + dlt_user.dlt_user_handle=DLT_FD_INIT; dlt_set_id(dlt_user.ecuID,DLT_USER_DEFAULT_ECU_ID); dlt_set_id(dlt_user.appID,""); @@ -287,25 +410,48 @@ int dlt_init_common(void) } /* Initialize LogLevel/TraceStatus field */ + DLT_SEM_LOCK(); dlt_user.dlt_ll_ts = 0; dlt_user.dlt_ll_ts_max_num_entries = 0; dlt_user.dlt_ll_ts_num_entries = 0; - if (dlt_ringbuffer_init(&(dlt_user.rbuf), DLT_USER_RINGBUFFER_SIZE)==-1) + if (dlt_buffer_init_dynamic(&(dlt_user.startup_buffer), DLT_USER_RINGBUFFER_MIN_SIZE, DLT_USER_RINGBUFFER_MAX_SIZE, DLT_USER_RINGBUFFER_STEP_SIZE)==-1) { dlt_user_initialised = 0; + DLT_SEM_FREE(); return -1; } + DLT_SEM_FREE(); signal(SIGPIPE,SIG_IGN); /* ignore pipe signals */ atexit(dlt_user_atexit_handler); +#ifdef DLT_TEST_ENABLE + dlt_user.corrupt_user_header = 0; + dlt_user.corrupt_message_size = 0; + dlt_user.corrupt_message_size_size = 0; +#endif + return 0; } void dlt_user_atexit_handler(void) { + if (dlt_user_initialised==0) + { + return; + } + + /* Try to resend potential log messages in the user buffer */ + int count = dlt_user_atexit_blow_out_user_buffer(); + + if(count != 0){ + char tmp[256]; + sprintf(tmp,"Lost log messages in user buffer when exiting: %i\n",count); + dlt_log(LOG_ERR, tmp); + } + /* Unregister app (this also unregisters all contexts in daemon) */ /* Ignore return value */ dlt_unregister_app(); @@ -315,9 +461,34 @@ void dlt_user_atexit_handler(void) dlt_free(); } +int dlt_user_atexit_blow_out_user_buffer(void){ + + int count,ret; + + uint32_t exitTime = dlt_uptime() + DLT_USER_ATEXIT_RESEND_BUFFER_EXIT_TIMEOUT; + + while(dlt_uptime() < exitTime ){ + + ret = dlt_user_log_resend_buffer(); + + if(ret == 0) + { + return 0; + } + + usleep(DLT_USER_ATEXIT_RESEND_BUFFER_SLEEP); + } + + DLT_SEM_LOCK(); + count = dlt_buffer_get_message_count(&(dlt_user.startup_buffer)); + DLT_SEM_FREE(); + + return count; +} + int dlt_free(void) { - int i; + uint32_t i; char filename[DLT_USER_MAX_FILENAME_LENGTH]; if (dlt_user_initialised==0) @@ -331,16 +502,21 @@ int dlt_free(void) pthread_cancel(dlt_receiverthread_handle); } - if (dlt_user.dlt_user_handle!=-1) + if (dlt_user.dlt_user_handle!=DLT_FD_INIT) { - sprintf(filename,"/tmp/dlt%d",getpid()); + sprintf(filename,"%s/dlt%d",DLT_USER_DIR,getpid()); close(dlt_user.dlt_user_handle); - dlt_user.dlt_user_handle=-1; + dlt_user.dlt_user_handle=DLT_FD_INIT; unlink(filename); } +#ifdef DLT_SHM_ENABLE + /* free shared memory */ + dlt_shm_free_client(&dlt_user.dlt_shm); +#endif + if (dlt_user.dlt_log_handle!=-1) { /* close log file/output fifo to daemon */ @@ -352,8 +528,9 @@ int dlt_free(void) dlt_receiver_free(&(dlt_user.receiver)); /* Ignore return value */ - dlt_ringbuffer_free(&(dlt_user.rbuf)); + dlt_buffer_free_dynamic(&(dlt_user.startup_buffer)); + DLT_SEM_LOCK(); if (dlt_user.dlt_ll_ts) { for (i=0;imcnt = 0; + /* Store context id in log level/trace status field */ /* Check if already registered, else register context */ @@ -561,19 +798,25 @@ int dlt_register_context_ll_ts(DltContext *handle, const char *contextid, const if ((dlt_user.dlt_ll_ts_num_entries%DLT_USER_CONTEXT_ALLOC_SIZE)==0) { /* allocate memory in steps of DLT_USER_CONTEXT_ALLOC_SIZE, e.g. 500 */ - dlt_ll_ts_type *old; - old = dlt_user.dlt_ll_ts; + dlt_ll_ts_type *old_ll_ts; + uint32_t old_max_entries; + + old_ll_ts = dlt_user.dlt_ll_ts; + old_max_entries = dlt_user.dlt_ll_ts_max_num_entries; + dlt_user.dlt_ll_ts_max_num_entries = ((dlt_user.dlt_ll_ts_num_entries/DLT_USER_CONTEXT_ALLOC_SIZE)+1)*DLT_USER_CONTEXT_ALLOC_SIZE; dlt_user.dlt_ll_ts = (dlt_ll_ts_type*) malloc(sizeof(dlt_ll_ts_type)* dlt_user.dlt_ll_ts_max_num_entries); if (dlt_user.dlt_ll_ts==0) { + dlt_user.dlt_ll_ts = old_ll_ts; + dlt_user.dlt_ll_ts_max_num_entries = old_max_entries; DLT_SEM_FREE(); return -1; } - memcpy(dlt_user.dlt_ll_ts,old,sizeof(dlt_ll_ts_type)*dlt_user.dlt_ll_ts_num_entries); - free(old); + memcpy(dlt_user.dlt_ll_ts,old_ll_ts,sizeof(dlt_ll_ts_type)*dlt_user.dlt_ll_ts_num_entries); + free(old_ll_ts); /* Initialize new entries */ for (i=dlt_user.dlt_ll_ts_num_entries;i= 0) + { + dlt_log(LOG_WARNING, "dlt_forward_msg: Failed to queue resending.\n"); + } } switch (ret) @@ -883,48 +1156,30 @@ int dlt_forward_msg(void *msgdata,size_t size) /* ********************************************************************************************* */ -int dlt_user_log_write_start(DltContext *handle, DltContextData *log,DltLogLevelType loglevel) +inline int dlt_user_log_write_start(DltContext *handle, DltContextData *log,DltLogLevelType loglevel) { return dlt_user_log_write_start_id(handle,log,loglevel,DLT_USER_DEFAULT_MSGID); } int dlt_user_log_write_start_id(DltContext *handle, DltContextData *log,DltLogLevelType loglevel, uint32_t messageid) { - uint32_t mid; - - if (dlt_user_initialised==0) - { - if (dlt_init()<0) - { - return -1; - } - } - - if (dlt_user_log_init(handle, log)==-1) - { - return -1; - } - + if(dlt_user_initialised==0) + { + if (dlt_init()<0) + { + return -1; + } + } if (log==0) { return -1; } - /* Removed because of DltLogLevelType - - if ((loglevelDLT_LOG_VERBOSE)) + if (dlt_user_log_init(handle, log)==-1) { - return -1; + return -1; } - */ - - mid = messageid; - - log->args_num = 0; - log->log_level = loglevel; - log->size = 0; - if (dlt_user.dlt_ll_ts==0) { return -1; @@ -932,9 +1187,11 @@ int dlt_user_log_write_start_id(DltContext *handle, DltContextData *log,DltLogLe DLT_SEM_LOCK(); - if ((log->log_level<=(int)(dlt_user.dlt_ll_ts[handle->log_level_pos].log_level) ) && (log->log_level!=0)) + if ((loglevel<=(int)(dlt_user.dlt_ll_ts[handle->log_level_pos].log_level) ) && (loglevel!=0)) { DLT_SEM_FREE(); + log->args_num = 0; + log->log_level = loglevel; /* In non-verbose mode, insert message id */ if (dlt_user.verbose_mode==0) @@ -944,12 +1201,13 @@ int dlt_user_log_write_start_id(DltContext *handle, DltContextData *log,DltLogLe return -1; } /* Write message id */ - memcpy(log->buffer,&(mid),sizeof(uint32_t)); + memcpy(log->buffer,&(messageid),sizeof(uint32_t)); log->size = sizeof(uint32_t); /* as the message id is part of each message in non-verbose mode, it doesn't increment the argument counter in extended header (if used) */ } + else log->size=0; return 1; } else @@ -968,7 +1226,7 @@ int dlt_user_log_write_finish(DltContextData *log) return -1; } - return dlt_user_log_send_log(log, DLT_TYPE_LOG); + return dlt_user_log_send_log(log, DLT_TYPE_LOG) < 0 ? -1 : 0; } int dlt_user_log_write_raw(DltContextData *log,void *data,uint16_t length) @@ -1510,7 +1768,50 @@ int dlt_user_log_write_string(DltContextData *log, const char *text) return -1; } - type_info = DLT_TYPE_INFO_STRG; + type_info = DLT_TYPE_INFO_STRG | DLT_SCOD_ASCII; + + memcpy((log->buffer)+log->size,&(type_info),sizeof(uint32_t)); + log->size += sizeof(uint32_t); + } + + arg_size = strlen(text) + 1; + + memcpy((log->buffer)+log->size,&(arg_size),sizeof(uint16_t)); + log->size += sizeof(uint16_t); + + memcpy((log->buffer)+log->size,text,arg_size); + log->size += arg_size; + + log->args_num ++; + + return 0; +} + +int dlt_user_log_write_utf8_string(DltContextData *log, const char *text) +{ + uint16_t arg_size; + uint32_t type_info; + + if ((log==0) || (text==0)) + { + return -1; + } + + arg_size = strlen(text)+1; + + if ((log->size+arg_size+sizeof(uint16_t))>DLT_USER_BUF_MAX_SIZE) + { + return -1; + } + + if (dlt_user.verbose_mode) + { + if ((log->size+arg_size+sizeof(uint32_t)+sizeof(uint16_t))>DLT_USER_BUF_MAX_SIZE) + { + return -1; + } + + type_info = DLT_TYPE_INFO_STRG | DLT_SCOD_UTF8; memcpy((log->buffer)+log->size,&(type_info),sizeof(uint32_t)); log->size += sizeof(uint32_t); @@ -1533,7 +1834,7 @@ int dlt_register_injection_callback(DltContext *handle, uint32_t service_id, int (*dlt_injection_callback)(uint32_t service_id, void *data, uint32_t length)) { DltContextData log; - int i,j,k; + uint32_t i,j,k; int found = 0; DltUserInjectionCallback *old; @@ -1593,11 +1894,22 @@ int dlt_register_injection_callback(DltContext *handle, uint32_t service_id, if (dlt_user.dlt_ll_ts[i].injection_table == 0) { dlt_user.dlt_ll_ts[i].injection_table = (DltUserInjectionCallback*) malloc(sizeof(DltUserInjectionCallback)); + if(dlt_user.dlt_ll_ts[i].injection_table == 0) + { + DLT_SEM_FREE(); + return -1; + } } else { old = dlt_user.dlt_ll_ts[i].injection_table; dlt_user.dlt_ll_ts[i].injection_table = (DltUserInjectionCallback*) malloc(sizeof(DltUserInjectionCallback)*(j+1)); + if(dlt_user.dlt_ll_ts[i].injection_table == 0) + { + dlt_user.dlt_ll_ts[i].injection_table = old; + DLT_SEM_FREE(); + return -1; + } memcpy(dlt_user.dlt_ll_ts[i].injection_table,old,sizeof(DltUserInjectionCallback)*j); free(old); } @@ -1613,36 +1925,42 @@ int dlt_register_injection_callback(DltContext *handle, uint32_t service_id, return 0; } -int dlt_user_trace_network(DltContext *handle, DltNetworkTraceType nw_trace_type, uint16_t header_len, void *header, uint16_t payload_len, void *payload) -{ - DltContextData log; +/** + * NW Trace related + */ - if (dlt_user_initialised==0) - { - if (dlt_init()<0) - { - return -1; - } - } - if (dlt_user_log_init(handle, &log)==-1) - { +int check_buffer() +{ + int total_size, used_size; + dlt_user_check_buffer(&total_size, &used_size); + + if((total_size - used_size) < (total_size/2)) + { return -1; - } + } + return 1; +} - if (handle==0) - { - return -1; - } +/** + * Send the start of a segment chain. + * Returns -1 on failure + */ +int dlt_user_trace_network_segmented_start(uint16_t *id, DltContext *handle, DltNetworkTraceType nw_trace_type, uint16_t header_len, void *header, uint16_t payload_len) +{ - /* Commented out because of DltNetworkTraceType: + DltContextData log; + struct timeval tv; - if ((nw_trace_type<=0) || (nw_trace_type>0x15)) + if (handle==NULL) { return -1; } - */ + if (dlt_user_log_init(handle, &log)==-1) + { + return -1; + } DLT_SEM_LOCK(); @@ -1660,26 +1978,51 @@ int dlt_user_trace_network(DltContext *handle, DltNetworkTraceType nw_trace_type log.trace_status = nw_trace_type; log.size = 0; - if (header==0) + gettimeofday(&tv, NULL); + *id = tv.tv_usec; + + /* Write identifier */ + if(dlt_user_log_write_string(&log, "NWST") < 0) { - header_len=0; + return -1; } - /* Write header and its length */ - if (dlt_user_log_write_raw(&log, header, header_len)==-1) + /* Write stream handle */ + if(dlt_user_log_write_uint16(&log, *id) < 0) { return -1; } - if (payload==0) + /* Write header */ + if(dlt_user_log_write_raw(&log, header, header_len) < 0) { - payload_len=0; + return -1; } - /* Write payload and its length */ - if (dlt_user_log_write_raw(&log, payload, payload_len)==-1) + /* Write size of payload */ + if(dlt_user_log_write_uint16(&log, payload_len) < 0) { - return -1; + return -1; + } + + /* Write expected segment count */ + uint16_t segment_count = payload_len/DLT_MAX_TRACE_SEGMENT_SIZE+1; + + /* If segments align perfectly with segment size, avoid sending empty segment */ + if((payload_len % DLT_MAX_TRACE_SEGMENT_SIZE) == 0) + { + segment_count--; + } + + if(dlt_user_log_write_uint16(&log, segment_count) < 0) + { + return -1; + } + + /* Write length of one segment */ + if(dlt_user_log_write_uint16(&log, DLT_MAX_TRACE_SEGMENT_SIZE) < 0) + { + return -1; } /* Send log */ @@ -1689,15 +2032,441 @@ int dlt_user_trace_network(DltContext *handle, DltNetworkTraceType nw_trace_type { DLT_SEM_FREE(); } - return 0; } -int dlt_log_string(DltContext *handle,DltLogLevelType loglevel, const char *text) +int dlt_user_trace_network_segmented_segment(uint16_t id, DltContext *handle, DltNetworkTraceType nw_trace_type, int sequence, uint16_t payload_len, void *payload) { - DltContextData log; + while(check_buffer() < 0) + { + usleep(1000*50); // Wait 50ms + dlt_user_log_resend_buffer(); + } - if (dlt_user.verbose_mode==0) + if (handle==NULL) + { + return -1; + } + + DltContextData log; + + if (dlt_user_log_init(handle, &log)==-1) + { + return -1; + } + + DLT_SEM_LOCK(); + + if (dlt_user.dlt_ll_ts==0) + { + DLT_SEM_FREE(); + return -1; + } + + if (dlt_user.dlt_ll_ts[handle->log_level_pos].trace_status==DLT_TRACE_STATUS_ON) + { + DLT_SEM_FREE(); + + log.args_num = 0; + log.trace_status = nw_trace_type; + log.size = 0; + + /* Write identifier */ + if(dlt_user_log_write_string(&log, "NWCH") < 0) + { + return -1; + } + + /* Write stream handle */ + if(dlt_user_log_write_uint16(&log, id) < 0) + { + return -1; + } + + /* Write segment sequence number */ + if(dlt_user_log_write_uint16(&log, sequence) < 0) + { + return -1; + } + + /* Write data */ + if(dlt_user_log_write_raw(&log, payload, payload_len) < 0) + { + return -1; + } + + /* Send log */ + return dlt_user_log_send_log(&log, DLT_TYPE_NW_TRACE); + } + else + { + DLT_SEM_FREE(); + } + + /* Allow other threads to log between chunks */ + pthread_yield(); + return 0; +} + +int dlt_user_trace_network_segmented_end(uint16_t id, DltContext *handle, DltNetworkTraceType nw_trace_type) +{ + DltContextData log; + + if (handle==0) + { + return -1; + } + + if (dlt_user_log_init(handle, &log)==-1) + { + return -1; + } + + + + DLT_SEM_LOCK(); + + if (dlt_user.dlt_ll_ts==0) + { + DLT_SEM_FREE(); + return -1; + } + + if (dlt_user.dlt_ll_ts[handle->log_level_pos].trace_status==DLT_TRACE_STATUS_ON) + { + DLT_SEM_FREE(); + + log.args_num = 0; + log.trace_status = nw_trace_type; + log.size = 0; + + /* Write identifier */ + if(dlt_user_log_write_string(&log, "NWEN") < 0) + { + return -1; + } + + /* Write stream handle */ + if(dlt_user_log_write_uint(&log, id) < 0) + { + return -1; + } + + /* Send log */ + return dlt_user_log_send_log(&log, DLT_TYPE_NW_TRACE); + } + else + { + DLT_SEM_FREE(); + } + return 0; +} + + +void dlt_user_trace_network_segmented_thread(void *unused) +{ + /* Unused on purpose. */ + (void) unused; + + s_segmented_data *data; + + while(1) + { + // Wait until message queue is initialized + pthread_mutex_lock(&mq_mutex); + if(dlt_user.dlt_segmented_queue_read_handle < 0) + { + pthread_cond_wait(&mq_init_condition, &mq_mutex); + } + pthread_mutex_unlock(&mq_mutex); + + ssize_t read = mq_receive(dlt_user.dlt_segmented_queue_read_handle, (char *)&data, + sizeof(s_segmented_data * ), NULL); + + if(read != sizeof(s_segmented_data *)) + { + + char str[255]; + snprintf(str,254,"NWTSegmented: Error while reading queue: %s \n",strerror(errno)); + dlt_log(LOG_CRIT, str); + continue; + } + + /* Indicator just to try to flush the buffer */ + if(data->payload_len == DLT_DELAYED_RESEND_INDICATOR_PATTERN) + { + // Sleep 100ms, to allow other process to read FIFO + usleep(100*1000); + if(dlt_user_log_resend_buffer() < 0) + { + // Requeue if still not empty + if ( dlt_user_queue_resend() < 0 ) + dlt_log(LOG_WARNING, "Failed to queue resending in dlt_user_trace_network_segmented_thread.\n"); + } + free(data); + continue; + } + + dlt_user_trace_network_segmented_thread_segmenter(data); + + /* Send the end message */ + DltReturnValue err = dlt_user_trace_network_segmented_end(data->id, data->handle, data->nw_trace_type); + if(err == DLT_RETURN_BUFFER_FULL || err == DLT_RETURN_ERROR) + { + dlt_log(LOG_ERR,"NWTSegmented: Could not send end segment.\n"); + } + + /* Free resources */ + free(data->header); + free(data->payload); + free(data); + } +} + +void dlt_user_trace_network_segmented_thread_segmenter(s_segmented_data *data) +{ + /* Segment the data and send the chunks */ + void *ptr = NULL; + uint16_t offset = 0; + uint16_t sequence = 0; + do + { + uint16_t len = 0; + if(offset + DLT_MAX_TRACE_SEGMENT_SIZE > data->payload_len) + { + len = data->payload_len - offset; + } + else + { + len = DLT_MAX_TRACE_SEGMENT_SIZE; + } + /* If payload size aligns perfectly with segment size, avoid sending empty segment */ + if(len == 0) + { + break; + } + + ptr = data->payload + offset; + DltReturnValue err = dlt_user_trace_network_segmented_segment(data->id, data->handle, data->nw_trace_type, sequence++, len, ptr); + if(err == DLT_RETURN_BUFFER_FULL || err == DLT_RETURN_ERROR) + { + dlt_log(LOG_ERR,"NWTSegmented: Could not send segment. Aborting.\n"); + break; // loop + } + offset += len; + }while(ptr < data->payload + data->payload_len); +} + + +int dlt_user_trace_network_segmented(DltContext *handle, DltNetworkTraceType nw_trace_type, uint16_t header_len, void *header, uint16_t payload_len, void *payload) +{ + /* Send as normal trace if possible */ + if(header_len+payload_len+sizeof(uint16_t) < DLT_USER_BUF_MAX_SIZE) { + return dlt_user_trace_network(handle, nw_trace_type, header_len, header, payload_len, payload); + } + + /* Allocate Memory */ + s_segmented_data *thread_data = malloc(sizeof(s_segmented_data)); + if(thread_data == NULL) + { + return -1; + } + thread_data->header = malloc(header_len); + if(thread_data->header == NULL) + { + free(thread_data); + return -1; + } + thread_data->payload = malloc(payload_len); + if(thread_data->payload == NULL) + { + free(thread_data->header); + free(thread_data); + return -1; + } + + /* Copy data */ + thread_data->handle = handle; + thread_data->nw_trace_type = nw_trace_type; + thread_data->header_len = header_len; + memcpy(thread_data->header, header, header_len); + thread_data->payload_len = payload_len; + memcpy(thread_data->payload, payload, payload_len); + + /* Send start message */ + DltReturnValue err = dlt_user_trace_network_segmented_start(&(thread_data->id), + thread_data->handle, thread_data->nw_trace_type, + thread_data->header_len, thread_data->header, + thread_data->payload_len); + if(err == DLT_RETURN_BUFFER_FULL || err == DLT_RETURN_ERROR) + { + dlt_log(LOG_ERR,"NWTSegmented: Could not send start segment. Aborting.\n"); + free(thread_data->header); + free(thread_data->payload); + free(thread_data); + return -1; + } + + /* Open queue if it is not open */ + if(dlt_init_message_queue() < 0) + { + dlt_log(LOG_ERR, "NWTSegmented: Could not open queue.\n"); + free(thread_data->header); + free(thread_data->payload); + free(thread_data); + + return -1; + } + + /* Add to queue */ + if(mq_send(dlt_user.dlt_segmented_queue_write_handle, + (char *)&thread_data, sizeof(s_segmented_data *), 1) < 0) + { + if(errno == EAGAIN) + { + dlt_log(LOG_ERR, "NWTSegmented: Queue full. Message discarded.\n"); + } + free(thread_data->header); + free(thread_data->payload); + free(thread_data); + char str[256]; + snprintf(str,255,"NWTSegmented: Could not write into queue: %s \n",strerror(errno)); + dlt_log(LOG_CRIT, str); + return -1; + } + + //thread_data will be freed by the receiver function + //coverity[leaked_storage] + return 0; +} + +int dlt_user_trace_network(DltContext *handle, DltNetworkTraceType nw_trace_type, uint16_t header_len, void *header, uint16_t payload_len, void *payload) +{ + return dlt_user_trace_network_truncated(handle, nw_trace_type, header_len, header, payload_len, payload, 1); +} + +int dlt_user_trace_network_truncated(DltContext *handle, DltNetworkTraceType nw_trace_type, uint16_t header_len, void *header, uint16_t payload_len, void *payload, int allow_truncate) +{ + DltContextData log; + + if (dlt_user_initialised==0) + { + if (dlt_init()<0) + { + return -1; + } + } + + if (dlt_user_log_init(handle, &log)==-1) + { + return -1; + } + + if (handle==0) + { + return -1; + } + + /* Commented out because of DltNetworkTraceType: + + if ((nw_trace_type<=0) || (nw_trace_type>0x15)) + { + return -1; + } + + */ + + DLT_SEM_LOCK(); + + if (dlt_user.dlt_ll_ts==0) + { + DLT_SEM_FREE(); + return -1; + } + + if (dlt_user.dlt_ll_ts[handle->log_level_pos].trace_status==DLT_TRACE_STATUS_ON) + { + DLT_SEM_FREE(); + + log.args_num = 0; + log.trace_status = nw_trace_type; + log.size = 0; + + if (header==0) + { + header_len=0; + } + + /* If truncation is allowed, check if we must do it */ + if(allow_truncate > 0 && (header_len+payload_len+sizeof(uint16_t))>DLT_USER_BUF_MAX_SIZE) + { + /* Identify as truncated */ + if(dlt_user_log_write_string(&log, "NWTR") < 0) + { + return -1; + } + + /* Write header and its length */ + if (dlt_user_log_write_raw(&log, header, header_len) < 0) + { + return -1; + } + + /* Write original size of payload */ + if(dlt_user_log_write_uint16(&log, payload_len) < 0) + { + return -1; + } + + /** + * Calculate maximum avaialble space in sending buffer after headers. + */ + + int truncated_payload_len = DLT_USER_BUF_MAX_SIZE - + log.size - sizeof(uint16_t) - sizeof(uint32_t); + + /* Write truncated payload */ + if (dlt_user_log_write_raw(&log, payload, truncated_payload_len) < 0) + { + return -1; + } + } + else /* Truncation not allowed or data short enough */ + { + /* Write header and its length */ + if (dlt_user_log_write_raw(&log, header, header_len)==-1) + { + return -1; + } + + if (payload==0) + { + payload_len=0; + } + + /* Write payload and its length */ + if (dlt_user_log_write_raw(&log, payload, payload_len)==-1) + { + return -1; + } + } + + /* Send log */ + return dlt_user_log_send_log(&log, DLT_TYPE_NW_TRACE); + } + else + { + DLT_SEM_FREE(); + } + + return 0; +} + +int dlt_log_string(DltContext *handle,DltLogLevelType loglevel, const char *text) +{ + DltContextData log; + + if (dlt_user.verbose_mode==0) { return -1; } @@ -1707,7 +2476,7 @@ int dlt_log_string(DltContext *handle,DltLogLevelType loglevel, const char *text return -1; } - if (dlt_user_log_write_start(handle,&log,loglevel)) + if (dlt_user_log_write_start(handle,&log,loglevel)>0) { if (dlt_user_log_write_string(&log,text)==-1) { @@ -1736,7 +2505,7 @@ int dlt_log_string_int(DltContext *handle,DltLogLevelType loglevel, const char * return -1; } - if (dlt_user_log_write_start(handle,&log,loglevel)) + if (dlt_user_log_write_start(handle,&log,loglevel)>0) { if (dlt_user_log_write_string(&log,text)==-1) { @@ -1769,7 +2538,7 @@ int dlt_log_string_uint(DltContext *handle,DltLogLevelType loglevel, const char return -1; } - if (dlt_user_log_write_start(handle,&log,loglevel)) + if (dlt_user_log_write_start(handle,&log,loglevel)>0) { if (dlt_user_log_write_string(&log,text)==-1) { @@ -1802,7 +2571,7 @@ int dlt_log_int(DltContext *handle,DltLogLevelType loglevel, int data) return -1; } - if (dlt_user_log_write_start(handle,&log,loglevel)) + if (dlt_user_log_write_start(handle,&log,loglevel)>0) { if (dlt_user_log_write_int(&log,data)==-1) { @@ -1831,7 +2600,7 @@ int dlt_log_uint(DltContext *handle,DltLogLevelType loglevel, unsigned int data) return -1; } - if (dlt_user_log_write_start(handle,&log,loglevel)) + if (dlt_user_log_write_start(handle,&log,loglevel)>0) { if (dlt_user_log_write_uint(&log,data)==-1) { @@ -1860,7 +2629,7 @@ int dlt_log_raw(DltContext *handle,DltLogLevelType loglevel, void *data,uint16_t return -1; } - if (dlt_user_log_write_start(handle,&log,loglevel)) + if (dlt_user_log_write_start(handle,&log,loglevel)>0) { if (dlt_user_log_write_raw(&log,data,length)==-1) { @@ -1937,7 +2706,7 @@ int dlt_disable_local_print(void) return 0; } -void dlt_user_receiverthread_function(void *ptr) +void dlt_user_receiverthread_function(__attribute__((unused)) void *ptr) { while (1) { @@ -1965,60 +2734,106 @@ int dlt_user_log_init(DltContext *handle, DltContextData *log) } log->handle = handle; - log->mcnt = 0; return 0; } -int dlt_user_log_send_log(DltContextData *log, int mtype) +int dlt_user_queue_resend(void) +{ + if(dlt_user.dlt_log_handle < 0) + { + // Fail silenty. FIFO is not open yet + return -1; + } + /** + * Ask segmented thread to try emptying the buffer soon. + * This will be freed in dlt_user_trace_network_segmented_thread + * */ + s_segmented_data *resend_data = malloc(sizeof(s_segmented_data)); + + if (NULL == resend_data) + { + return -1; + } + + resend_data->payload_len = DLT_DELAYED_RESEND_INDICATOR_PATTERN; + + + + /* Open queue if it is not open */ + if(dlt_init_message_queue() < 0) + { + dlt_log(LOG_ERR, "NWTSegmented: Could not open queue.\n"); + free(resend_data); + return -1; + } + + if(mq_send(dlt_user.dlt_segmented_queue_write_handle, (char *)&resend_data, sizeof(s_segmented_data *), 1) < 0) + { + char str[255]; + snprintf(str,254,"Could not request resending.: %s \n",strerror(errno)); + dlt_log(LOG_CRIT, str); + free(resend_data); + return -1; + } + //thread_data will be freed by the receiver function + //coverity[leaked_storage] + return 0; +} + +DltReturnValue dlt_user_log_send_log(DltContextData *log, int mtype) { DltMessage msg; DltUserHeader userheader; int32_t len; - DltReturnValue ret; + DltReturnValue ret = DLT_RETURN_OK; if (log==0) { - return -1; + return DLT_RETURN_ERROR; } if (log->handle==0) { - return -1; + return DLT_RETURN_ERROR; } if (dlt_user.appID[0]=='\0') { - return -1; + return DLT_RETURN_ERROR; } if (log->handle->contextID[0]=='\0') { - return -1; + return DLT_RETURN_ERROR; } if ((mtypeDLT_TYPE_CONTROL)) { - return -1; + return DLT_RETURN_ERROR; } /* also for Trace messages */ +#ifdef DLT_SHM_ENABLE + if (dlt_user_set_userheader(&userheader, DLT_USER_MESSAGE_LOG_SHM)==-1) +#else if (dlt_user_set_userheader(&userheader, DLT_USER_MESSAGE_LOG)==-1) +#endif { - return -1; + return DLT_RETURN_ERROR; } if (dlt_message_init(&msg,0)==-1) { - return -1; + return DLT_RETURN_ERROR; } msg.storageheader = (DltStorageHeader*)msg.headerbuffer; if (dlt_set_storageheader(msg.storageheader,dlt_user.ecuID)==-1) { - return -1; + return DLT_RETURN_ERROR; } msg.standardheader = (DltStandardHeader*)(msg.headerbuffer + sizeof(DltStorageHeader)); @@ -2041,7 +2856,7 @@ int dlt_user_log_send_log(DltContextData *log, int mtype) msg.standardheader->htyp = (msg.standardheader->htyp | DLT_HTYP_MSBF); #endif - msg.standardheader->mcnt = log->mcnt++; + msg.standardheader->mcnt = log->handle->mcnt++; /* Set header extra parameters */ dlt_set_id(msg.headerextra.ecu,dlt_user.ecuID); @@ -2050,7 +2865,7 @@ int dlt_user_log_send_log(DltContextData *log, int mtype) if (dlt_message_set_extraparameters(&msg,0)==-1) { - return -1; + return DLT_RETURN_ERROR; } /* Fill out extended header, if extended header should be provided */ @@ -2074,7 +2889,7 @@ int dlt_user_log_send_log(DltContextData *log, int mtype) default: { /* This case should not occur */ - return -1; + return DLT_RETURN_ERROR; break; } } @@ -2101,7 +2916,7 @@ int dlt_user_log_send_log(DltContextData *log, int mtype) if (len>UINT16_MAX) { dlt_log(LOG_CRIT,"Huge message discarded!\n"); - return -1; + return DLT_RETURN_ERROR; } msg.standardheader->len = DLT_HTOBE_16(len); @@ -2114,7 +2929,7 @@ int dlt_user_log_send_log(DltContextData *log, int mtype) { if (dlt_user_print_msg(&msg, log)==-1) { - return -1; + return DLT_RETURN_ERROR; } } } @@ -2123,7 +2938,7 @@ int dlt_user_log_send_log(DltContextData *log, int mtype) { /* log to file */ ret=dlt_user_log_out2(dlt_user.dlt_log_handle, msg.headerbuffer, msg.headersize, log->buffer, log->size); - return ((ret==DLT_RETURN_OK)?0:-1); + return ret; } else { @@ -2138,35 +2953,78 @@ int dlt_user_log_send_log(DltContextData *log, int mtype) } } - /* log to FIFO */ - ret = dlt_user_log_out3(dlt_user.dlt_log_handle, - &(userheader), sizeof(DltUserHeader), - msg.headerbuffer+sizeof(DltStorageHeader), msg.headersize-sizeof(DltStorageHeader), - log->buffer, log->size); - + /* try to resent old data first */ + ret = DLT_RETURN_OK; + if(dlt_user.dlt_log_handle!=-1) + ret = dlt_user_log_resend_buffer(); + if(ret==DLT_RETURN_OK) + { + /* resend ok or nothing to resent */ +#ifdef DLT_SHM_ENABLE + if(dlt_user.dlt_log_handle!=-1) + dlt_shm_push(&dlt_user.dlt_shm,msg.headerbuffer+sizeof(DltStorageHeader), msg.headersize-sizeof(DltStorageHeader), + log->buffer, log->size,0,0); + + /* log to FIFO */ + ret = dlt_user_log_out3(dlt_user.dlt_log_handle, + &(userheader), sizeof(DltUserHeader), + 0, 0, + 0, 0); +#else + /* log to FIFO */ +#ifdef DLT_TEST_ENABLE + if(dlt_user.corrupt_user_header) { + userheader.pattern[0]=0xff; + userheader.pattern[1]=0xff; + userheader.pattern[2]=0xff; + userheader.pattern[3]=0xff; + } + if(dlt_user.corrupt_message_size) { + msg.standardheader->len = DLT_HTOBE_16(dlt_user.corrupt_message_size_size); + } +#endif + ret = dlt_user_log_out3(dlt_user.dlt_log_handle, + &(userheader), sizeof(DltUserHeader), + msg.headerbuffer+sizeof(DltStorageHeader), msg.headersize-sizeof(DltStorageHeader), + log->buffer, log->size); +#endif + } + /* store message in ringbuffer, if an error has occured */ if (ret!=DLT_RETURN_OK) { DLT_SEM_LOCK(); - if (dlt_ringbuffer_put3(&(dlt_user.rbuf), - &(userheader), sizeof(DltUserHeader), + if (dlt_buffer_push3(&(dlt_user.startup_buffer), + (unsigned char *)&(userheader), sizeof(DltUserHeader), msg.headerbuffer+sizeof(DltStorageHeader), msg.headersize-sizeof(DltStorageHeader), log->buffer, log->size)==-1) { dlt_log(LOG_ERR,"Storing message to history buffer failed! Message discarded.\n"); + ret = DLT_RETURN_BUFFER_FULL; } DLT_SEM_FREE(); + + // Fail silenty if FIFO is not open + if(dlt_user_queue_resend() < 0 && dlt_user.dlt_log_handle >= 0) + { + dlt_log(LOG_WARNING, "dlt_user_log_send_log: Failed to queue resending.\n"); + } } switch (ret) { + case DLT_RETURN_BUFFER_FULL: + { + /* Buffer full */ + return DLT_RETURN_BUFFER_FULL; + } case DLT_RETURN_PIPE_FULL: { /* data could not be written */ dlt_user.overflow = 1; - return -1; + return DLT_RETURN_PIPE_FULL; } case DLT_RETURN_PIPE_ERROR: { @@ -2174,31 +3032,36 @@ int dlt_user_log_send_log(DltContextData *log, int mtype) close(dlt_user.dlt_log_handle); dlt_user.dlt_log_handle = -1; +#ifdef DLT_SHM_ENABLE + /* free shared memory */ + dlt_shm_free_client(&dlt_user.dlt_shm); +#endif + if (dlt_user.local_print_mode == DLT_PM_AUTOMATIC) { dlt_user_print_msg(&msg, log); } - return -1; + return DLT_RETURN_PIPE_ERROR; } case DLT_RETURN_ERROR: { /* other error condition */ - return -1; + return DLT_RETURN_ERROR; } case DLT_RETURN_OK: { - return 0; + return DLT_RETURN_OK; } default: { /* This case should never occur. */ - return -1; + return DLT_RETURN_ERROR; } } } - return 0; + return DLT_RETURN_OK; } int dlt_user_log_send_register_application(void) @@ -2239,7 +3102,31 @@ int dlt_user_log_send_register_application(void) /* log to FIFO */ ret=dlt_user_log_out3(dlt_user.dlt_log_handle, &(userheader), sizeof(DltUserHeader), &(usercontext), sizeof(DltUserControlMsgRegisterApplication),dlt_user.application_description,usercontext.description_length); - return ((ret==DLT_RETURN_OK)?0:-1); + + /* store message in ringbuffer, if an error has occured */ + if (ret!=DLT_RETURN_OK) + { + DLT_SEM_LOCK(); + + if (dlt_buffer_push3(&(dlt_user.startup_buffer), + (unsigned char *)&(userheader), sizeof(DltUserHeader), + (const unsigned char*)&(usercontext), sizeof(DltUserControlMsgRegisterApplication), + (const unsigned char*)dlt_user.application_description, usercontext.description_length)==-1) + { + dlt_log(LOG_ERR,"Storing message to history buffer failed! Message discarded.\n"); + DLT_SEM_FREE(); + return -1; + } + + DLT_SEM_FREE(); + + if(dlt_user_queue_resend() < 0 && dlt_user.dlt_log_handle >= 0) + { + dlt_log(LOG_WARNING, "dlt_user_log_send_register_application: Failed to queue resending.\n"); + } + } + + return 0; } int dlt_user_log_send_unregister_application(void) @@ -2326,7 +3213,32 @@ int dlt_user_log_send_register_context(DltContextData *log) /* log to FIFO */ ret=dlt_user_log_out3(dlt_user.dlt_log_handle, &(userheader), sizeof(DltUserHeader), &(usercontext), sizeof(DltUserControlMsgRegisterContext),log->context_description,usercontext.description_length); - return ((ret==DLT_RETURN_OK)?0:-1); + + /* store message in ringbuffer, if an error has occured */ + if (ret!=DLT_RETURN_OK) + { + DLT_SEM_LOCK(); + + if (dlt_buffer_push3(&(dlt_user.startup_buffer), + (unsigned char *)&(userheader), sizeof(DltUserHeader), + (const unsigned char*)&(usercontext), sizeof(DltUserControlMsgRegisterContext), + (const unsigned char*)log->context_description, usercontext.description_length)==-1) + { + dlt_log(LOG_ERR,"Storing message to history buffer failed! Message discarded.\n"); + DLT_SEM_FREE(); + return -1; + } + + DLT_SEM_FREE(); + + if(dlt_user_queue_resend() < 0 && dlt_user.dlt_log_handle >= 0) + { + dlt_log(LOG_WARNING, "dlt_user_log_send_register_context: Failed to queue resending.\n"); + } + } + + return 0; + } int dlt_user_log_send_unregister_context(DltContextData *log) @@ -2417,10 +3329,38 @@ int dlt_send_app_ll_ts_limit(const char *appid, DltLogLevelType loglevel, DltTra return ((ret==DLT_RETURN_OK)?0:-1); } +int dlt_user_log_send_log_mode(DltUserLogMode mode) +{ + DltUserHeader userheader; + DltUserControlMsgLogMode logmode; + + DltReturnValue ret; + + /* set userheader */ + if (dlt_user_set_userheader(&userheader, DLT_USER_MESSAGE_LOG_MODE)==-1) + { + return -1; + } + + /* set data */ + logmode.log_mode = (unsigned char) mode; + + if (dlt_user.dlt_is_file) + { + return 0; + } + + /* log to FIFO */ + ret=dlt_user_log_out2(dlt_user.dlt_log_handle, &(userheader), sizeof(DltUserHeader), &(logmode), sizeof(DltUserControlMsgLogMode)); + return ((ret==DLT_RETURN_OK)?0:-1); +} + int dlt_user_print_msg(DltMessage *msg, DltContextData *log) { uint8_t *databuffer_tmp; int32_t datasize_tmp; + int32_t databuffersize_tmp; + static char text[DLT_USER_TEXT_LENGTH]; if ((msg==0) || (log==0)) { @@ -2430,6 +3370,7 @@ int dlt_user_print_msg(DltMessage *msg, DltContextData *log) /* Save variables before print */ databuffer_tmp = msg->databuffer; datasize_tmp = msg->datasize; + databuffersize_tmp = msg->databuffersize; /* Act like a receiver, convert header back to host format */ msg->standardheader->len = DLT_BETOH_16(msg->standardheader->len); @@ -2437,6 +3378,7 @@ int dlt_user_print_msg(DltMessage *msg, DltContextData *log) msg->databuffer = log->buffer; msg->datasize = log->size; + msg->databuffersize = log->size; /* Print message as ASCII */ if (dlt_message_print_ascii(msg,text,DLT_USER_TEXT_LENGTH,0)==-1) @@ -2446,6 +3388,7 @@ int dlt_user_print_msg(DltMessage *msg, DltContextData *log) /* Restore variables and set len to BE*/ msg->databuffer = databuffer_tmp; + msg->databuffersize = databuffersize_tmp; msg->datasize = datasize_tmp; msg->standardheader->len = DLT_HTOBE_16(msg->standardheader->len); @@ -2458,18 +3401,26 @@ int dlt_user_log_check_user_message(void) int offset=0; int leave_while=0; - int i; + uint32_t i; DltUserHeader *userheader; DltReceiver *receiver = &(dlt_user.receiver); DltUserControlMsgLogLevel *usercontextll; - DltUserControlMsgInjection *usercontextinj; + DltUserControlMsgLogState *userlogstate; unsigned char *userbuffer; - unsigned char *inject_buffer; - if (dlt_user.dlt_user_handle!=-1) + /* For delayed calling of injection callback, to avoid deadlock */ + DltUserInjectionCallback delayed_injection_callback; + unsigned char *delayed_inject_buffer = 0; + uint32_t delayed_inject_data_length = 0; + + /* Ensure that callback is null before searching for it */ + delayed_injection_callback.injection_callback = 0; + delayed_injection_callback.service_id = 0; + + if (dlt_user.dlt_user_handle!=DLT_FD_INIT) { while (1) { @@ -2482,7 +3433,7 @@ int dlt_user_log_check_user_message(void) /* look through buffer as long as data is in there */ while (1) { - if (receiver->bytesRcvd < sizeof(DltUserHeader)) + if (receiver->bytesRcvd < (int32_t)sizeof(DltUserHeader)) { break; } @@ -2501,10 +3452,11 @@ int dlt_user_log_check_user_message(void) offset++; } - while ((sizeof(DltUserHeader)+offset)<=receiver->bytesRcvd); + while ((int32_t)(sizeof(DltUserHeader)+offset)<=receiver->bytesRcvd); /* Check for user header pattern */ - if (dlt_user_check_userheader(userheader)==0) + if (dlt_user_check_userheader(userheader)<0 || + dlt_user_check_userheader(userheader)==0) { break; } @@ -2520,7 +3472,7 @@ int dlt_user_log_check_user_message(void) { case DLT_USER_MESSAGE_LOG_LEVEL: { - if (receiver->bytesRcvd < (sizeof(DltUserHeader)+sizeof(DltUserControlMsgLogLevel))) + if (receiver->bytesRcvd < (int32_t)(sizeof(DltUserHeader)+sizeof(DltUserControlMsgLogLevel))) { leave_while=1; break; @@ -2533,7 +3485,7 @@ int dlt_user_log_check_user_message(void) { DLT_SEM_LOCK(); - if ((usercontextll->log_level_pos>=0) && (usercontextll->log_level_poslog_level_pos >= 0) && (usercontextll->log_level_pos < (int32_t)dlt_user.dlt_ll_ts_num_entries)) { // printf("Store ll, ts\n"); if (dlt_user.dlt_ll_ts) @@ -2556,7 +3508,7 @@ int dlt_user_log_check_user_message(void) case DLT_USER_MESSAGE_INJECTION: { /* At least, user header, user context, and service id and data_length of injected message is available */ - if (receiver->bytesRcvd < (sizeof(DltUserHeader)+sizeof(DltUserControlMsgInjection))) + if (receiver->bytesRcvd < (int32_t)(sizeof(DltUserHeader)+sizeof(DltUserControlMsgInjection))) { leave_while = 1; break; @@ -2564,12 +3516,11 @@ int dlt_user_log_check_user_message(void) usercontextinj = (DltUserControlMsgInjection*) (receiver->buf+sizeof(DltUserHeader)); userbuffer = (unsigned char*) (receiver->buf+sizeof(DltUserHeader)+sizeof(DltUserControlMsgInjection)); - inject_buffer = 0; if (userbuffer!=0) { - if (receiver->bytesRcvd < (sizeof(DltUserHeader)+sizeof(DltUserControlMsgInjection)+usercontextinj->data_length_inject)) + if (receiver->bytesRcvd < (int32_t)(sizeof(DltUserHeader)+sizeof(DltUserControlMsgInjection)+usercontextinj->data_length_inject)) { leave_while = 1; break; @@ -2585,28 +3536,18 @@ int dlt_user_log_check_user_message(void) if ((dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].injection_table) && (dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].injection_table[i].service_id == usercontextinj->service_id)) { - /* callback available, so prepare data, then call it */ - inject_buffer = malloc(usercontextinj->data_length_inject); - if (inject_buffer!=0) - { - /* copy from receiver to inject_buffer */ - memcpy(inject_buffer, userbuffer, usercontextinj->data_length_inject); - - /* call callback */ - if (dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].injection_table[i].injection_callback!=0) - { - // printf("Got injection(%d), length=%d, '%s' \n", usercontext->service_id, usercontext->data_length_inject, inject_buffer); - dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].injection_table[i].injection_callback( - usercontextinj->service_id, inject_buffer, usercontextinj->data_length_inject); - } - - if (inject_buffer!=0) - { - free(inject_buffer); - inject_buffer = 0; - } - } - + /* Prepare delayed injection callback call */ + if (dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].injection_table[i].injection_callback!=0) + { + delayed_injection_callback.injection_callback = dlt_user.dlt_ll_ts[usercontextinj->log_level_pos].injection_table[i].injection_callback; + delayed_injection_callback.service_id = usercontextinj->service_id; + delayed_inject_data_length = usercontextinj->data_length_inject; + delayed_inject_buffer = malloc(delayed_inject_data_length); + if(delayed_inject_buffer != 0) { + memcpy(delayed_inject_buffer, userbuffer, delayed_inject_data_length); + } + + } break; } } @@ -2614,6 +3555,15 @@ int dlt_user_log_check_user_message(void) DLT_SEM_FREE(); + /* Delayed injection callback call */ + if(delayed_inject_buffer != 0 && delayed_injection_callback.injection_callback != 0) { + delayed_injection_callback.injection_callback(delayed_injection_callback.service_id, delayed_inject_buffer, delayed_inject_data_length); + delayed_injection_callback.injection_callback = 0; + free(delayed_inject_buffer); + delayed_inject_buffer = NULL; + + } + /* keep not read data in buffer */ if (dlt_receiver_remove(receiver,(sizeof(DltUserHeader)+sizeof(DltUserControlMsgInjection)+usercontextinj->data_length_inject))==-1) { @@ -2622,6 +3572,25 @@ int dlt_user_log_check_user_message(void) } } break; + case DLT_USER_MESSAGE_LOG_STATE: + { + /* At least, user header, user context, and service id and data_length of injected message is available */ + if (receiver->bytesRcvd < (int32_t)(sizeof(DltUserHeader)+sizeof(DltUserControlMsgLogState))) + { + leave_while = 1; + break; + } + + userlogstate = (DltUserControlMsgLogState*) (receiver->buf+sizeof(DltUserHeader)); + dlt_user.log_state = userlogstate->log_state; + + /* keep not read data in buffer */ + if (dlt_receiver_remove(receiver,(sizeof(DltUserHeader)+sizeof(DltUserControlMsgLogState)))==-1) + { + return -1; + } + } + break; default: { dlt_log(LOG_ERR,"Invalid user message type received!\n"); @@ -2647,19 +3616,62 @@ int dlt_user_log_check_user_message(void) } /* while receive */ } /* if */ - return 0; + return DLT_RETURN_OK; } -void dlt_user_log_reattach_to_daemon(void) +int dlt_user_log_resend_buffer(void) { - int num, count, reregistered=0; + int num,count; + int size; + DltReturnValue ret; + + /* Send content of ringbuffer */ + DLT_SEM_LOCK(); + count = dlt_buffer_get_message_count(&(dlt_user.startup_buffer)); + DLT_SEM_FREE(); + + for (num=0;num0) + { +#ifdef DLT_SHM_ENABLE + dlt_shm_push(&dlt_user.dlt_shm,dlt_user.resend_buffer+sizeof(DltUserHeader),size-sizeof(DltUserHeader),0,0,0,0); + + /* log to FIFO */ + ret = dlt_user_log_out3(dlt_user.dlt_log_handle, dlt_user.resend_buffer,sizeof(DltUserHeader),0,0,0,0); +#else + /* log to FIFO */ + ret = dlt_user_log_out3(dlt_user.dlt_log_handle, dlt_user.resend_buffer,size,0,0,0,0); +#endif + + /* in case of error, keep message in ringbuffer */ + if (ret==DLT_RETURN_OK) + { + dlt_buffer_remove(&(dlt_user.startup_buffer)); + } + else + { + /* keep message in ringbuffer */ + DLT_SEM_FREE(); + return -1; + } + } + DLT_SEM_FREE(); + } + + return 0; +} - uint8_t buf[DLT_USER_RINGBUFFER_SIZE]; - size_t size; +void dlt_user_log_reattach_to_daemon(void) +{ + uint32_t num,reregistered=0; DltContext handle; DltContextData log_new; - DltReturnValue ret; if (dlt_user.dlt_log_handle<0) { @@ -2674,6 +3686,16 @@ void dlt_user_log_reattach_to_daemon(void) return; } +#ifdef DLT_SHM_ENABLE + /* init shared memory */ + if (dlt_shm_init_client(&dlt_user.dlt_shm,DLT_SHM_KEY) < 0) + { + sprintf(str,"Loging disabled, Shared memory %d cannot be created!\n",DLT_SHM_KEY); + dlt_log(LOG_WARNING, str); + //return 0; + } +#endif + dlt_log(LOG_NOTICE, "Logging re-enabled!\n"); /* Re-register application */ @@ -2688,7 +3710,7 @@ void dlt_user_log_reattach_to_daemon(void) for (num=0; num0) - { - /* log to FIFO */ - ret = dlt_user_log_out3(dlt_user.dlt_log_handle, buf,size,0,0,0,0); - - /* in case of error, push message back to ringbuffer */ - if (ret!=DLT_RETURN_OK) - { - DLT_SEM_LOCK(); - if (dlt_ringbuffer_put(&(dlt_user.rbuf), buf, size)==-1) - { - dlt_log(LOG_ERR,"Error pushing back message to history buffer. Message discarded.\n"); - } - DLT_SEM_FREE(); - - /* In case of: data could not be written, set overflow flag */ - if (ret==DLT_RETURN_PIPE_FULL) - { - dlt_user.overflow = 1; - } - } - } - - } + dlt_user_log_resend_buffer(); } } } @@ -2774,3 +3761,29 @@ int dlt_user_log_send_overflow(void) return ((ret==DLT_RETURN_OK)?0:-1); } +int dlt_user_check_buffer(int *total_size, int *used_size) +{ +#ifdef DLT_SHM_ENABLE + *total_size = dlt_shm_get_total_size(&(dlt_user.dlt_shm)); + *used_size = dlt_shm_get_used_size(&(dlt_user.dlt_shm)); +#else + *total_size = dlt_buffer_get_total_size(&(dlt_user.startup_buffer)); + *used_size = dlt_buffer_get_used_size(&(dlt_user.startup_buffer)); +#endif + + return 0; /* ok */ +} + +#ifdef DLT_TEST_ENABLE +void dlt_user_test_corrupt_user_header(int enable) +{ + dlt_user.corrupt_user_header = enable; +} +void dlt_user_test_corrupt_message_size(int enable,int16_t size) +{ + dlt_user.corrupt_message_size = enable; + dlt_user.corrupt_message_size_size = size; +} +#endif + +