diff options
Diffstat (limited to 'tinySIGCOMP/src/tcomp_message.c')
-rw-r--r-- | tinySIGCOMP/src/tcomp_message.c | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/tinySIGCOMP/src/tcomp_message.c b/tinySIGCOMP/src/tcomp_message.c new file mode 100644 index 0000000..6cecb79 --- /dev/null +++ b/tinySIGCOMP/src/tcomp_message.c @@ -0,0 +1,390 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org> +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + +/**@file tcomp_message.c + * @brief SIGCOMP message as per RFC 3320 subclause 7. + * A message sent from the compressor dispatcher to the decompressordispatcher. In case of a message-based transport such as UDP, a + * SigComp message corresponds to exactly one datagram. For a stream-based transport such as TCP, the SigComp messages are + * separated by reserved delimiters. + * + * @author Mamadou Diop <diopmamadou(at)yahoo.fr> + * + + */ +#include "tcomp_message.h" +#include "tcomp_nack_codes.h" + +#include "tsk_memory.h" +#include "tsk_debug.h" +#include "tsk_binaryutils.h" +#include "tsk_sha1.h" + +#include <string.h> + +#define MIN_LEN 2 +#define HEADER_GET_LEN(message) (message->headerSigComp & 0x03) +#define HEADER_GET_T(message) (message->headerSigComp & 0x04) +#define HEADER_IS_VALID(message) (message->headerSigComp >= 0xf8) + +#define HEADER_GET_DEST_VALUE(destination) ( sigcomp_encoding_destination[destination] ) +#define HEADER_GET_STATE_LENGTH(length) ( sigcomp_encoding_partial_id_length[length] ) + +static void initFeedbackItem(tcomp_message_t *message, uint8_t** start_ptr); +static void initStateId(tcomp_message_t *message, uint8_t** start_ptr, uint8_t state_len); +static void initStateful(tcomp_message_t *message, uint8_t** start_ptr, uint8_t* end_ptr); +static void initStateless(tcomp_message_t *message, uint8_t** start_ptr, uint8_t* end_ptr, int32_t *nack_code); +static void initNack(tcomp_message_t *message, uint8_t** start_ptr, uint8_t* end_ptr, int32_t* nack_code); + +/* +Creates new SigComp message. +*/ +tcomp_message_t* tcomp_message_create(const void* input_ptr, tsk_size_t input_size, tsk_bool_t stream, int32_t* nack_code) +{ + tcomp_message_t *message; + + if(!nack_code){ + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + if(!input_ptr){ + TSK_DEBUG_ERROR("Invalid parameter"); + *nack_code = NACK_INTERNAL_ERROR; + return tsk_null; + } + + if(input_size < MIN_LEN){ + TSK_DEBUG_ERROR("MESSAGE_TOO_SHORT"); + *nack_code = NACK_MESSAGE_TOO_SHORT; + return tsk_null; + } + + if((message = tsk_object_new(tcomp_message_def_t))){ + uint8_t *dummy_ptr, *end_ptr; + uint8_t state_len; + + message->startPtr = input_ptr; + message->stateId = tcomp_buffer_create_null(); + message->remaining_sigcomp_buffer = tcomp_buffer_create_null(); + message->uploaded_UDVM_buffer = tcomp_buffer_create_null(); + message->ret_feedback_buffer= tcomp_buffer_create_null(); + + message->isNack = 0; + dummy_ptr = ((uint8_t*)input_ptr); + end_ptr = (dummy_ptr + input_size); + + // + message->totalSize = input_size; + message->stream_based = stream; + message->bytecodes_destination = 0; + + /* Get sigcomp header */ + message->headerSigComp = *dummy_ptr; + dummy_ptr++; + + /* Check message validity --> magic code (11111)? */ + message->isOK = HEADER_IS_VALID(message); + if(!message->isOK){ + TSK_DEBUG_ERROR("SigComp Message not valid (magic code mismatch)"); + *nack_code = NACK_INTERNAL_ERROR; + goto bail; + } + + /* Feedback item */ + if((HEADER_GET_T(message)!=0)){ + initFeedbackItem(message, &dummy_ptr); + if(!message->isOK){ + goto bail; + } + } + + /* + * If the len field is non-zero, then the SigComp message contains a state identifier + * to access a state item at the receiving endpoint. + */ + state_len = HEADER_GET_STATE_LENGTH( HEADER_GET_LEN(message) ); + if(state_len){ + initStateId(message, &dummy_ptr, state_len); + initStateful(message, &dummy_ptr, end_ptr); + TSK_DEBUG_INFO("SigComp - Decompressing stateful message with state id ="); + tcomp_buffer_print(message->stateId); + } + else + { + if( !*dummy_ptr && !(*(dummy_ptr+1)&0xf0) ){ + // "code_len" field of zero --> it's a nack + initNack(message, &dummy_ptr, end_ptr, nack_code); + } + else{ + initStateless(message, &dummy_ptr, end_ptr, nack_code); + } + } + + /* + * The fields (RFC 3320 section 7) except for the "remaining SigComp message" are referred to + * as the "SigComp header" (note that this may include the uploaded UDVM bytecode). + */ + if(message->isOK){ + message->header_size = ( message->totalSize - tcomp_buffer_getSize(message->remaining_sigcomp_buffer)); + } + } + else{ + TSK_DEBUG_ERROR("Failed to create new SigComp message"); + } + +bail: + if(message && !message->isOK){ + TSK_OBJECT_SAFE_FREE(message); + } + + return message; +} + +/* +Iniatizes the feedback item field. +*/ +static void initFeedbackItem(tcomp_message_t *message, uint8_t** start_ptr) +{ + /* + 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + +---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+ + | 0 | returned_feedback_field | | 1 | returned_feedback_length | + +---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+ + | | + : returned_feedback_field : + | | + +---+---+---+---+---+---+---+---+ + */ + if((**start_ptr) <= 128){ + tcomp_buffer_referenceBuff(message->ret_feedback_buffer, *start_ptr, 1); + (void)(*start_ptr++); + } + else{ + tcomp_buffer_referenceBuff(message->ret_feedback_buffer, *start_ptr, 1+(**start_ptr&0x7f)); + *start_ptr += tcomp_buffer_getSize(message->ret_feedback_buffer); + } +} + +/* +Initializes the state identifier field. +*/ +static void initStateId(tcomp_message_t *message, uint8_t** start_ptr, uint8_t state_len) +{ + tcomp_buffer_referenceBuff(message->stateId, *start_ptr, state_len); + *start_ptr += state_len; +} + +/* +Initializes a stateful SigComp message. +*/ +static void initStateful(tcomp_message_t *message, uint8_t** start_ptr, uint8_t* end_ptr) +{ + /* + +---+---+---+---+---+---+---+---+ + | | + : partial state identifier : + | | + +---+---+---+---+---+---+---+---+ + | | + : remaining SigComp message : + | | + +---+---+---+---+---+---+---+---+ + */ + message->isOK &= (*start_ptr<=end_ptr); + if(message->isOK){ + tcomp_buffer_referenceBuff(message->remaining_sigcomp_buffer, *start_ptr, + ((end_ptr-*start_ptr))); + } +} + +/* +Initializes a stateless SigComp message. +*/ +static void initStateless(tcomp_message_t *message, uint8_t** start_ptr, uint8_t* end_ptr, int32_t *nack_code) +{ + int has_bytecode = (HEADER_GET_LEN(message) == 0); // No state ==> message contains udvm bytecode + message->isOK &= has_bytecode; + if(!message->isOK) return; + + /* + +---+---+---+---+---+---+---+---+ + | code_len | + +---+---+---+---+---+---+---+---+ + | code_len | destination | + +---+---+---+---+---+---+---+---+ + | | + : uploaded UDVM bytecode : + | | + +---+---+---+---+---+---+---+---+ + | | + : remaining SigComp message : + | | + +---+---+---+---+---+---+---+---+ + */ + { + uint32_t code_len1, bytecodes_len; + uint8_t code_len2, destination, *bytecodes_uploaded_udvm, *remaining_SigComp_message; + + uint8_t* dummy_ptr = ((uint8_t*)*start_ptr); + + /* Code_len --> 12bits [8+4] */ + code_len1 = *dummy_ptr; dummy_ptr++; /* skip first code_len 8bits */ + code_len2 = (*dummy_ptr) & 0xf0; /* code_len 4 remaining bits */ + destination = (*dummy_ptr) & 0x0f; /* 4bits after code_len */ + dummy_ptr++; /* skip code_len 4bits + destination 4bits ==> 1-byte */ + + /* Get bytecodes length (12bits) */ + bytecodes_len = ( (code_len1<<4)|(code_len2>>4) ); + + /* Starting memory address (code destination address). In UDVM. */ + message->bytecodes_destination = HEADER_GET_DEST_VALUE(destination); + if((message->bytecodes_destination < 128) || (message->bytecodes_destination > 1024)){ + TSK_DEBUG_ERROR("INVALID_CODE_LOCATION"); + *nack_code = NACK_INVALID_CODE_LOCATION; + message->isOK = 0; + return; + } + + /* Uploaded UDVM pointer */ + bytecodes_uploaded_udvm = dummy_ptr; /* SigComp header, feedback_item, code_len and destination have been skipped */ + + /* Skip uploaded udvm */ + dummy_ptr += bytecodes_len; + + /* remaining SigComp message */ + remaining_SigComp_message = dummy_ptr; + + /* check that remaining sigcomp message is valide */ + if( !(message->isOK &= (remaining_SigComp_message <= end_ptr )) ){ + TSK_DEBUG_ERROR("MESSAGE_TOO_SHORT"); + *nack_code = NACK_MESSAGE_TOO_SHORT; + return; + } + + // + // Setting buffers + // + tcomp_buffer_referenceBuff(message->uploaded_UDVM_buffer, bytecodes_uploaded_udvm, bytecodes_len); + tcomp_buffer_referenceBuff(message->remaining_sigcomp_buffer, remaining_SigComp_message, ((end_ptr-remaining_SigComp_message))); + } +} + +/* +Initializes a NACK message as per RFC 4077. +*/ +static void initNack(tcomp_message_t *message, uint8_t** start_ptr, uint8_t* end_ptr, int32_t* nack_code) +{ + /* + +---+---+---+---+---+---+---+---+ + | code_len = 0 | + +---+---+---+---+---+---+---+---+ + | code_len = 0 | version = 1 | + +---+---+---+---+---+---+---+---+ + | Reason Code | + +---+---+---+---+---+---+---+---+ + | OPCODE of failed instruction | + +---+---+---+---+---+---+---+---+ + | PC of failed instruction | + | | + +---+---+---+---+---+---+---+---+ + | | + : SHA-1 Hash of failed message : + | | + +---+---+---+---+---+---+---+---+ + | | + : Error Details : + | | + +---+---+---+---+---+---+---+---+*/ + + uint8_t* dummy_ptr; + message->isNack = 1; + if( (end_ptr - *start_ptr)<25 ){ + *nack_code = NACK_MESSAGE_TOO_SHORT; + TSK_DEBUG_ERROR("MESSAGE_TOO_SHORT"); + message->isOK = 0; + return; + } + + dummy_ptr = ((uint8_t*)*start_ptr); + dummy_ptr++; /* skip first code_len byte */ + if(!(message->isOK = (*dummy_ptr++ == NACK_VERSION))) { + return; + } + + if(!message->nack_info){ + message->nack_info = tcomp_nackinfo_create(); + } + + message->nack_info->reasonCode = *dummy_ptr++; + message->nack_info->opcode = *dummy_ptr++; + message->nack_info->pc = TSK_BINARY_GET_2BYTES(dummy_ptr); dummy_ptr+=2; + memcpy(message->nack_info->sha1, dummy_ptr, TSK_SHA1_DIGEST_SIZE); dummy_ptr += TSK_SHA1_DIGEST_SIZE; + if(dummy_ptr < end_ptr){ + /* Has error details */ + tcomp_buffer_appendBuff(message->nack_info->details, dummy_ptr, (end_ptr-dummy_ptr)); + } +} + + + + + +//======================================================== +// SigComp message object definition +// + +static tsk_object_t* tcomp_message_ctor(tsk_object_t *self, va_list * app) +{ + tcomp_message_t *message = self; + + if(message){ + } + + return self; +} + +static tsk_object_t* tcomp_message_dtor(tsk_object_t *self) +{ + tcomp_message_t *message = self; + + if(message){ + TSK_OBJECT_SAFE_FREE(message->stateId); + TSK_OBJECT_SAFE_FREE(message->remaining_sigcomp_buffer); + TSK_OBJECT_SAFE_FREE(message->uploaded_UDVM_buffer); + TSK_OBJECT_SAFE_FREE(message->ret_feedback_buffer); + TSK_OBJECT_SAFE_FREE(message->nack_info); + } + else{ + TSK_DEBUG_WARN("NULL SigComp message."); + } + + return self; +} + +static const tsk_object_def_t tcomp_message_def_s = +{ + sizeof(tcomp_message_t), + tcomp_message_ctor, + tcomp_message_dtor, + tsk_null +}; +const tsk_object_def_t* tcomp_message_def_t = &tcomp_message_def_s; |