+/**
+ * NW Trace related
+ */
+
+
+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;
+}
+
+/**
+ * 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)
+{
+
+ DltContextData log;
+ struct timeval tv;
+
+ if (handle==NULL)
+ {
+ return -1;
+ }
+
+ if (dlt_user_log_init(handle, &log)==-1)
+ {
+ return -1;
+ }
+
+
+ if (dlt_user.dlt_ll_ts==0)
+ {
+ return -1;
+ }
+
+ if (handle->trace_status_ptr && *(handle->trace_status_ptr)==DLT_TRACE_STATUS_ON)
+ {
+
+ log.args_num = 0;
+ log.trace_status = nw_trace_type;
+ log.size = 0;
+
+ gettimeofday(&tv, NULL);
+ *id = tv.tv_usec;
+
+ /* Write identifier */
+ if(dlt_user_log_write_string(&log, "NWST") < 0)
+ {
+ return -1;
+ }
+
+ /* Write stream handle */
+ if(dlt_user_log_write_uint16(&log, *id) < 0)
+ {
+ return -1;
+ }
+
+ /* Write header */
+ if(dlt_user_log_write_raw(&log, header, header_len) < 0)
+ {
+ return -1;
+ }
+
+ /* Write size of payload */
+ if(dlt_user_log_write_uint16(&log, payload_len) < 0)
+ {
+ 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 */
+ return dlt_user_log_send_log(&log, DLT_TYPE_NW_TRACE);
+ }
+ return 0;
+}
+
+int dlt_user_trace_network_segmented_segment(uint16_t id, DltContext *handle, DltNetworkTraceType nw_trace_type, int sequence, uint16_t payload_len, void *payload)
+{
+ while(check_buffer() < 0)
+ {
+ usleep(1000*50); // Wait 50ms
+ dlt_user_log_resend_buffer();
+ }
+
+ if (handle==NULL)
+ {
+ return -1;
+ }
+
+ DltContextData log;
+
+ if (dlt_user_log_init(handle, &log)==-1)
+ {
+ return -1;
+ }
+
+ if (dlt_user.dlt_ll_ts==0)
+ {
+ return -1;
+ }
+
+ if (handle->trace_status_ptr && *(handle->trace_status_ptr)==DLT_TRACE_STATUS_ON)
+ {
+
+ 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);
+ }
+
+ /* 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;
+ }
+
+
+
+ if (dlt_user.dlt_ll_ts==0)
+ {
+ return -1;
+ }
+
+ if (handle->trace_status_ptr && *(handle->trace_status_ptr)==DLT_TRACE_STATUS_ON)
+ {
+
+ 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);
+ }
+ return 0;
+}
+
+
+void dlt_user_trace_network_segmented_thread(void *unused)
+{
+ /* Unused on purpose. */
+ (void) unused;
+#ifdef linux
+ prctl(PR_SET_NAME, "dlt_segmented", 0, 0, 0);
+#endif
+
+ 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;
+}
+