summaryrefslogtreecommitdiffstats
path: root/tinySIGCOMP/src/tcomp_compartment.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinySIGCOMP/src/tcomp_compartment.c')
-rw-r--r--tinySIGCOMP/src/tcomp_compartment.c552
1 files changed, 552 insertions, 0 deletions
diff --git a/tinySIGCOMP/src/tcomp_compartment.c b/tinySIGCOMP/src/tcomp_compartment.c
new file mode 100644
index 0000000..5d774a2
--- /dev/null
+++ b/tinySIGCOMP/src/tcomp_compartment.c
@@ -0,0 +1,552 @@
+/*
+* 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_compartment.c
+ * @brief SigComp compartment.
+ * An application-specific grouping of messages that relate to a peer endpoint. Depending on the signaling protocol, this grouping may
+ * relate to application concepts such as "session", "dialog", "connection", or "association". The application allocates state
+ * memory on a per-compartment basis, and determines when a compartment should be created or closed.
+ *
+ * @author Mamadou Diop <diopmamadou(at)yahoo.fr>
+ *
+
+ */
+#include "tcomp_compartment.h"
+
+#include "tsk_debug.h"
+
+#include <assert.h>
+
+static void _tcomp_compartment_freeState(tcomp_compartment_t *compartment, tcomp_state_t **lpState);
+
+tcomp_compartment_t* tcomp_compartment_create(uint64_t id, uint32_t sigCompParameters, tsk_bool_t useOnlyACKedStates)
+{
+ tcomp_compartment_t *compartment;
+ if((compartment = tsk_object_new(tcomp_compartment_def_t))){
+
+
+ /*
+ +---+---+---+---+---+---+---+---+
+ | cpb | dms | sms |
+ +---+---+---+---+---+---+---+---+
+ | SigComp_version |
+ +---+---+---+---+---+---+---+---+
+ */
+
+ // I always assume that remote params are equal to local params
+
+ /* Identifier */
+ compartment->identifier = id;
+
+ /* Remote parameters */
+ compartment->remote_parameters = tcomp_params_create();
+ tcomp_params_setParameters(compartment->remote_parameters, sigCompParameters);
+
+ /* Local parameters */
+ compartment->local_parameters = tcomp_params_create();
+ tcomp_params_setParameters(compartment->local_parameters, sigCompParameters);
+
+ /* Total size */
+ compartment->total_memory_size = compartment->total_memory_left = compartment->local_parameters->smsValue;
+
+ /* Empty list. */
+ compartment->nacks = tsk_list_create();
+
+ /* Empty list. */
+ compartment->local_states = tsk_list_create();
+
+ /* Whether to use only ACKed states */
+ compartment->useOnlyACKedStates = useOnlyACKedStates;
+ }
+ else{
+ TSK_DEBUG_ERROR("Null Compartment");
+ }
+
+ return compartment;
+}
+
+int tcomp_compartment_setUseOnlyACKedStates(tcomp_compartment_t* self, tsk_bool_t useOnlyACKedStates)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->useOnlyACKedStates = useOnlyACKedStates;
+ return 0;
+}
+
+/**Sets remote parameters
+*/
+void tcomp_compartment_setRemoteParams(tcomp_compartment_t *compartment, tcomp_params_t *lpParams)
+{
+ if(!compartment){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return;
+ }
+
+ /* CPB||DMS||SMS [1-BYTE] */
+ if(tcomp_params_hasCpbDmsSms(lpParams)){
+ tcomp_params_setCpbCode(compartment->remote_parameters, lpParams->cpbCode);
+ tcomp_params_setDmsCode(compartment->remote_parameters, lpParams->dmsCode);
+ tcomp_params_setSmsCode(compartment->remote_parameters, lpParams->smsCode);
+ }
+
+ /* SigComp version */
+ if(lpParams->SigComp_version){
+ compartment->remote_parameters->SigComp_version = lpParams->SigComp_version;
+ }
+
+ /*
+ * Returned states
+ * FIXME: check states about quota
+ * FIXME: not tic tac
+ * FIXME: what about returned feedback?
+ */
+ if(lpParams->returnedStates && tcomp_buffer_getSize(lpParams->returnedStates)){
+ TSK_OBJECT_SAFE_FREE(compartment->remote_parameters->returnedStates);
+ /* swap */
+ compartment->remote_parameters->returnedStates = lpParams->returnedStates;
+ lpParams->returnedStates = 0;
+ }
+}
+
+/**Sets requested feedback
+*/
+void tcomp_compartment_setReqFeedback(tcomp_compartment_t *compartment, tcomp_buffer_handle_t *feedback)
+{
+ if(!compartment){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return;
+ }
+
+ tsk_safeobj_lock(compartment);
+
+ /* Delete old */
+ TSK_OBJECT_SAFE_FREE(compartment->lpReqFeedback);
+
+ compartment->lpReqFeedback = tcomp_buffer_create(tcomp_buffer_getBuffer(feedback), tcomp_buffer_getSize(feedback));
+
+ tsk_safeobj_unlock(compartment);
+}
+
+/**Sets returned feedback
+*/
+void tcomp_compartment_setRetFeedback(tcomp_compartment_t *compartment, tcomp_buffer_handle_t *feedback)
+{
+ if(!compartment){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return;
+ }
+
+ tsk_safeobj_lock(compartment);
+
+ // Delete old
+ TSK_OBJECT_SAFE_FREE(compartment->lpRetFeedback);
+
+ compartment->lpRetFeedback = tcomp_buffer_create(tcomp_buffer_getBuffer(feedback), tcomp_buffer_getSize(feedback));
+
+ /*
+ * ACK STATE ==> Returned feedback contains the partial state-id.
+ */
+ if(compartment->compressorData/* && !compartment->compressorData_isStream*/){
+ tcomp_buffer_handle_t *stateid = tcomp_buffer_create(tcomp_buffer_getBufferAtPos(feedback, 1), tcomp_buffer_getSize(feedback)-1);
+ compartment->ackGhost(compartment->compressorData, stateid);
+ TSK_OBJECT_SAFE_FREE(stateid);
+ }
+
+ tsk_safeobj_unlock(compartment);
+}
+
+/**Clears are compartment from the history.
+*/
+void tcomp_compartment_clearStates(tcomp_compartment_t *compartment)
+{
+ if(!compartment){
+ TSK_DEBUG_ERROR("NULL sigcomp compartment.");
+ return;
+ }
+
+ tsk_safeobj_lock(compartment);
+
+ tsk_list_clear_items(compartment->local_states);
+ compartment->total_memory_left = compartment->total_memory_size;
+
+ tsk_safeobj_unlock(compartment);
+}
+
+/**Removes a state from the compartment by priority.
+*/
+void tcomp_compartment_freeStateByPriority(tcomp_compartment_t *compartment)
+{
+ tcomp_state_t *lpState;
+ tsk_list_item_t *item;
+
+ if(!compartment){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return;
+ }
+
+ tsk_safeobj_lock(compartment);
+
+ lpState = 0;
+ item = 0;
+
+ /*
+ * The order in which the existing state items are freed is determined by the state_retention_priority, which is set when the
+ * state items are created. The state_retention_priority of 65535 is reserved for locally available states; these states must always be
+ * freed first. Apart from this special case, states with the lowest state_retention_priority are always freed first. In the event of
+ * a tie, then the state item created first in the compartment is also the first to be freed.
+ */
+ tsk_list_foreach(item, compartment->local_states){
+ tcomp_state_t *curr = item->data;
+
+ if(!curr){
+ continue;
+ }
+
+ /* Local state ? */
+ if(curr->retention_priority == 65535){
+ lpState = curr;
+ break;
+ }
+
+ /* Lower priority? */
+ if(!lpState || curr->retention_priority < lpState->retention_priority){
+ lpState = curr;
+ continue;
+ }
+ }
+
+ if(lpState){
+ compartment->total_memory_left += TCOMP_GET_STATE_SIZE(lpState);
+ tsk_list_remove_item_by_data(compartment->local_states, lpState);
+ }
+
+ tsk_safeobj_unlock(compartment);
+}
+
+/**Removes a state from the compartment.
+*/
+static void _tcomp_compartment_freeState(tcomp_compartment_t *compartment, tcomp_state_t **lpState)
+{
+ if(!compartment){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return;
+ }
+
+ tsk_safeobj_lock(compartment);
+
+ compartment->total_memory_left += TCOMP_GET_STATE_SIZE(*lpState);
+ tsk_list_remove_item_by_data(compartment->local_states, *lpState);
+ *lpState = tsk_null;
+
+ tsk_safeobj_unlock(compartment);
+}
+
+/**Remove states
+* Called by UDVM after STATE_FREE instruction
+*/
+void tcomp_compartment_freeStates(tcomp_compartment_t *compartment, tcomp_tempstate_to_free_t **tempStates, uint8_t size)
+{
+ uint8_t i;
+ tcomp_state_t *lpState;
+ tsk_list_item_t *item;
+
+ if(!compartment){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return;
+ }
+
+ if(!tempStates || !size){
+ return;
+ }
+
+ lpState = tsk_null;
+ item = tsk_null;
+
+ for (i = 0; i < size; i++){
+ /* lock */
+ tsk_safeobj_lock(compartment);
+
+ tsk_list_foreach(item, compartment->local_states){
+ tcomp_state_t *curr = item->data;
+
+ /* Compare current state with provided partial state */
+ if(tcomp_buffer_startsWith(curr->identifier, tempStates[i]->identifier)){
+ /*
+ * If more than one state item in the compartment matches the partial state identifier,
+ * then the state free request is ignored.
+ */
+ TSK_DEBUG_INFO("Request to free state with usage_count=%d", curr->usage_count);
+ if(tcomp_state_dec_usage_count(curr) == 0){
+ if(lpState){
+ lpState = tsk_null;
+ break;
+ }
+ else{
+ lpState = curr;
+ }
+ }
+ }
+ }
+
+ /* unlock */
+ tsk_safeobj_unlock(compartment);
+
+ if(lpState){
+ _tcomp_compartment_freeState(compartment, &lpState);
+ }
+ }
+}
+
+/**Adds a state to the compartment.
+*/
+void tcomp_compartment_addState(tcomp_compartment_t *compartment, tcomp_state_t **lpState)
+{
+ tsk_list_item_t *item;
+ int32_t usage_count = 0;
+ const tcomp_buffer_handle_t *identifier;
+ if(!compartment || !lpState || !*lpState){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return;
+ }
+
+ tsk_safeobj_lock(compartment);
+
+ tcomp_state_makeValid(*lpState);
+ identifier = (*lpState)->identifier;
+
+ // check if the state exist
+ tsk_list_foreach(item, compartment->local_states){
+ if(tcomp_buffer_startsWith(((tcomp_state_t*)item->data)->identifier, (*lpState)->identifier)){
+ *lpState = ((tcomp_state_t*)item->data); // override
+ usage_count = tcomp_state_inc_usage_count(*lpState);
+ break;
+ }
+ }
+
+ if(usage_count == 0){ // alread exist?
+ compartment->total_memory_left -= TCOMP_GET_STATE_SIZE(*lpState);
+ usage_count = tcomp_state_inc_usage_count(*lpState);
+ tsk_list_push_back_data(compartment->local_states, ((void**) lpState));
+ }
+
+ TSK_DEBUG_INFO("SigComp - Add new state with usage_count=%d and id=", usage_count);
+ tcomp_buffer_print(identifier);
+
+ *lpState = tsk_null;
+
+ tsk_safeobj_unlock(compartment);
+}
+
+/**Finds a state.
+*/
+uint32_t tcomp_compartment_findState(tcomp_compartment_t *compartment, const tcomp_buffer_handle_t *partial_identifier, tcomp_state_t **lpState)
+{
+ uint32_t count = 0;
+ tsk_list_item_t *item;
+
+ if(!compartment){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return 0;
+ }
+
+ tsk_safeobj_lock(compartment);
+
+ tsk_list_foreach(item, compartment->local_states){
+ tcomp_state_t *curr = item->data;
+
+ if(tcomp_buffer_startsWith(curr->identifier, partial_identifier)){
+ *lpState = curr; // override
+ count++;
+ }
+ }
+
+ tsk_safeobj_unlock(compartment);
+
+ return count;
+}
+
+/**Removes a Ghost state.
+*/
+void tcomp_compartment_freeGhostState(tcomp_compartment_t *compartment)
+{
+ if(!compartment){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return;
+ }
+
+ tsk_safeobj_lock(compartment);
+
+ if(compartment->compressorData){
+ compartment->freeGhostState(compartment->compressorData);
+ }
+ else{
+ TSK_DEBUG_WARN("No compression data to free.");
+ }
+
+ tsk_safeobj_unlock(compartment);
+}
+
+/**Adds a NACK to the compartment.
+*/
+void tcomp_compartment_addNack(tcomp_compartment_t *compartment, const uint8_t nackId[TSK_SHA1_DIGEST_SIZE])
+{
+ tcomp_buffer_handle_t *id;
+
+ if(!compartment){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return;
+ }
+
+#if 0
+ {
+ int i;
+ TSK_DEBUG_INFO("Save NACK with id:");
+ for(i = 0; i < TSK_SHA1_DIGEST_SIZE; ++i){
+ printf("%x ", nackId[i]);
+ }
+ printf("\n");
+ }
+#endif
+
+ tsk_safeobj_lock(compartment);
+
+ if(compartment->nacks_history_count >= NACK_MAX_HISTORY_SIZE){
+ tsk_list_remove_last_item(compartment->nacks);
+ compartment->nacks_history_count--;
+ }
+
+ id = tcomp_buffer_create(nackId, TSK_SHA1_DIGEST_SIZE);
+ tsk_list_push_back_data(compartment->nacks, ((void**) &id));
+ compartment->nacks_history_count++;
+
+ tsk_safeobj_unlock(compartment);
+}
+
+/**Checks if the NACK exist.
+*/
+tsk_bool_t tcomp_compartment_hasNack(tcomp_compartment_t *compartment, const tcomp_buffer_handle_t *nackId)
+{
+ tsk_bool_t ret = tsk_false;
+ tsk_list_item_t *item;
+
+ if(!compartment){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return tsk_false;
+ }
+
+ tsk_safeobj_lock(compartment);
+
+ item = tsk_null;
+
+ tsk_list_foreach(item, compartment->nacks){
+ tcomp_buffer_handle_t *curr = item->data;
+
+ if(tcomp_buffer_equals(curr, nackId)){
+ TSK_DEBUG_INFO("SigComp - Nack found.");
+ ret = tsk_true;
+ break;
+ }
+ }
+
+ tsk_safeobj_unlock(compartment);
+
+ return ret;
+}
+
+
+
+
+
+
+
+
+
+
+//========================================================
+// State object definition
+//
+
+static tsk_object_t* tcomp_compartment_ctor(tsk_object_t* self, va_list * app)
+{
+ tcomp_compartment_t *compartment = self;
+ if(compartment){
+ /* Initialize safeobject */
+ tsk_safeobj_init(compartment);
+ }
+
+ return self;
+}
+
+static tsk_object_t* tcomp_compartment_dtor(tsk_object_t* self)
+{
+ tcomp_compartment_t *compartment = self;
+ if(compartment){
+ /* Deinitialize safeobject */
+ tsk_safeobj_deinit(compartment);
+
+ /* Delete feedbacks */
+ TSK_OBJECT_SAFE_FREE(compartment->lpReqFeedback);
+ TSK_OBJECT_SAFE_FREE(compartment->lpRetFeedback);
+
+ /* Delete Nacks */
+ TSK_OBJECT_SAFE_FREE(compartment->nacks);
+
+ /* Delete Compressor data */
+ TSK_OBJECT_SAFE_FREE(compartment->compressorData);
+ compartment->ackGhost = tsk_null;
+ compartment->freeGhostState = tsk_null;
+
+ /* Delete params */
+ TSK_OBJECT_SAFE_FREE(compartment->local_parameters);
+ TSK_OBJECT_SAFE_FREE(compartment->remote_parameters);
+
+ /* Delete NACKS */
+ TSK_OBJECT_SAFE_FREE(compartment->nacks);
+
+ /* Delete local states */
+ TSK_OBJECT_SAFE_FREE(compartment->local_states);
+ }
+ else{
+ TSK_DEBUG_ERROR("Null Compartment");
+ }
+
+ return self;
+}
+
+static int tcomp_compartment_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2)
+{
+ const tcomp_compartment_t *compartment1 = obj1;
+ const tcomp_compartment_t *compartment2 = obj2;
+ int64_t res = (compartment1->identifier - compartment2->identifier);
+ return res > 0 ? (int)1 : (res < 0 ? (int)-1 : (int)0);
+}
+
+static const tsk_object_def_t tsk_compartment_def_s =
+{
+ sizeof(tcomp_compartment_t),
+ tcomp_compartment_ctor,
+ tcomp_compartment_dtor,
+ tcomp_compartment_cmp
+};
+const tsk_object_def_t *tcomp_compartment_def_t = &tsk_compartment_def_s;
OpenPOWER on IntegriCloud