/** * \brief This function add command to the head of the queue */ int v_out_queue_push_head(struct VOutQueue *out_queue, uint8 prio, struct Generic_Cmd *cmd) { struct VBucket *vbucket; int ret = 0; /* Lock mutex */ pthread_mutex_lock(&out_queue->lock); /* 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); /* Add command from history of sent command to the outgoing queue * only in situation, when there isn't already newer command in the * queue */ if(vbucket==NULL) { v_print_log_simple(VRS_PRINT_DEBUG_MSG, "\tRe-sending command: %d\n", cmd->id); v_cmd_print(VRS_PRINT_DEBUG_MSG, (struct Generic_Cmd*)cmd); ret = _v_out_queue_push(out_queue, OUT_QUEUE_ADD_HEAD, prio, cmd); } } else { v_print_log_simple(VRS_PRINT_DEBUG_MSG, "\tRe-sending command: %d\n", cmd->id); v_cmd_print(VRS_PRINT_DEBUG_MSG, (struct Generic_Cmd*)cmd); ret = _v_out_queue_push(out_queue, OUT_QUEUE_ADD_HEAD, prio, cmd); } pthread_mutex_unlock(&out_queue->lock); return ret; }
/** * \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 Try to find node using node_id * * \param[in] *vs_ctx The pointer at server context * \param[in] node_id The ID of node * * \return This function return pointer at VSNode, when node is found. * Otherwise, it returns NULL pointer. */ struct VSNode *vs_node_find(struct VS_CTX *vs_ctx, uint32 node_id) { struct VSNode find_node; struct VBucket *bucket; struct VSNode *node = NULL; find_node.id = node_id; bucket = v_hash_array_find_item(&vs_ctx->data.nodes, &find_node); if(bucket != NULL) { node = (struct VSNode *)bucket->data; } return node; }
static VSLayer *vs_layer_find(struct VSNode *node, uint16 layer_id) { struct VSLayer find_layer; struct VBucket *bucket; struct VSLayer *layer = NULL; find_layer.id = layer_id; bucket = v_hash_array_find_item(&node->layers, &find_layer); if(bucket != NULL) { layer = (struct VSLayer*)bucket->data; } return layer; }
/** * \brief This function finds tag group in node using tag group id * * \param[in] *node The pointer at VSNode * \param[in] taggroup_id The id of tag group * * \return This function return pointer at structure with tag group. */ struct VSTagGroup *vs_taggroup_find(struct VSNode *node, uint16 taggroup_id) { struct VSTagGroup find_tg; struct VBucket *bucket; struct VSTagGroup *tg = NULL; find_tg.id = taggroup_id; bucket = v_hash_array_find_item(&node->tag_groups, (void*)&find_tg); if(bucket != NULL) { tg = (struct VSTagGroup*)bucket->data; } return tg; }
/** * \brief This function tries to find tag in tag_group */ static struct VSTag *vs_tag_find(struct VSTagGroup *tg, uint16 tag_id) { struct VSTag find_tag; struct VSTag *tag = NULL; struct VBucket *bucket; find_tag.id = tag_id; bucket = v_hash_array_find_item(&tg->tags, (void*)&find_tag); if(bucket != NULL) { tag = (struct VSTag*)bucket->data; } return tag; }
/** * \brief This function tries to unset value in the layer and all child layers * * This function is called for parent layer and it is called recursively to * unset values in all child layers * * \param[in] *node The pointer at node * \param[in] *layer The pointer at layer * \param[in] item_id The ID of item which should be unset (deleted) * \param[in] send_command If this argument is equal to 1, then unset_value * command is sent to all subscribers (should be equal to1 only for parent layer) * * \return This function returns 1, when it was able to unset value. Otherwise * it returns 0. */ static int vs_layer_unset_value(struct VSNode *node, struct VSLayer *layer, uint32 item_id, uint8 send_command) { struct VSLayer *child_layer; struct VSLayerValue *item = NULL, _item; struct VBucket *vbucket; struct VSEntitySubscriber *layer_subscriber; /* Try to find item value first */ _item.id = item_id; vbucket = v_hash_array_find_item(&layer->values, &_item); if(vbucket != NULL) { item = (struct VSLayerValue*)vbucket->data; /* Send unset command only for parent layer */ if(send_command == 1) { /* Send item value unset to all layer subscribers */ layer_subscriber = layer->layer_subs.first; while(layer_subscriber != NULL) { vs_layer_send_unset_value(layer_subscriber, node, layer, item); layer_subscriber = layer_subscriber->next; } } /* Free value */ free(item->value); /* Remove value from hashed array */ v_hash_array_remove_item(&layer->values, item); /* Free item */ free(item); } else { return 0; } /* Try to unset values in all child values, but don't send unset_value command * about this unsetting, because client will receive layer_unset of parent * layer*/ child_layer = layer->child_layers.first; while(child_layer != NULL) { vs_layer_unset_value(node, child_layer, item_id, 0); child_layer = child_layer->next; } return 1; }
/** * \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 node at verse server, when client sent * node_create command. */ static struct VSNode *vs_node_new(struct VS_CTX *vs_ctx, struct VSession *vsession, const uint16 type) { struct VSNode *node = NULL; struct VSNode find_node, *avatar_node; struct VSUser *owner; struct VBucket *bucket; struct VSNodePermission *perm; struct VSNodeSubscriber *node_subscriber; /* Try to find avatar node to be able to create initial link to * avatar node (initial parent of new created node) */ find_node.id = vsession->avatar_id; bucket = v_hash_array_find_item(&vs_ctx->data.nodes, &find_node); if(bucket != NULL) { avatar_node = (struct VSNode*)bucket->data; } else { v_print_log(VRS_PRINT_DEBUG_MSG, "vsession->avatar_id: %d not found\n", vsession->avatar_id); goto end; } /* Try to find owner of the new node */ if((owner = vs_user_find(vs_ctx, vsession->user_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "vsession->user_id: %d not found\n", vsession->user_id); goto end; } /* Try to create new verse node */ if( (node = vs_node_create(vs_ctx, avatar_node, owner, VRS_RESERVED_NODE_ID, type)) == NULL) { goto end; } /* Set initial state of this node */ node->state = ENTITY_CREATING; /* Find node representing fake user other_users */ if( vs_ctx->other_users != NULL) { /* Set access permissions for other users */ perm = (struct VSNodePermission *)calloc(1, sizeof(struct VSNodePermission)); perm->user = vs_ctx->other_users; /* TODO: implement default session permissions and use them, * when are available */ perm->permissions = vs_ctx->default_perm; v_list_add_tail(&node->permissions, perm); } /* Send node_create to all subscribers of avatar node data */ node_subscriber = avatar_node->node_subs.first; while(node_subscriber) { vs_node_send_create(node_subscriber, node, avatar_node); node_subscriber = node_subscriber->next; } end: return node; }
/** * \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; }