/** * \brief This function create new tag group */ struct VSTagGroup *vs_taggroup_create(struct VSNode *node, uint16 tg_id, uint16 custom_type) { struct VSTagGroup *tg = NULL; struct VBucket *tg_bucket; if ( !(v_hash_array_count_items(&node->tag_groups) < MAX_TAGGROUPS_COUNT) ) { v_print_log(VRS_PRINT_DEBUG_MSG, "Maximal number of tag groups in node: %d reached.\n", node->id); return NULL; } /* Try to create new tag group */ tg = (struct VSTagGroup*)calloc(1, sizeof(VSTagGroup)); if(tg == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "Out of memory.\n"); return NULL; } /* Initialize new tag group */ vs_taggroup_init(tg); if(tg_id == VRS_RESERVED_TAGGROUP_ID) { /* Try to find first free taggroup_id */ tg->id = node->last_tg_id; while( v_hash_array_find_item(&node->tag_groups, tg) != NULL) { /* When not found, then try higher value */ tg->id++; /* Skip IDs with special purpose */ if(tg->id > LAST_TAGGROUP_ID) { tg->id = FIRST_TAGGROUP_ID; } } } else { tg->id = tg_id; } node->last_tg_id = tg->id; /* Try to add TagGroup to the hashed linked list */ tg_bucket = v_hash_array_add_item(&node->tag_groups, tg, sizeof(struct VSTagGroup)); if(tg_bucket == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "Tag group could not be added to node: %d.\n", node->id); free(tg); return NULL; } /* Copy type */ tg->custom_type = custom_type; vs_node_inc_version(node); return tg; }
/** * \brief This function creates VQueueCommand to priority queue */ static struct VOutQueueCommand * _v_out_queue_command_create(struct VOutQueue *out_queue, uint8 flag, uint8 prio, struct Generic_Cmd *cmd) { /* Create new command in queue */ struct VOutQueueCommand *queue_cmd = (struct VOutQueueCommand*)calloc(1, sizeof(struct VOutQueueCommand)); if(queue_cmd != NULL) { /* Set up id and priority of command */ queue_cmd->id = cmd->id; queue_cmd->prio = prio; queue_cmd->counter = NULL; queue_cmd->share = NULL; if(out_queue->cmds[cmd->id]->flag & NOT_SHARE_ADDR) { _v_out_queue_command_add(out_queue->queues[prio], flag, 0, queue_cmd, cmd); } else { _v_out_queue_command_add(out_queue->queues[prio], flag, 1, queue_cmd, cmd); } /* Add new command data */ queue_cmd->vbucket = v_hash_array_add_item(&out_queue->cmds[cmd->id]->cmds, cmd, out_queue->cmds[cmd->id]->item_size); queue_cmd->vbucket->ptr = (void*)queue_cmd; assert(queue_cmd->vbucket->data != NULL); /* When this priority queue was empty, then update summary of real priorities */ if(out_queue->queues[prio]->count == 0) { if(prio>=VRS_DEFAULT_PRIORITY) out_queue->r_prio_sum_high += out_queue->queues[prio]->r_prio; else out_queue->r_prio_sum_low += out_queue->queues[prio]->r_prio; } /* Update count and size of commands */ out_queue->count++; out_queue->size += out_queue->cmds[cmd->id]->item_size; out_queue->queues[prio]->count++; out_queue->queues[prio]->size += out_queue->cmds[cmd->id]->item_size; /* If necessary update maximal or minimal priority */ if(prio > out_queue->max_prio) { out_queue->max_prio = prio; } else if(prio < out_queue->min_prio) { out_queue->min_prio = prio; } } return queue_cmd; }
/** * \brief This function adds command to the head or tail of the queue */ static int _v_out_queue_push(struct VOutQueue *out_queue, uint8 flag, uint8 prio, struct Generic_Cmd *cmd) { struct VOutQueueCommand *queue_cmd; struct VBucket *vbucket; int ret = 1; assert(cmd!=NULL); /* Try to find command with the same address, when duplicities are not * allowed in command queue */ if(out_queue->cmds[cmd->id]->flag & REMOVE_HASH_DUPS) { vbucket = v_hash_array_find_item(&out_queue->cmds[cmd->id]->cmds, (void*)cmd); if(vbucket != NULL) { /* Bucket has to include not NULL pointer */ assert(vbucket->ptr!=NULL); queue_cmd = (struct VOutQueueCommand*)vbucket->ptr; /* Remove old command from the queue if the priority is different * and add command to the end of new priority queue */ if(queue_cmd->prio != prio) { /* Remove old obsolete data */ v_hash_array_remove_item(&out_queue->cmds[cmd->id]->cmds, vbucket->data); /* Remove old command */ v_list_rem_item(&out_queue->queues[queue_cmd->prio]->cmds, queue_cmd); /* Update size and count in old priority queue */ out_queue->queues[queue_cmd->prio]->count--; out_queue->queues[queue_cmd->prio]->size -= out_queue->cmds[cmd->id]->item_size; /* If needed, then update counter of commands with the same id in the queue */ if(queue_cmd->counter != NULL) { *queue_cmd->counter -= 1; if(*queue_cmd->counter == 0) { free(queue_cmd->counter); queue_cmd->counter = NULL; free(queue_cmd->share); queue_cmd->share = NULL; free(queue_cmd->len); queue_cmd->len = NULL; } } /* When this priority queue is empty now, then update summary of real priorities */ if(out_queue->queues[queue_cmd->prio]->count == 0) { if(prio>=VRS_DEFAULT_PRIORITY) out_queue->r_prio_sum_high -= out_queue->queues[queue_cmd->prio]->r_prio; else out_queue->r_prio_sum_low -= out_queue->queues[queue_cmd->prio]->r_prio; } /* Update new priority command */ queue_cmd->id = cmd->id; queue_cmd->prio = prio; if(out_queue->cmds[cmd->id]->flag & NOT_SHARE_ADDR) { _v_out_queue_command_add(out_queue->queues[prio], flag, 0, queue_cmd, cmd); } else { _v_out_queue_command_add(out_queue->queues[prio], flag, 1, queue_cmd, cmd); } /* Add data of the command to the hashed linked list */ queue_cmd->vbucket = v_hash_array_add_item(&out_queue->cmds[cmd->id]->cmds, cmd, out_queue->cmds[cmd->id]->item_size); queue_cmd->vbucket->ptr = (void*)queue_cmd; assert(queue_cmd->vbucket->data != NULL); /* When this priority queue was empty, then update summary of real priorities */ if(out_queue->queues[prio]->count == 0) { if(prio>=VRS_DEFAULT_PRIORITY) out_queue->r_prio_sum_high += out_queue->queues[prio]->r_prio; else out_queue->r_prio_sum_low += out_queue->queues[prio]->r_prio; } /* Update count and size in new priority queue */ out_queue->queues[prio]->count++; out_queue->queues[prio]->size += out_queue->cmds[cmd->id]->item_size; /* If necessary update maximal or minimal priority */ if(prio > out_queue->max_prio) { out_queue->max_prio = prio; } else if(prio < out_queue->min_prio) { out_queue->min_prio = prio; } } else { /* Debug print */ #if 0 v_print_log(VRS_PRINT_DEBUG_MSG, "Replacing obsolete command with new\n"); v_cmd_print(VRS_PRINT_DEBUG_MSG, (struct Generic_Cmd*)vbucket->data); v_cmd_print(VRS_PRINT_DEBUG_MSG, cmd); #endif /* Destroy original command */ v_cmd_destroy((struct Generic_Cmd**)&vbucket->data); /* Replace data of current queue command with new data */ vbucket->data = (void*)cmd; } } else { /* Add new command in queue */ queue_cmd = _v_out_queue_command_create(out_queue, flag, prio, cmd); if(queue_cmd == NULL) { ret = 0; } } } else { /* Add new command in queue */ queue_cmd = _v_out_queue_command_create(out_queue, flag, prio, cmd); if(queue_cmd == NULL) { ret = 0; } } return ret; }
/** * \brief This function creates new VSNode at Verse server */ struct VSNode *vs_node_create(struct VS_CTX *vs_ctx, struct VSNode *parent_node, struct VSUser *owner, uint32 node_id, uint16 custom_type) { struct VSNode *node; struct VSLink *link; struct VBucket *bucket; if(! (v_hash_array_count_items(&vs_ctx->data.nodes) < VRS_MAX_COMMON_NODE_COUNT) ) { v_print_log(VRS_PRINT_DEBUG_MSG, "max number: %d of nodes reached\n", VRS_MAX_COMMON_NODE_COUNT); return NULL; } node = (struct VSNode*)calloc(1, sizeof(struct VSNode)); if(node == NULL) { v_print_log(VRS_PRINT_ERROR, "Out of memory\n"); return NULL; } vs_node_init(node); if(node_id == VRS_RESERVED_NODE_ID) { /* Try to find first free node_id. It is fast and easy, When * VRS_LAST_COMMON_NODE_ID did not reach 0xFFFFFFFF-1 value yet and not used * node_id are not reused.*/ node->id = vs_ctx->data.last_common_node_id + 1; while( v_hash_array_find_item(&vs_ctx->data.nodes, &node) != NULL) { node->id++; /* Node id 0xFFFFFFFF has special purpose and node IDs in range <0, 65535> * have special purposes too (skip them) */ if(node->id > VRS_LAST_COMMON_NODE_ID) node->id = VRS_FIRST_COMMON_NODE_ID; /* TODO: implement faster finding of free node id */ } vs_ctx->data.last_common_node_id = node->id; } else { node->id = node_id; } /* Create link to the parent node */ if(parent_node != NULL) { link = vs_link_create(parent_node, node); if(link == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "link between nodes %d %d could not be created\n", parent_node->id, node->id); free(node); return NULL; } } else { /* This can happen only for root node */ assert(node_id == VRS_ROOT_NODE_ID); node->parent_link = NULL; node->level = 0; } /* Add node to the hashed array of all verse nodes */ bucket = v_hash_array_add_item(&vs_ctx->data.nodes, node, sizeof(struct VSNode)); if(bucket == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "node %d could not be added to the hashed list of nodes\n", node->id); if(node->parent_link != NULL) { v_list_free_item(&parent_node->children_links, node->parent_link); } free(node); return NULL; } node->owner = owner; node->type = custom_type; return node; }
/** * \brief This function add command to the history of sent command * * When this new added command updates some recent command with * the same address, then this command is set as obsolete. Pointer at this * command is set to NULL in previous packet. * * \param[in] *history The structure containing history of sent packets * and commands * \param[in] *sent_packet The current packet * \param[in] *cmd The data of command * * \return This function returns 1, when command was added to history. * When it wasn't able to add command to history, then zero is returned. */ int v_packet_history_add_cmd(struct VPacket_History *history, struct VSent_Packet *sent_packet, struct Generic_Cmd *cmd, uint8 prio) { struct VSent_Command *sent_cmd; struct VBucket *vbucket; void *_cmd = (void*)cmd; uint8 cmd_id = cmd->id; uint16 cmd_size = v_cmd_struct_size(cmd); int ret = 0; /* Are duplications allowed for this type of commands? */ if(history->cmd_hist[cmd_id]->flag & REMOVE_HASH_DUPS) { /* Try to find command with the same address */ vbucket = v_hash_array_find_item(&history->cmd_hist[cmd_id]->cmds, _cmd); if(vbucket != NULL) { struct Generic_Cmd *obsolete_cmd = (struct Generic_Cmd*)vbucket->data; /* Bucket has to include not NULL pointer */ assert(vbucket->ptr!=NULL); assert(vbucket->data!=NULL); /* Debug print */ #if 0 v_print_log(VRS_PRINT_INFO, "Replacing obsolete command\n"); v_cmd_print(VRS_PRINT_INFO, obsolete_cmd); v_cmd_print(VRS_PRINT_INFO, cmd); #endif /* When old data are obsolete, then set pointer at command in old * command to the NULL (obsolete command would not be re-send) */ ((struct VSent_Command*)(vbucket->ptr))->vbucket = NULL; /* Remove data with the same key as cmd_data has from hashed linked * list */ ret = v_hash_array_remove_item(&history->cmd_hist[cmd_id]->cmds, vbucket->data); if(ret == 1) { /* Destroy original command */ v_cmd_destroy(&obsolete_cmd); } else { v_print_log(VRS_PRINT_DEBUG_MSG, "Could not remove obsolete command (id: %d) from history\n", cmd_id); ret = 0; } } } /* Add own command data to the hashed linked list */ vbucket = v_hash_array_add_item(&history->cmd_hist[cmd_id]->cmds, _cmd, cmd_size); if(vbucket != NULL) { /* Create new command */ sent_cmd = (struct VSent_Command*)malloc(sizeof(struct VSent_Command)); /* Check if it was possible to allocate enough memory for sent command */ if(sent_cmd != NULL) { sent_cmd->id = cmd_id; /* Add command to the linked list of sent packet */ v_list_add_tail(&sent_packet->cmds, sent_cmd); /* Set up pointer at command data */ sent_cmd->vbucket = vbucket; /* Set up pointer at owner of this command item to be able to obsolete * this command in future */ vbucket->ptr = (void*)sent_cmd; /* Store information about command priority. Lost commands should * be re-send with same priority*/ sent_cmd->prio = prio; ret = 1; } else { /* When memory wasn't allocated, then free bucket from hashed * linked list */ v_print_log(VRS_PRINT_ERROR, "Unable allocate enough memory for sent command\n"); ret = v_hash_array_remove_item(&history->cmd_hist[cmd_id]->cmds, _cmd); if(ret == 1) { v_cmd_destroy(_cmd); } ret = 0; } } else { v_print_log(VRS_PRINT_ERROR, "Unable to add command (id: %d) to packet history\n", cmd_id); ret = 0; } return ret; }
/** * \brief This function creates new Verse Tag */ struct VSTag *vs_tag_create(struct VSTagGroup *tg, uint16 tag_id, uint8 data_type, uint8 count, uint16 custom_type) { struct VSTag *tag = NULL; struct VBucket *tag_bucket; tag = (struct VSTag*)calloc(1, sizeof(struct VSTag)); if(tag == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "Out of memory.\n"); return NULL; } /* Initialize new tag */ vs_tag_init(tag); if(tag_id == RESERVED_TAG_ID) { /* Try to find first free id for tag */ tag->id = tg->last_tag_id; while( v_hash_array_find_item(&tg->tags, tag) != NULL ) { tag->id++; if(tag->id > LAST_TAG_ID) { tag->id = FIRST_TAG_ID; } } } else { tag->id = tag_id; } tg->last_tag_id = tag->id; /* Try to add new Tag to the hashed linked list of tags */ tag_bucket = v_hash_array_add_item(&tg->tags, (void*)tag, sizeof(struct VSTag)); if(tag_bucket==NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "Tag could not be added to tag group: %d.\n", tg->id); free(tag); return NULL; } tag->data_type = data_type; tag->count = count; tag->custom_type = custom_type; /* Allocate memory for value (not for type string8) */ switch(data_type) { case VRS_VALUE_TYPE_UINT8: tag->value = (void*)calloc(count, sizeof(uint8)); break; case VRS_VALUE_TYPE_UINT16: tag->value = (void*)calloc(count, sizeof(uint16)); break; case VRS_VALUE_TYPE_UINT32: tag->value = (void*)calloc(count, sizeof(uint32)); break; case VRS_VALUE_TYPE_UINT64: tag->value = (void*)calloc(count, sizeof(uint64)); break; case VRS_VALUE_TYPE_REAL16: tag->value = (void*)calloc(count, sizeof(real16)); break; case VRS_VALUE_TYPE_REAL32: tag->value = (void*)calloc(count, sizeof(real32)); break; case VRS_VALUE_TYPE_REAL64: tag->value = (void*)calloc(count, sizeof(real64)); break; case VRS_VALUE_TYPE_STRING8: /* Memory for this type of tag is allocated, when value of * tag is set. */ tag->value = NULL; break; default: break; } vs_taggroup_inc_version(tg); return tag; }
int vs_handle_layer_set_value(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *layer_set_value_cmd, uint8 data_type, uint8 count) { struct VSNode *node; struct VSLayer *layer; struct VSLayerValue *item, _item; struct VBucket *vbucket; struct VSUser *user; struct VSEntitySubscriber *layer_subscriber; uint32 node_id = UINT32(layer_set_value_cmd->data[0]); uint16 layer_id = UINT16(layer_set_value_cmd->data[UINT32_SIZE]); uint32 item_id = UINT32(layer_set_value_cmd->data[UINT32_SIZE + UINT16_SIZE]); /* Try to find node */ if((node = vs_node_find(vs_ctx, node_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n", __FUNCTION__, node_id); return 0; } /* Try to find user */ if((user = vs_user_find(vs_ctx, vsession->user_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() vsession->user_id: %d not found\n", __FUNCTION__, vsession->user_id); return 0; } /* User has to have permission to write to the node */ if(vs_node_can_write(vs_ctx, vsession, node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s(): user: %s can't write to the node: %d\n", __FUNCTION__, user->username, node->id); return 0; } /* Try to find layer */ if( (layer = vs_layer_find(node, layer_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() layer (id: %d) in node (id: %d) not found\n", __FUNCTION__, layer_id, node_id); return 0; } /* Check type of value */ if( data_type != layer->data_type ) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() data type (%d) of layer (id: %d) in node (id: %d) does not match data type of received command (%d)\n", __FUNCTION__, layer->data_type, layer_id, node_id, data_type); return 0; } /* Check count of value */ if( count != layer->num_vec_comp ) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() count of values (%d) of layer (id: %d) in node (id: %d) does not match count of values of received command (%d)\n", __FUNCTION__, layer->num_vec_comp, layer_id, node_id, count); return 0; } /* Set item value */ /* Try to find item value first */ _item.id = item_id; vbucket = v_hash_array_find_item(&layer->values, &_item); if(vbucket == NULL) { /* When this item doesn't exist yet, then allocate memory for this item * and add it to the hashed array */ item = calloc(1, sizeof(struct VSLayerValue)); item->id = item_id; v_hash_array_add_item(&layer->values, item, sizeof(struct VSLayerValue)); /* Allocate memory for values and copy data to this memory */ switch(layer->data_type) { case VRS_VALUE_TYPE_UINT8: item->value = (void*)calloc(layer->num_vec_comp, sizeof(uint8)); memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*UINT8_SIZE); break; case VRS_VALUE_TYPE_UINT16: item->value = (void*)calloc(layer->num_vec_comp, sizeof(uint16)); memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*UINT16_SIZE); break; case VRS_VALUE_TYPE_UINT32: item->value = (void*)calloc(layer->num_vec_comp, sizeof(uint32)); memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*UINT32_SIZE); break; case VRS_VALUE_TYPE_UINT64: item->value = (void*)calloc(layer->num_vec_comp, sizeof(uint64)); memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*UINT64_SIZE); break; case VRS_VALUE_TYPE_REAL16: item->value = (void*)calloc(layer->num_vec_comp, sizeof(real16)); memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*REAL16_SIZE); break; case VRS_VALUE_TYPE_REAL32: item->value = (void*)calloc(layer->num_vec_comp, sizeof(real32)); memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*REAL32_SIZE); break; case VRS_VALUE_TYPE_REAL64: item->value = (void*)calloc(layer->num_vec_comp, sizeof(real64)); memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*REAL64_SIZE); break; default: return 0; } } else { item = (struct VSLayerValue*)vbucket->data; switch(layer->data_type) { case VRS_VALUE_TYPE_UINT8: memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*UINT8_SIZE); break; case VRS_VALUE_TYPE_UINT16: memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*UINT16_SIZE); break; case VRS_VALUE_TYPE_UINT32: memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*UINT32_SIZE); break; case VRS_VALUE_TYPE_UINT64: memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*UINT64_SIZE); break; case VRS_VALUE_TYPE_REAL16: memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*REAL16_SIZE); break; case VRS_VALUE_TYPE_REAL32: memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*REAL32_SIZE); break; case VRS_VALUE_TYPE_REAL64: memcpy(item->value, &layer_set_value_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_SIZE], layer->num_vec_comp*REAL64_SIZE); break; default: return 0; } } /* Send item value set to all layer subscribers */ layer_subscriber = layer->layer_subs.first; while(layer_subscriber != NULL) { vs_layer_send_set_value(layer_subscriber, node, layer, item); layer_subscriber = layer_subscriber->next; } return 1; }
/** * \brief This function is called, when server receives command layer_create * * \param[in] *vs_ctx The pointer at verse server context * \param[in] *vsession The pointer at session of client that sent this command * \param[in] *layer_create_cmd The pointer at received command * * \return This function returns 0, when parameters of received command are * wrong. When all parameters are right, then it returns 1. */ int vs_handle_layer_create(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *layer_create_cmd) { struct VSNode *node; struct VSUser *user; struct VSLayer *parent_layer; struct VSLayer *layer; struct VBucket *vbucket; struct VSNodeSubscriber *node_subscriber; uint32 node_id = UINT32(layer_create_cmd->data[0]); uint16 parent_layer_id = UINT16(layer_create_cmd->data[UINT32_SIZE]); uint16 layer_id = UINT16(layer_create_cmd->data[UINT32_SIZE+UINT16_SIZE]); uint8 data_type = UINT16(layer_create_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT16_SIZE]); uint8 count = UINT16(layer_create_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT16_SIZE+UINT8_SIZE]); uint16 type = UINT16(layer_create_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT16_SIZE+UINT8_SIZE+UINT8_SIZE]); /* Try to find node */ if((node = vs_node_find(vs_ctx, node_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n", __FUNCTION__, node_id); return 0; } /* When parent layer id is not -1, then try to find this parent layer */ if(parent_layer_id == RESERVED_LAYER_ID) { parent_layer = NULL; } else { parent_layer = vs_layer_find(node, parent_layer_id); if(parent_layer == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() parent layer (id: %d) in node (id: %d) not found\n", __FUNCTION__, parent_layer_id, node_id); return 0; } } /* Node has to be created */ if(!(node->state == ENTITY_CREATED || node->state == ENTITY_CREATING)) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) is not in CREATING or CREATED state: %d\n", __FUNCTION__, node->id, node->state); return 0; } /* Try to find user */ if((user = vs_user_find(vs_ctx, vsession->user_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() vsession->user_id: %d not found\n", __FUNCTION__, vsession->user_id); return 0; } /* User has to have permission to write to the node */ if(vs_node_can_write(vs_ctx, vsession, node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s(): user: %s can't write to node: %d\n", __FUNCTION__, user->username, node->id); return 0; } /* Client has to send layer_create command with layer_id equal to * the value 0xFFFF */ if(layer_id != RESERVED_LAYER_ID) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() layer_id: %d is not 0xFFFF\n", __FUNCTION__, layer_id); return 0; } /* Is type of Layer supported? */ if(!(data_type>VRS_VALUE_TYPE_RESERVED && data_type<=VRS_VALUE_TYPE_REAL64)) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() data_type: %d is not supported\n", __FUNCTION__, data_type); return 0; } vbucket = node->layers.lb.first; /* Check, if there isn't tag with the same type */ while(vbucket != NULL) { layer = vbucket->data; if(layer->type == type) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() layer type: %d is already used in layer: %d\n", __FUNCTION__, type, layer->id); return 0; } vbucket = vbucket->next; } if (v_hash_array_count_items(&node->layers) > MAX_LAYERS_COUNT) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() max number of layers in node: %d was reached\n", node->id); return 0; } layer = vs_layer_create(node, parent_layer, data_type, count, type); /* Try to find first free id for layer */ /* TODO: this could be more effective */ layer->id = node->last_layer_id; while( v_hash_array_find_item(&node->layers, layer) != NULL ) { layer->id++; if(layer->id > LAST_LAYER_ID) { layer->id = FIRST_LAYER_ID; } } node->last_layer_id = layer->id; /* Try to add new Tag to the hashed linked list of tags */ vbucket = v_hash_array_add_item(&node->layers, (void*)layer, sizeof(struct VSLayer)); if(vbucket==NULL) { free(layer); return 0; } layer->state = ENTITY_CREATING; /* Send layer_create to all node subscribers */ node_subscriber = node->node_subs.first; while(node_subscriber != NULL) { vs_layer_send_create(node_subscriber, node, layer); node_subscriber = node_subscriber->next; } return 0; }