PageRenderTime 26ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/doubango/tinySIGCOMP/src/tcomp_message.c

https://gitlab.com/iwan.aucamp/doubango
C | 390 lines | 205 code | 52 blank | 133 comment | 27 complexity | deb6ad8a3210a9a41ece62eefa0976df MD5 | raw file
  1. /*
  2. * Copyright (C) 2010-2011 Mamadou Diop.
  3. *
  4. * Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
  5. *
  6. * This file is part of Open Source Doubango Framework.
  7. *
  8. * DOUBANGO is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * DOUBANGO is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with DOUBANGO.
  20. *
  21. */
  22. /**@file tcomp_message.c
  23. * @brief SIGCOMP message as per RFC 3320 subclause 7.
  24. * A message sent from the compressor dispatcher to the decompressordispatcher. In case of a message-based transport such as UDP, a
  25. * SigComp message corresponds to exactly one datagram. For a stream-based transport such as TCP, the SigComp messages are
  26. * separated by reserved delimiters.
  27. *
  28. * @author Mamadou Diop <diopmamadou(at)yahoo.fr>
  29. *
  30. */
  31. #include "tcomp_message.h"
  32. #include "tcomp_nack_codes.h"
  33. #include "tsk_memory.h"
  34. #include "tsk_debug.h"
  35. #include "tsk_binaryutils.h"
  36. #include "tsk_sha1.h"
  37. #include <string.h>
  38. #define MIN_LEN 2
  39. #define HEADER_GET_LEN(message) (message->headerSigComp & 0x03)
  40. #define HEADER_GET_T(message) (message->headerSigComp & 0x04)
  41. #define HEADER_IS_VALID(message) (message->headerSigComp >= 0xf8)
  42. #define HEADER_GET_DEST_VALUE(destination) ( sigcomp_encoding_destination[destination] )
  43. #define HEADER_GET_STATE_LENGTH(length) ( sigcomp_encoding_partial_id_length[length] )
  44. static void initFeedbackItem(tcomp_message_t *message, uint8_t** start_ptr);
  45. static void initStateId(tcomp_message_t *message, uint8_t** start_ptr, uint8_t state_len);
  46. static void initStateful(tcomp_message_t *message, uint8_t** start_ptr, uint8_t* end_ptr);
  47. static void initStateless(tcomp_message_t *message, uint8_t** start_ptr, uint8_t* end_ptr, int32_t *nack_code);
  48. static void initNack(tcomp_message_t *message, uint8_t** start_ptr, uint8_t* end_ptr, int32_t* nack_code);
  49. /*
  50. Creates new SigComp message.
  51. */
  52. tcomp_message_t* tcomp_message_create(const void* input_ptr, tsk_size_t input_size, tsk_bool_t stream, int32_t* nack_code)
  53. {
  54. tcomp_message_t *message;
  55. if(!nack_code){
  56. TSK_DEBUG_ERROR("Invalid parameter");
  57. return tsk_null;
  58. }
  59. if(!input_ptr){
  60. TSK_DEBUG_ERROR("Invalid parameter");
  61. *nack_code = NACK_INTERNAL_ERROR;
  62. return tsk_null;
  63. }
  64. if(input_size < MIN_LEN){
  65. TSK_DEBUG_ERROR("MESSAGE_TOO_SHORT");
  66. *nack_code = NACK_MESSAGE_TOO_SHORT;
  67. return tsk_null;
  68. }
  69. if((message = tsk_object_new(tcomp_message_def_t))){
  70. uint8_t *dummy_ptr, *end_ptr;
  71. uint8_t state_len;
  72. message->startPtr = input_ptr;
  73. message->stateId = tcomp_buffer_create_null();
  74. message->remaining_sigcomp_buffer = tcomp_buffer_create_null();
  75. message->uploaded_UDVM_buffer = tcomp_buffer_create_null();
  76. message->ret_feedback_buffer= tcomp_buffer_create_null();
  77. message->isNack = 0;
  78. dummy_ptr = ((uint8_t*)input_ptr);
  79. end_ptr = (dummy_ptr + input_size);
  80. //
  81. message->totalSize = input_size;
  82. message->stream_based = stream;
  83. message->bytecodes_destination = 0;
  84. /* Get sigcomp header */
  85. message->headerSigComp = *dummy_ptr;
  86. dummy_ptr++;
  87. /* Check message validity --> magic code (11111)? */
  88. message->isOK = HEADER_IS_VALID(message);
  89. if(!message->isOK){
  90. TSK_DEBUG_ERROR("SigComp Message not valid (magic code mismatch)");
  91. *nack_code = NACK_INTERNAL_ERROR;
  92. goto bail;
  93. }
  94. /* Feedback item */
  95. if((HEADER_GET_T(message)!=0)){
  96. initFeedbackItem(message, &dummy_ptr);
  97. if(!message->isOK){
  98. goto bail;
  99. }
  100. }
  101. /*
  102. * If the len field is non-zero, then the SigComp message contains a state identifier
  103. * to access a state item at the receiving endpoint.
  104. */
  105. state_len = HEADER_GET_STATE_LENGTH( HEADER_GET_LEN(message) );
  106. if(state_len){
  107. initStateId(message, &dummy_ptr, state_len);
  108. initStateful(message, &dummy_ptr, end_ptr);
  109. TSK_DEBUG_INFO("SigComp - Decompressing stateful message with state id =");
  110. tcomp_buffer_print(message->stateId);
  111. }
  112. else
  113. {
  114. if( !*dummy_ptr && !(*(dummy_ptr+1)&0xf0) ){
  115. // "code_len" field of zero --> it's a nack
  116. initNack(message, &dummy_ptr, end_ptr, nack_code);
  117. }
  118. else{
  119. initStateless(message, &dummy_ptr, end_ptr, nack_code);
  120. }
  121. }
  122. /*
  123. * The fields (RFC 3320 section 7) except for the "remaining SigComp message" are referred to
  124. * as the "SigComp header" (note that this may include the uploaded UDVM bytecode).
  125. */
  126. if(message->isOK){
  127. message->header_size = ( message->totalSize - tcomp_buffer_getSize(message->remaining_sigcomp_buffer));
  128. }
  129. }
  130. else{
  131. TSK_DEBUG_ERROR("Failed to create new SigComp message");
  132. }
  133. bail:
  134. if(message && !message->isOK){
  135. TSK_OBJECT_SAFE_FREE(message);
  136. }
  137. return message;
  138. }
  139. /*
  140. Iniatizes the feedback item field.
  141. */
  142. static void initFeedbackItem(tcomp_message_t *message, uint8_t** start_ptr)
  143. {
  144. /*
  145. 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
  146. +---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
  147. | 0 | returned_feedback_field | | 1 | returned_feedback_length |
  148. +---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
  149. | |
  150. : returned_feedback_field :
  151. | |
  152. +---+---+---+---+---+---+---+---+
  153. */
  154. if((**start_ptr) <= 128){
  155. tcomp_buffer_referenceBuff(message->ret_feedback_buffer, *start_ptr, 1);
  156. (void)(*start_ptr++);
  157. }
  158. else{
  159. tcomp_buffer_referenceBuff(message->ret_feedback_buffer, *start_ptr, 1+(**start_ptr&0x7f));
  160. *start_ptr += tcomp_buffer_getSize(message->ret_feedback_buffer);
  161. }
  162. }
  163. /*
  164. Initializes the state identifier field.
  165. */
  166. static void initStateId(tcomp_message_t *message, uint8_t** start_ptr, uint8_t state_len)
  167. {
  168. tcomp_buffer_referenceBuff(message->stateId, *start_ptr, state_len);
  169. *start_ptr += state_len;
  170. }
  171. /*
  172. Initializes a stateful SigComp message.
  173. */
  174. static void initStateful(tcomp_message_t *message, uint8_t** start_ptr, uint8_t* end_ptr)
  175. {
  176. /*
  177. +---+---+---+---+---+---+---+---+
  178. | |
  179. : partial state identifier :
  180. | |
  181. +---+---+---+---+---+---+---+---+
  182. | |
  183. : remaining SigComp message :
  184. | |
  185. +---+---+---+---+---+---+---+---+
  186. */
  187. message->isOK &= (*start_ptr<=end_ptr);
  188. if(message->isOK){
  189. tcomp_buffer_referenceBuff(message->remaining_sigcomp_buffer, *start_ptr,
  190. ((end_ptr-*start_ptr)));
  191. }
  192. }
  193. /*
  194. Initializes a stateless SigComp message.
  195. */
  196. static void initStateless(tcomp_message_t *message, uint8_t** start_ptr, uint8_t* end_ptr, int32_t *nack_code)
  197. {
  198. int has_bytecode = (HEADER_GET_LEN(message) == 0); // No state ==> message contains udvm bytecode
  199. message->isOK &= has_bytecode;
  200. if(!message->isOK) return;
  201. /*
  202. +---+---+---+---+---+---+---+---+
  203. | code_len |
  204. +---+---+---+---+---+---+---+---+
  205. | code_len | destination |
  206. +---+---+---+---+---+---+---+---+
  207. | |
  208. : uploaded UDVM bytecode :
  209. | |
  210. +---+---+---+---+---+---+---+---+
  211. | |
  212. : remaining SigComp message :
  213. | |
  214. +---+---+---+---+---+---+---+---+
  215. */
  216. {
  217. uint32_t code_len1, bytecodes_len;
  218. uint8_t code_len2, destination, *bytecodes_uploaded_udvm, *remaining_SigComp_message;
  219. uint8_t* dummy_ptr = ((uint8_t*)*start_ptr);
  220. /* Code_len --> 12bits [8+4] */
  221. code_len1 = *dummy_ptr; dummy_ptr++; /* skip first code_len 8bits */
  222. code_len2 = (*dummy_ptr) & 0xf0; /* code_len 4 remaining bits */
  223. destination = (*dummy_ptr) & 0x0f; /* 4bits after code_len */
  224. dummy_ptr++; /* skip code_len 4bits + destination 4bits ==> 1-byte */
  225. /* Get bytecodes length (12bits) */
  226. bytecodes_len = ( (code_len1<<4)|(code_len2>>4) );
  227. /* Starting memory address (code destination address). In UDVM. */
  228. message->bytecodes_destination = HEADER_GET_DEST_VALUE(destination);
  229. if((message->bytecodes_destination < 128) || (message->bytecodes_destination > 1024)){
  230. TSK_DEBUG_ERROR("INVALID_CODE_LOCATION");
  231. *nack_code = NACK_INVALID_CODE_LOCATION;
  232. message->isOK = 0;
  233. return;
  234. }
  235. /* Uploaded UDVM pointer */
  236. bytecodes_uploaded_udvm = dummy_ptr; /* SigComp header, feedback_item, code_len and destination have been skipped */
  237. /* Skip uploaded udvm */
  238. dummy_ptr += bytecodes_len;
  239. /* remaining SigComp message */
  240. remaining_SigComp_message = dummy_ptr;
  241. /* check that remaining sigcomp message is valide */
  242. if( !(message->isOK &= (remaining_SigComp_message <= end_ptr )) ){
  243. TSK_DEBUG_ERROR("MESSAGE_TOO_SHORT");
  244. *nack_code = NACK_MESSAGE_TOO_SHORT;
  245. return;
  246. }
  247. //
  248. // Setting buffers
  249. //
  250. tcomp_buffer_referenceBuff(message->uploaded_UDVM_buffer, bytecodes_uploaded_udvm, bytecodes_len);
  251. tcomp_buffer_referenceBuff(message->remaining_sigcomp_buffer, remaining_SigComp_message, ((end_ptr-remaining_SigComp_message)));
  252. }
  253. }
  254. /*
  255. Initializes a NACK message as per RFC 4077.
  256. */
  257. static void initNack(tcomp_message_t *message, uint8_t** start_ptr, uint8_t* end_ptr, int32_t* nack_code)
  258. {
  259. /*
  260. +---+---+---+---+---+---+---+---+
  261. | code_len = 0 |
  262. +---+---+---+---+---+---+---+---+
  263. | code_len = 0 | version = 1 |
  264. +---+---+---+---+---+---+---+---+
  265. | Reason Code |
  266. +---+---+---+---+---+---+---+---+
  267. | OPCODE of failed instruction |
  268. +---+---+---+---+---+---+---+---+
  269. | PC of failed instruction |
  270. | |
  271. +---+---+---+---+---+---+---+---+
  272. | |
  273. : SHA-1 Hash of failed message :
  274. | |
  275. +---+---+---+---+---+---+---+---+
  276. | |
  277. : Error Details :
  278. | |
  279. +---+---+---+---+---+---+---+---+*/
  280. uint8_t* dummy_ptr;
  281. message->isNack = 1;
  282. if( (end_ptr - *start_ptr)<25 ){
  283. *nack_code = NACK_MESSAGE_TOO_SHORT;
  284. TSK_DEBUG_ERROR("MESSAGE_TOO_SHORT");
  285. message->isOK = 0;
  286. return;
  287. }
  288. dummy_ptr = ((uint8_t*)*start_ptr);
  289. dummy_ptr++; /* skip first code_len byte */
  290. if(!(message->isOK = (*dummy_ptr++ == NACK_VERSION))) {
  291. return;
  292. }
  293. if(!message->nack_info){
  294. message->nack_info = tcomp_nackinfo_create();
  295. }
  296. message->nack_info->reasonCode = *dummy_ptr++;
  297. message->nack_info->opcode = *dummy_ptr++;
  298. message->nack_info->pc = TSK_BINARY_GET_2BYTES(dummy_ptr); dummy_ptr+=2;
  299. memcpy(message->nack_info->sha1, dummy_ptr, TSK_SHA1_DIGEST_SIZE); dummy_ptr += TSK_SHA1_DIGEST_SIZE;
  300. if(dummy_ptr < end_ptr){
  301. /* Has error details */
  302. tcomp_buffer_appendBuff(message->nack_info->details, dummy_ptr, (end_ptr-dummy_ptr));
  303. }
  304. }
  305. //========================================================
  306. // SigComp message object definition
  307. //
  308. static tsk_object_t* tcomp_message_ctor(tsk_object_t *self, va_list * app)
  309. {
  310. tcomp_message_t *message = self;
  311. if(message){
  312. }
  313. return self;
  314. }
  315. static tsk_object_t* tcomp_message_dtor(tsk_object_t *self)
  316. {
  317. tcomp_message_t *message = self;
  318. if(message){
  319. TSK_OBJECT_SAFE_FREE(message->stateId);
  320. TSK_OBJECT_SAFE_FREE(message->remaining_sigcomp_buffer);
  321. TSK_OBJECT_SAFE_FREE(message->uploaded_UDVM_buffer);
  322. TSK_OBJECT_SAFE_FREE(message->ret_feedback_buffer);
  323. TSK_OBJECT_SAFE_FREE(message->nack_info);
  324. }
  325. else{
  326. TSK_DEBUG_WARN("NULL SigComp message.");
  327. }
  328. return self;
  329. }
  330. static const tsk_object_def_t tcomp_message_def_s =
  331. {
  332. sizeof(tcomp_message_t),
  333. tcomp_message_ctor,
  334. tcomp_message_dtor,
  335. tsk_null
  336. };
  337. const tsk_object_def_t* tcomp_message_def_t = &tcomp_message_def_s;