int vs_handle_taggroup_create_ack(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *cmd) { struct VSNode *node; struct VSTagGroup *tg; struct VSEntityFollower *tg_foll; struct TagGroup_Create_Ack_Cmd *cmd_tg_create_ack = (struct TagGroup_Create_Ack_Cmd*)cmd; int all_created = 1, ret = 0; /* Try to find node */ if((node = vs_node_find(vs_ctx, cmd_tg_create_ack->node_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n", __FUNCTION__, cmd_tg_create_ack->node_id); return 0; } pthread_mutex_lock(&node->mutex); if( (tg = vs_taggroup_find(node, cmd_tg_create_ack->taggroup_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag_group (id: %d) in node (id: %d) not found\n", __FUNCTION__, cmd_tg_create_ack->taggroup_id, cmd_tg_create_ack->node_id); } else { ret = 1; for(tg_foll = tg->tg_folls.first; tg_foll != NULL; tg_foll = tg_foll->next) { /* Try to find follower of this tag group */ if(tg_foll->node_sub->session->session_id == vsession->session_id) { /* Switch from state CREATING to state CREATED */ if(tg_foll->state == ENTITY_CREATING) { tg_foll->state = ENTITY_CREATED; } /* If the tag group is in the state DELETING, then it is possible * now to sent tag_group_destroy command to the client, because * the client knows about this tag group now */ if(tg->state == ENTITY_DELETING) { struct Generic_Cmd *taggroup_destroy_cmd = v_taggroup_destroy_create(node->id, tg->id); /* Push this command to the outgoing queue */ if ( taggroup_destroy_cmd!= NULL && v_out_queue_push_tail(tg_foll->node_sub->session->out_queue, tg_foll->node_sub->prio, taggroup_destroy_cmd) == 1) { tg_foll->state = ENTITY_DELETING; } else { v_print_log(VRS_PRINT_DEBUG_MSG, "taggroup_destroy (node_id: %d, tg_id: %d) wasn't added to the queue\n", node->id, tg->id); ret = 0; } } } else { if(tg_foll->state != ENTITY_CREATED) { all_created = 0; } } } if(all_created == 1) { tg->state = ENTITY_CREATED; } } pthread_mutex_unlock(&node->mutex); return ret; }
/** * \brief This function tries to handle node_create command */ int vs_handle_taggroup_create(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *taggroup_create_cmd) { struct VSNode *node; struct VSTagGroup *tg; struct VBucket *vbucket; uint32 node_id = UINT32(taggroup_create_cmd->data[0]); uint16 taggroup_id = UINT16(taggroup_create_cmd->data[UINT32_SIZE]); uint16 type = UINT16(taggroup_create_cmd->data[UINT32_SIZE+UINT16_SIZE]); int ret = 0; /* Client has to send taggroup_create command with taggroup_id equal to * the value 0xFFFF */ if(taggroup_id != VRS_RESERVED_TAGGROUP_ID) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() taggroup_id: %d is not 0xFFFF\n", __FUNCTION__, taggroup_id); return 0; } /* 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; } pthread_mutex_lock(&node->mutex); /* Node has to be created */ if( vs_node_is_created(node) != 1 ) { goto end; } vbucket = node->tag_groups.lb.first; /* Check, if there isn't tag group with the same type */ while(vbucket != NULL) { tg = vbucket->data; if(tg->custom_type == type) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() taggroup type: %d is already used in node: %d\n", __FUNCTION__, type, node->id); goto end; } vbucket = vbucket->next; } /* Is user owner of this node or can user write to this node? */ if(vs_node_can_write(vsession, node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s(): user: %s can't write to node: %d\n", __FUNCTION__, ((struct VSUser *)vsession->user)->username, node->id); goto end; } /* Try to create new tag group */ tg = vs_taggroup_create(node, VRS_RESERVED_TAGGROUP_ID, type); if(tg == NULL) { goto end; } else { struct VSNodeSubscriber *node_subscriber; /* Set state for this entity */ tg->state = ENTITY_CREATING; ret = 1; /* Send tag group create command to all subscribers to the node * that can read this node */ for(node_subscriber = node->node_subs.first; node_subscriber != NULL; node_subscriber = node_subscriber->next) { if( vs_node_can_read(node_subscriber->session, node) == 1) { if(vs_taggroup_send_create(node_subscriber, node, tg) != 1) { ret = 0; } } } } end: pthread_mutex_unlock(&node->mutex); return ret; }
/** * \brief This function tries to handle Tag_Destroy command */ int vs_handle_tag_destroy_ack(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *cmd) { struct VSNode *node; struct VSTagGroup *tg; struct VSTag *tag; struct VSEntityFollower *tag_follower; struct Tag_Destroy_Ack_Cmd *tag_destroy_ack = (struct Tag_Destroy_Ack_Cmd*)cmd; uint32 node_id = tag_destroy_ack->node_id; uint16 taggroup_id = tag_destroy_ack->taggroup_id; uint16 tag_id = tag_destroy_ack->tag_id; int ret = 0; /* 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; } pthread_mutex_lock(&node->mutex); /* Try to find TagGroup */ if( (tg = vs_taggroup_find(node, taggroup_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag_group (id: %d) in node (id: %d) not found\n", __FUNCTION__, taggroup_id, node_id); goto end; } /* Try to find Tag */ if ( (tag = vs_tag_find(tg, tag_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag (id: %d) in tag_group (id: %d), node (id: %d) not found\n", __FUNCTION__, tag_id, taggroup_id, node_id); goto end; } /* Try to find tag follower that generated this fake command */ tag_follower = tag->tag_folls.first; while(tag_follower != NULL) { if(tag_follower->node_sub->session->session_id == vsession->session_id) { tag_follower->state = ENTITY_DELETED; v_list_free_item(&tag->tag_folls, tag_follower); break; } tag_follower = tag_follower->next; } /* When tag doesn't have any follower, then it is possible to destroy * this tag and remove it from list of tags from the tag group */ if(tag->tag_folls.first == NULL) { tag->state = ENTITY_DELETED; vs_tag_destroy(tg, tag); } ret = 1; end: pthread_mutex_unlock(&node->mutex); return ret; }
/** * \brief This function tries to handle Tag_Set_Int8 command */ int vs_handle_tag_set(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *tag_set, uint8 data_type, uint8 count) { struct VSNode *node; struct VSTagGroup *tg; struct VSTag *tag; struct VSEntitySubscriber *tg_subscriber; uint32 node_id; uint16 taggroup_id; uint16 tag_id; int ret = 0; node_id = UINT32(tag_set->data[0]); taggroup_id = UINT16(tag_set->data[UINT32_SIZE]); tag_id = UINT16(tag_set->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; } pthread_mutex_lock(&node->mutex); /* Node has to be created */ if(vs_node_is_created(node) != 1) { goto end; } /* Is user owner of this node or can user write to this node? */ if(vs_node_can_write(vsession, node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s(): user: %s can't write to node: %d\n", __FUNCTION__, ((struct VSUser *)vsession->user)->username, node->id); goto end; } /* Try to find TagGroup */ if( (tg = vs_taggroup_find(node, taggroup_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag_group (id: %d) in node (id: %d) not found\n", __FUNCTION__, taggroup_id, node_id); goto end; } /* Try to find Tag */ if ( (tag = vs_tag_find(tg, tag_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag (id: %d) in tag_group (id: %d), node (id: %d) not found\n", __FUNCTION__, tag_id, taggroup_id, node_id); goto end; } /* Data type has to match */ if(data_type != tag->data_type) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() data type (%d) of tag (id: %d) in tg (id: %d) in node (id: %d) does not match data type of received command (%d)\n", __FUNCTION__, tag->data_type, tag_id, taggroup_id, node_id, data_type); goto end; } /* Count of values has to match */ if(count != tag->count) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() count of values (%d) of tag (id: %d) in tg (id: %d) in node (id: %d) does not match count of values of received command (%d)\n", __FUNCTION__, tag->count, tag_id, taggroup_id, node_id, count); goto end; } /* Set value in tag */ switch(tag->data_type) { case VRS_VALUE_TYPE_UINT8: memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], UINT8_SIZE*tag->count); break; case VRS_VALUE_TYPE_UINT16: memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], UINT16_SIZE*tag->count); break; case VRS_VALUE_TYPE_UINT32: memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], UINT32_SIZE*tag->count); break; case VRS_VALUE_TYPE_UINT64: memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], UINT64_SIZE*tag->count); break; case VRS_VALUE_TYPE_REAL16: memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], REAL16_SIZE*tag->count); break; case VRS_VALUE_TYPE_REAL32: memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], REAL32_SIZE*tag->count); break; case VRS_VALUE_TYPE_REAL64: memcpy(tag->value, &tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE], REAL64_SIZE*tag->count); break; case VRS_VALUE_TYPE_STRING8: if(tag->value == NULL) { tag->value = strdup(PTR(tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE])); } else { size_t new_str_len = strlen(PTR(tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE])); size_t old_str_len = strlen((char*)tag->value); /* Rewrite old string */ if(new_str_len == old_str_len) { strcpy((char*)tag->value, PTR(tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE])); } else { tag->value = (char*)realloc(tag->value, new_str_len*sizeof(char)); strcpy((char*)tag->value, PTR(tag_set->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE])); } } break; default: assert(0); break; } ret = 1; /* Set this tag as initialized, because value of this tag was set. */ tag->flag = TAG_INITIALIZED; vs_taggroup_inc_version(tg); /* Send this tag to all client subscribed to the TagGroup */ tg_subscriber = tg->tg_subs.first; while(tg_subscriber != NULL) { if(vs_tag_send_set(tg_subscriber->node_sub->session, tg_subscriber->node_sub->prio, node, tg, tag) != 1) { ret = 0; } tg_subscriber = tg_subscriber->next; } end: pthread_mutex_unlock(&node->mutex); return ret; }
/** * \brief This function tries to handle Tag_Create command. * * This function change state of follower from CREATING to CREATED * and it sends value to this client. */ int vs_handle_tag_create_ack(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *cmd) { struct VSNode *node; struct VSTagGroup *tg; struct VSTag *tag; struct VSEntityFollower *tag_follower; struct Tag_Create_Ack_Cmd *tag_create_ack = (struct Tag_Create_Ack_Cmd*)cmd; uint32 node_id = tag_create_ack->node_id; uint16 taggroup_id = tag_create_ack->taggroup_id; uint16 tag_id = tag_create_ack->tag_id; int all_created = 1, tag_found = 0, ret = 0; /* 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; } pthread_mutex_lock(&node->mutex); /* Try to find TagGroup */ if( (tg = vs_taggroup_find(node, taggroup_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag_group (id: %d) in node (id: %d) not found\n", __FUNCTION__, taggroup_id, node_id); goto end; } /* Try to find Tag */ if ( (tag = vs_tag_find(tg, tag_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag (id: %d) in tag_group (id: %d), node (id: %d) not found\n", __FUNCTION__, tag_id, taggroup_id, node_id); goto end; } /* Try to find tag follower that generated this fake command */ tag_follower = tag->tag_folls.first; while(tag_follower != NULL) { if(tag_follower->node_sub->session->session_id == vsession->session_id) { tag_found = 1; /* When tag contain value, then send this value to the client */ if( (tag->flag & TAG_INITIALIZED) && (tag_follower->state != ENTITY_CREATED)) { ret = vs_tag_send_set(tag_follower->node_sub->session, tag_follower->node_sub->prio, node, tg, tag); } tag_follower->state = ENTITY_CREATED; /* When this tag has been destroyed during sending tag_create * command, then send tag_destroy command now */ if(tag->state == ENTITY_DELETING) { struct Generic_Cmd *tag_destroy_cmd = v_tag_destroy_create(node->id, tg->id, tag->id); if( tag_destroy_cmd != NULL && (v_out_queue_push_tail(tag_follower->node_sub->session->out_queue, 0, tag_follower->node_sub->prio, tag_destroy_cmd) == 1)) { tag_follower->state = ENTITY_DELETING; } else { v_print_log(VRS_PRINT_DEBUG_MSG, "Tag_Destroy (node_id: %d, taggroup_id: %d, tag_id: %d) wasn't added to the queue\n", node->id, tg->id, tag->id); ret = 0; } } } else if(tag_follower->state != ENTITY_CREATED) { all_created = 0; } tag_follower = tag_follower->next; } /* When all clients knows about this tag, then switch tag to state CREATED */ if(all_created == 1) { tag->state = ENTITY_CREATED; } if(tag_found == 0) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag_follower of tag (id: %d) in tag_group (id: %d) in node (id: %d) not found\n", __FUNCTION__, tag_id, tg->id, node->id); } else { ret = 1; } end: pthread_mutex_unlock(&node->mutex); return ret; }
/** * \brief This function tries to handle Tag_Create command */ int vs_handle_tag_create(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *tag_create) { struct VSNode *node; struct VSTagGroup *tg; struct VSTag *tag; struct VBucket *vbucket; struct VSEntitySubscriber *tg_subscriber; uint32 node_id = UINT32(tag_create->data[0]); uint16 taggroup_id = UINT16(tag_create->data[UINT32_SIZE]); uint16 tag_id = UINT16(tag_create->data[UINT32_SIZE + UINT16_SIZE]); uint8 data_type = UINT8(tag_create->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE]); uint8 count = UINT8(tag_create->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE + UINT8_SIZE]); uint16 type = UINT16(tag_create->data[UINT32_SIZE + UINT16_SIZE + UINT16_SIZE + UINT8_SIZE + UINT8_SIZE]); int ret = 0; /* 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; } pthread_mutex_lock(&node->mutex); /* Node has to be created */ if(vs_node_is_created(node) != 1) { goto end; } /* User has to have permission to write to the node */ if(vs_node_can_write(vsession, node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s(): user: %s can't write to node: %d\n", __FUNCTION__, ((struct VSUser *)vsession->user)->username, node->id); goto end; } /* Try to find TagGroup */ if( (tg = vs_taggroup_find(node, taggroup_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag_group (id: %d) in node (id: %d) not found\n", __FUNCTION__, taggroup_id, node_id); goto end; } /* Tag Group has to be created too (it can't be in DELETING or DELETED state ) */ if(!(tg->state == ENTITY_CREATED || tg->state == ENTITY_CREATING)) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag group (id: %d) from node (id: %d) is not in CREATING or CREATED state: %d\n", __FUNCTION__, tg->id, node->id, tg->state); goto end; } /* Client has to send tag_create command with tag_id equal to * the value 0xFFFF */ if(tag_id != RESERVED_TAG_ID) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag_id: %d is not 0xFFFF\n", __FUNCTION__, tag_id); goto end; } /* Is type of Tag supported? */ if(!(data_type>VRS_VALUE_TYPE_RESERVED && data_type<=VRS_VALUE_TYPE_STRING8)) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag_type: %d is not supported\n", __FUNCTION__, data_type); goto end; } vbucket = tg->tags.lb.first; /* Check, if there isn't tag with the same type */ while(vbucket != NULL) { tag = vbucket->data; if(tag->custom_type == type) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag type: %d is already used in taggroup: %d\n", __FUNCTION__, type, tg->id); goto end; } vbucket = vbucket->next; } if (v_hash_array_count_items(&tg->tags) > MAX_TAGS_COUNT) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() max number of tags in node: %d tag_group: %d was reached\n", tg->id); goto end; } /* Try to create new tag */ tag = vs_tag_create(tg, RESERVED_TAG_ID, data_type, count, type); if(tag == NULL) { goto end; } ret = 1; tag->state = ENTITY_CREATING; /* Send TagCreate to all subscribers of tag group */ tg_subscriber = tg->tg_subs.first; while(tg_subscriber != NULL) { if(vs_tag_send_create(tg_subscriber, node, tg, tag) != 1) { ret = 0; } tg_subscriber = tg_subscriber->next; } end: pthread_mutex_unlock(&node->mutex); return ret; }
/** * \brief This function is called, when server receive ack command of packet * that contained node_create command sent to the client * * When this function is called, then we can be sure, that client knows about * the node. This node can be switched to the NODE_CREATED state for the * follower of this node */ int vs_handle_node_create_ack(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *cmd) { VSNode *node; struct VSEntityFollower *node_follower; struct Node_Create_Ack_Cmd *node_create_ack = (struct Node_Create_Ack_Cmd*)cmd; int all_created = 1; /* Try to find node */ if((node = vs_node_find(vs_ctx, node_create_ack->node_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n", __FUNCTION__, node_create_ack->node_id); return 0; } node_follower = node->node_folls.first; while(node_follower != NULL) { if(node_follower->node_sub->session->session_id == vsession->session_id) { if(node_follower->state == ENTITY_CREATING) { node_follower->state = ENTITY_CREATED; /* If the node is in state DELETING, then send to the client command * node_delete. The client knows about this node now and can receive * node_destroy command */ if(node->state == ENTITY_DELETING) { /* Create Destroy_Node command */ struct Generic_Cmd *node_destroy_cmd = v_node_destroy_create(node->id); /* Push this command to the outgoing queue */ if ( node_destroy_cmd != NULL && v_out_queue_push_tail(node_follower->node_sub->session->out_queue, node_follower->node_sub->prio, node_destroy_cmd) == 1) { node_follower->state = ENTITY_DELETING; } else { v_print_log(VRS_PRINT_DEBUG_MSG, "node_destroy (id: %d) wasn't added to the queue\n", node->id); } } } else { v_print_log(VRS_PRINT_DEBUG_MSG, "node %d isn't in CREATING state\n"); } } else { if(node_follower->state != ENTITY_CREATED) { all_created = 0; } } node_follower = node_follower->next; } /* When all followers know about this node, then change state of this node */ if(all_created == 1) { node->state = ENTITY_CREATED; } return 0; }
/** * \brief This function handle changing link between nodes */ int vs_handle_link_change(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *node_link) { struct VSUser *user = (struct VSUser*)vsession->user; struct VSNode *old_parent_node, *parent_node, *child_node; struct VSLink *link; struct VSNodeSubscriber *node_subscriber; struct VSEntityFollower *node_follower; uint32 parent_node_id = UINT32(node_link->data[0]); uint32 child_node_id = UINT32(node_link->data[UINT32_SIZE]); int i; /* Try to find child node */ if((child_node = vs_node_find(vs_ctx, child_node_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d node (id: %d) not found\n", __func__, __LINE__, child_node_id); return 0; } /* Child node has to be created */ if(! (child_node->state == ENTITY_CREATED || child_node->state == ENTITY_CREATING)) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d node id: %d is not in NODE_CREATED state: %d\n", __func__, __LINE__, child_node->id, child_node->state); return 0; } /* Is user owner of child node or can user write to child node? */ if(vs_node_can_write(vsession, child_node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d user: %s can't write to child node: %d (owner: %s)\n", __func__, __LINE__, user->username, child_node->id, child_node->owner->username); return 0; } /* Old link */ link = child_node->parent_link; /* Old parent node */ old_parent_node = link->parent; /* Is user owner of old parent node or can user write to old parent node? */ if(vs_node_can_write(vsession, old_parent_node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d user: %s can't write to old parent node: %d (owner: %s)\n", __func__, __LINE__, user->username, old_parent_node->id, old_parent_node->owner->username); return 0; } /* Try to find new parent node */ if((parent_node = vs_node_find(vs_ctx, parent_node_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d node (id: %d) not found\n", __func__, __LINE__, parent_node_id); return 0; } /* Parent node has to be created */ if(! (parent_node->state == ENTITY_CREATED || parent_node->state == ENTITY_CREATING)) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d node (id: %d) is not in NODE_CREATED state: %d\n", __func__, __LINE__, parent_node->id, parent_node->state); return 0; } /* Test if client doesn't want to recreate existing link */ if( parent_node == old_parent_node) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d link between nodes (parent_id: %d) (child_id: %d) already exists\n", __func__, __LINE__, parent_node->id, child_node->id); return 0; } /* Is user owner of parent node or can user write to parent node? */ if(vs_node_can_write(vsession, parent_node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d user: %s can't write to parent node: %d (owner: %s)\n", __func__, __LINE__, user->username, parent_node->id, parent_node->owner->username); return 0; } /* Test, if new link could be created */ if(vs_link_test_nodes(parent_node, child_node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d node: %d can't be child of node: %d\n", __func__, __LINE__, child_node->id, parent_node->id); return 0; } /* Remove link from old parent node */ v_list_rem_item(&old_parent_node->children_links, link); /* Add link to new parent node */ v_list_add_tail(&parent_node->children_links, link); link->parent = parent_node; /* Update child node internal properties according new parent node */ vs_link_update_child(parent_node, child_node); /* Update version in child node, parent node and old parent node */ vs_node_inc_version(parent_node); vs_node_inc_version(child_node); vs_node_inc_version(old_parent_node); /* Subscribers of old and new parent node will receive information about * changing link between nodes. Prevent double sending command Node_Link, * when clients are subscribed to both nodes. */ /* Set temporary value in all sessions */ for(i=0; i<vs_ctx->max_sessions; i++) { vs_ctx->vsessions[i]->tmp = 0; } /* Send Node_Link command to subscribers of old parent node and set * session temporary value */ node_subscriber = old_parent_node->node_subs.first; while(node_subscriber != NULL) { if(vs_node_can_read(node_subscriber->session, old_parent_node) == 1) { node_subscriber->session->tmp = 1; vs_link_change_send(node_subscriber, link); } node_subscriber = node_subscriber->next; } /* When client is subscribed to the new parent node and aware of child * node, then send to the client only node_link */ node_follower = child_node->node_folls.first; while(node_follower != NULL) { if(node_follower->node_sub->session->tmp != 1) { vs_link_change_send(node_follower->node_sub, link); node_follower->node_sub->session->tmp = 1; } node_follower = node_follower->next; } /* Send Node_Create command to subscribers of new parent node, when * subscribers were not subscribed to child node */ node_subscriber = parent_node->node_subs.first; while(node_subscriber != NULL) { if(node_subscriber->session->tmp != 1) { if(vs_node_can_read(node_subscriber->session, parent_node) == 1) { vs_node_send_create(node_subscriber, child_node, NULL); } } node_subscriber = node_subscriber->next; } return 1; }
/** * \brief This function handle node_subscribe command */ int vs_handle_taggroup_subscribe(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *taggroup_subscribe) { struct VSNode *node; uint32 node_id = UINT32(taggroup_subscribe->data[0]); uint16 taggroup_id = UINT16(taggroup_subscribe->data[UINT32_SIZE]); int ret = 0; /* 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", __func__, node_id); return 0; } pthread_mutex_lock(&node->mutex); /* Node has to be created */ if( vs_node_is_created(node) != 1 ) { goto end; } /* Is user owner of the node or can user read the node? */ if(vs_node_can_read(vsession, node) == 1) { struct VSNodeSubscriber *node_subscriber; struct VSTagGroup *tg; struct VSTag *tag; struct VSEntitySubscriber *tg_subscriber; struct VBucket *bucket; /* Try to find node subscriber */ node_subscriber = node->node_subs.first; while(node_subscriber != NULL) { if(node_subscriber->session == vsession) { break; } node_subscriber = node_subscriber->next; } /* Client has to be subscribed to the node first */ if(node_subscriber == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s(): client has to be subscribed to the node: %d before subscribing to the tag_group: %d\n", __func__, node_id, taggroup_id); goto end; } /* Try to find TagGroup */ if( (tg = vs_taggroup_find(node, taggroup_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() tag_group (id: %d) in node (id: %d) not found\n", __func__, taggroup_id, node_id); goto end; } /* Is Client already subscribed to this tag group? */ tg_subscriber = tg->tg_subs.first; while(tg_subscriber != NULL) { if(tg_subscriber->node_sub->session->session_id == vsession->session_id) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() client already subscribed to the tag_group (id: %d) in node (id: %d)\n", __func__, taggroup_id, node_id); goto end; } tg_subscriber = tg_subscriber->next; } ret = 1; /* Add new subscriber to the list of tag group subscribers */ tg_subscriber = (struct VSEntitySubscriber*)malloc(sizeof(struct VSEntitySubscriber)); tg_subscriber->node_sub = node_subscriber; v_list_add_tail(&tg->tg_subs, tg_subscriber); /* Try to send tag_create for all tags in this tag group */ bucket = tg->tags.lb.first; while(bucket != NULL) { tag = (struct VSTag*)bucket->data; vs_tag_send_create(tg_subscriber, node, tg, tag); /* When TCP/WebSocket is used and tag is initialized, then it * is possible (necessary) to send value too. */ if( ((vsession->flags & VRS_TP_TCP) || (vsession->flags & VRS_TP_WEBSOCKET)) && (tag->flag & TAG_INITIALIZED)) { vs_tag_send_set(vsession, node_subscriber->prio, node, tg, tag); } bucket = bucket->next; } } else { v_print_log(VRS_PRINT_DEBUG_MSG, "%s(): user: %s doesn't have permissions to subscribe to taggroup: %d in node: %d\n", __func__, ((struct VSUser *)vsession->user)->username, taggroup_id, node->id); } end: pthread_mutex_unlock(&node->mutex); return ret; }
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; }
int vs_handle_layer_subscribe(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *layer_subscribe_cmd) { struct VSNode *node; struct VSUser *user; struct VSLayer *layer; struct VSNodeSubscriber *node_subscriber; struct VSEntitySubscriber *layer_subscriber; struct VBucket *vbucket; struct VSLayerValue *value; uint32 node_id = UINT32(layer_subscribe_cmd->data[0]); uint16 layer_id = UINT16(layer_subscribe_cmd->data[UINT32_SIZE]); /* uint32 version = UINT32(layer_subscribe_cmd->data[UINT32_SIZE+UINT16_SIZE]); uint32 crc32 = UINT32(layer_subscribe_cmd->data[UINT32_SIZE+UINT16_SIZE+UINT32_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; } /* 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 read the node */ if(vs_node_can_read(vs_ctx, vsession, node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s(): user: %s can't read the node: %d\n", __FUNCTION__, user->username, node->id); return 0; } /* Try to find node subscriber */ node_subscriber = node->node_subs.first; while(node_subscriber != NULL) { if(node_subscriber->session == vsession) { break; } node_subscriber = node_subscriber->next; } /* Client has to be subscribed to the node first */ if(node_subscriber == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s(): client has to be subscribed to the node: %d before subscribing to the layer: %d\n", __FUNCTION__, node_id, layer_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; } /* Layer has to be created */ if(! (layer->state == ENTITY_CREATING || layer->state == ENTITY_CREATED)) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() layer (id: %u) in node (id: %d) is not in CREATED state: %d\n", __FUNCTION__, layer->id, node->id, node->state); return 0; } /* Try to find layer subscriber (client can't be subscribed twice) */ layer_subscriber = layer->layer_subs.first; while(layer_subscriber != NULL) { if(layer_subscriber->node_sub->session->session_id == vsession->session_id) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() client already subscribed to the layer (id: %d) in node (id: %d)\n", __FUNCTION__, layer_id, node_id); return 0; } layer_subscriber = layer_subscriber->next; } /* Add new subscriber to the list of layer subscribers */ layer_subscriber = (struct VSEntitySubscriber*)malloc(sizeof(struct VSEntitySubscriber)); layer_subscriber->node_sub = node_subscriber; v_list_add_tail(&layer->layer_subs, layer_subscriber); /* Send value set for all items in this layer * TODO: do not push all values to outgoing queue at once, when there is lot * of values in this layer. Implement this, when queue limits will be * finished. */ vbucket = layer->values.lb.first; while(vbucket != NULL) { value = (struct VSLayerValue*)vbucket->data; vs_layer_send_set_value(layer_subscriber, node, layer, value); vbucket = vbucket->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; }
/** * \brief This function is called, when client acknowledge receiving of * layer_create command */ int vs_handle_layer_create_ack(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *cmd) { struct VSNode *node; struct VSLayer *layer; struct VSEntityFollower *layer_foll; struct Layer_Create_Ack_Cmd *layer_create_cmd_ack = (struct Layer_Create_Ack_Cmd*)cmd; int all_created = 1; /* Try to find node */ if((node = vs_node_find(vs_ctx, layer_create_cmd_ack->node_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n", __FUNCTION__, layer_create_cmd_ack->node_id); return 0; } /* Try to find layer */ if( (layer = vs_layer_find(node, layer_create_cmd_ack->layer_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s() layer (id: %d) in node (id: %d) not found\n", __FUNCTION__, layer_create_cmd_ack->layer_id, layer_create_cmd_ack->node_id); return 0; } for(layer_foll = layer->layer_folls.first; layer_foll != NULL; layer_foll = layer_foll->next) { if(layer_foll->node_sub->session->session_id == vsession->session_id) { /* Switch from state CREATING to state CREATED */ if(layer_foll->state == ENTITY_CREATING) { layer_foll->state = ENTITY_CREATED; } /* If the layer is in the state DELETING, then it is possible * now to sent layer_destroy command to the client, because * the client knows about this layer now */ if(layer->state == ENTITY_DELETING) { struct Generic_Cmd *layer_destroy_cmd = v_layer_destroy_create(node->id, layer->id); /* Push this command to the outgoing queue */ if ( layer_destroy_cmd!= NULL && v_out_queue_push_tail(layer_foll->node_sub->session->out_queue, layer_foll->node_sub->prio, layer_destroy_cmd) == 1) { layer_foll->state = ENTITY_DELETING; } else { v_print_log(VRS_PRINT_DEBUG_MSG, "layer_destroy (node_id: %d, layer_id: %d) wasn't added to the queue\n", node->id, layer->id); } } else { if(layer_foll->state != ENTITY_CREATED) { all_created = 0; } } } } if(all_created == 1) { layer->state = ENTITY_CREATED; } return 0; }