doubango/tinySIGCOMP/src/tcomp_compressordisp.c
c732d49e
 #if HAVE_CRT
 #define _CRTDBG_MAP_ALLOC 
 #include <stdlib.h> 
 #include <crtdbg.h>
 #endif //HAVE_CRT
 /*
74ca6d11
 * Copyright (C) 2020, University of the Basque Country (UPV/EHU)
c732d49e
 * Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
 *
 * The original file was part of Open Source Doubango Framework
 * Copyright (C) 2010-2011 Mamadou Diop.
 * Copyright (C) 2012 Doubango Telecom <http://doubango.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_compressordisp.h
  * @brief  Entity that receives application messages, invokes a compressor,and forwards the resulting SigComp compressed messages to a remote
  * endpoint.
  *
  * @author Mamadou Diop <diopmamadou(at)yahoo.fr>
  *
 
  */
 #include "tcomp_compressordisp.h"
 #include "tcomp_compressor_dummy.h"
 #include "tcomp_compressor_deflate.h"
 
 #include "tsk_memory.h"
 #include "tsk_debug.h"
 
 #include <string.h>
 
 /**Checks whether NACK (RFC 4077) handling is supported
 */
 #define TCOMP_NACK_SUPPORTED (dispatcher->stateHandler->sigcomp_parameters->SigComp_version >= 0x02)
 
 
 /**Creates new compressor dispatcher.
 */
 tcomp_compressordisp_t* tcomp_compressordisp_create(const tcomp_statehandler_t* statehandler)
 {
 	return tsk_object_new(tcomp_compressordisp_def_t, statehandler);
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 /// Compress a message.
 ///
 /// @param [in,out]	dispatcher	The compressor dispatcher. 
 /// @param	compartmentId		The compartment to use to compress the message. 
 /// @param [in,out]	input_ptr	The message to compress. 
 /// @param	input_size			The size of the input buffer. 
 /// @param [in,out]	output_ptr	The output buffer to copy the compressed data. 
 /// @param [in,out]	output_size	The size of the output buffer. 
 /// @param	stream				Indicates whether it's a stream buffer or not. 
 ///
 /// @return	@a tsk_true if succeed and @a tsk_false otherwize. 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 tsk_bool_t tcomp_compressordisp_compress(tcomp_compressordisp_t *dispatcher, uint64_t compartmentId, const void *input_ptr, tsk_size_t input_size, void *output_ptr, tsk_size_t *output_size, tsk_bool_t stream)
 {
 	tsk_bool_t ret = tsk_true;
 	int i = 0;
 
 	/* For each compartment id create/retrieve one compressor instance */
 	tcomp_compartment_t *lpCompartment = tcomp_statehandler_getCompartment(dispatcher->stateHandler, compartmentId);
 	
 	if(!lpCompartment){
 		TSK_DEBUG_ERROR("You must provide a valid compartment to perform compression.");
 		return tsk_false;
 	}
 
 	
 	/*
 	*	Performs compression.
 	*/
 	tsk_safeobj_lock(dispatcher);
 	
 	for( i = 0; (i < TCOMP_MAX_COMPRESSORS && dispatcher->compressors[i]); i++ ){
 		if((ret = dispatcher->compressors[i](lpCompartment, input_ptr, input_size, output_ptr, output_size, stream))) {
 			break;
 		}
 	}
 
 	tsk_safeobj_unlock(dispatcher);
 
 
 	/*
 	*	STREAM case. FIXME:Because I'm a lazy man I only support 0xFF00 case
 	*/
 	if(stream){
 		uint8_t* escapedBuffer;
 		tsk_size_t i, j;
 		tsk_size_t escapedBufferSize = (*output_size + 2); /* 2 = strlen(0xffff) */
 
 		for(i = 0; i < *output_size ; i++) {
 			escapedBufferSize += ((uint8_t*)output_ptr)[i] == 0xff ? 1 : 0;
 		}
 		#if HAVE_CRT //Debug memory
 		escapedBuffer = (uint8_t*)calloc(escapedBufferSize, sizeof(uint8_t));
 		
 	#else
 		escapedBuffer = (uint8_t*)tsk_calloc(escapedBufferSize, sizeof(uint8_t));
 		
 	#endif //HAVE_CRT
 
 		for(i = 0, j = 0; i < *output_size; i++, j++){
 			escapedBuffer[j] = ((uint8_t*)output_ptr)[i];
 			if(escapedBuffer[j] == 0xff) {
 				escapedBuffer[++j] = 0x00;
 			}
 		}
 		
 		/* End stream */
 		escapedBuffer[escapedBufferSize-1] = escapedBuffer[escapedBufferSize-2] = 0xff;
 		memcpy(output_ptr, escapedBuffer, escapedBufferSize);
 		
 		*output_size = escapedBufferSize; /* Update size */
 		TSK_FREE(escapedBuffer); /* free */
 	}
 
 	/*
 	* NACK
 	*/
 	if(ret && TCOMP_NACK_SUPPORTED){
 		/* store nack for later retrieval in case of errors */
 		uint8_t nackId[TSK_SHA1_DIGEST_SIZE];
 		tsk_sha1context_t sha;
 
 		tsk_sha1reset(&sha);
 		tsk_sha1input(&sha, (const uint8_t*)output_ptr, *output_size);
 		tsk_sha1result(&sha, (uint8_t*)nackId);
 		tcomp_compartment_addNack(lpCompartment, nackId);
 	}
 
 	return ret;
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 /// Adds new compressor the list of the compressors. 
 ///
 ///
 /// @param [in,out]	dispatcher	The compressor dispatcher. 
 /// @param	compressor			A function pointer to the new compressor. 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 int tcomp_compressordisp_addCompressor(tcomp_compressordisp_t *dispatcher, tcomp_compressor_compress_f compressor)
 {
 	tsk_size_t i;
 
 	if(!dispatcher){
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return -1;
 	}
 
 	for(i = 0; i < TCOMP_MAX_COMPRESSORS; i++){
 		if(!dispatcher->compressors[i]){
 			dispatcher->compressors[i] = compressor;
 			return 0;
 		}
 	}
 	return -2;
 }
 
 /** Removes a compressor
 */
 int tcomp_compressordisp_removeCompressor(tcomp_compressordisp_t *dispatcher, tcomp_compressor_compress_f compressor)
 {
 	tsk_size_t i;
 
 	if(!dispatcher){
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return -1;
 	}
 
 	for(i = 0; i < TCOMP_MAX_COMPRESSORS; i++){
 		if(dispatcher->compressors[i] == compressor){
 			dispatcher->compressors[i] = tsk_null;
 			return 0;
 		}
 	}
 	return -2;
 }
 
 
 
 
 
 
 
 
 //========================================================
 //	SigComp compressor dispatcher object definition
 //
 static tsk_object_t* tcomp_compressordisp_ctor(tsk_object_t * self, va_list * app)
 {
 	tcomp_compressordisp_t *compressordisp = self;
 	if(compressordisp){
 		int i = 0;
 		compressordisp->stateHandler = va_arg(*app, const tcomp_statehandler_t*);
 
 		compressordisp->compressors[0] = tcomp_compressor_deflate_compress;	/* If you don't want deflate compressor then remove this line. */
 		compressordisp->compressors[1] = tcomp_compressor_dummy_compress;	/* RFC 4896 [11. Uncompressed Bytecode]. */
 
 		/* Initialize safeobject */
 		tsk_safeobj_init(compressordisp);
 	}
 	else{
 		TSK_DEBUG_ERROR("Failed to create new compressor dispatcher.");
 	}
 
 	return self;
 }
 
 static tsk_object_t* tcomp_compressordisp_dtor(tsk_object_t *self)
 {
 	tcomp_compressordisp_t *compressordisp = self;
 	if(compressordisp){
 		/* Deinitialize safeobject */
 		tsk_safeobj_deinit(compressordisp);
 
 		memset(compressordisp->compressors, 0 , sizeof(compressordisp->compressors));
 		compressordisp->stateHandler = tsk_null; // not owner
 	}
 	else{
 		TSK_DEBUG_ERROR("Null dispatcher.");
 	}
 	
 	return self;
 }
 
 static const tsk_object_def_t tcomp_compressordisp_def_s = 
 {
 	sizeof(tcomp_compressordisp_t),
 	tcomp_compressordisp_ctor,
 	tcomp_compressordisp_dtor,
 	tsk_null
 };
 const tsk_object_def_t *tcomp_compressordisp_def_t = &tcomp_compressordisp_def_s;