/** * \brief This function adds TagDestroy command to the queue of the session */ int vs_tag_send_destroy(struct VSNode *node, struct VSTagGroup *tg, struct VSTag *tag) { struct VSEntityFollower *tag_follower; struct Generic_Cmd *tag_destroy_cmd; int ret = 0; tag_follower = tag->tag_folls.first; while(tag_follower != NULL) { /* Client can receive tag_destroy command only in situation, when * this client already received tag_create command */ if(tag_follower->state == ENTITY_CREATED) { 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; ret = 1; } 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); } } tag_follower = tag_follower->next; } tag->state = ENTITY_DELETING; return ret; }
int32_t vrs_send_node_unlock(const uint8_t session_id, const uint8_t prio, uint32_t node_id) { int i, ret; if(vc_ctx == NULL) { v_print_log(VRS_PRINT_ERROR, "Basic callback functions were not set.\n"); return VRS_NO_CB_FUNC; } else { /* Go through all sessions ... */ for(i=0; i<vc_ctx->max_sessions; i++) { /* ... and try to find session with session_id */ if(vc_ctx->vsessions[i]!=NULL && vc_ctx->vsessions[i]->session_id==session_id) { struct Generic_Cmd *node_unlock_cmd; node_unlock_cmd = v_node_unlock_create(node_id, vc_ctx->vsessions[i]->avatar_id); assert(node_unlock_cmd != NULL); ret = v_out_queue_push_tail(vc_ctx->vsessions[i]->out_queue, OUT_QUEUE_LIMITS, prio, node_unlock_cmd); if(ret == 1) return VRS_SUCCESS; else return VRS_FAILURE; } } } return VRS_FAILURE; }
/** * \brief This function sends TagGroupCreate command to the client * * \param[in] *node_subscriber * \param[in] *node * \param[in] *tg * * \return This function return 1, when command was successfully created and * pushed to outgoing queue. When some error occur (already subscribed to * tag group, out of memory, etc.) then 0 is returned. When outgoing queue is * empty, then -1 is returned. */ int vs_taggroup_send_create(struct VSNodeSubscriber *node_subscriber, struct VSNode *node, struct VSTagGroup *tg) { struct VSession *vsession = node_subscriber->session; struct Generic_Cmd *taggroup_create_cmd; struct VSEntityFollower *taggroup_follower; /* Check if this tag group is in created/creating state */ if(!(tg->state == ENTITY_CREATING || tg->state == ENTITY_CREATED)) { v_print_log(VRS_PRINT_DEBUG_MSG, "This tag group: %d in node: %d is in %d state\n", tg->id, node->id, tg->state); return 0; } /* Check if this command, has not been already sent */ taggroup_follower = tg->tg_folls.first; while(taggroup_follower != NULL) { if(taggroup_follower->node_sub->session->session_id == vsession->session_id ) { v_print_log(VRS_PRINT_DEBUG_MSG, "Client already knows about this TagGroup: %d\n", tg->id); return 0; } taggroup_follower = taggroup_follower->next; } /* Create TagGroup create command */ taggroup_create_cmd = v_taggroup_create_create(node->id, tg->id, tg->custom_type); /* Put this command to the outgoing queue */ if(taggroup_create_cmd == NULL) { return 0; } if(v_out_queue_push_tail(vsession->out_queue, 0, node_subscriber->prio, taggroup_create_cmd) == 0) { return -1; } else { /* Add this session to the list of session, that knows about this * taggroup. Server could send them taggroup_destroy in the future. */ taggroup_follower = (struct VSEntityFollower*)calloc(1, sizeof(struct VSEntityFollower)); taggroup_follower->node_sub = node_subscriber; taggroup_follower->state = ENTITY_CREATING; v_list_add_tail(&tg->tg_folls, taggroup_follower); return 1; } return 0; }
/** * \brief This function send Node_Link command */ static int vs_link_change_send(struct VSNodeSubscriber *node_subscriber, struct VSLink *link) { struct Generic_Cmd *node_link_cmd; node_link_cmd = v_node_link_create(link->parent->id, link->child->id); return v_out_queue_push_tail(node_subscriber->session->out_queue, node_subscriber->prio, node_link_cmd); }
/** * \brief This function send unset layer value to the client */ int vs_layer_send_unset_value(struct VSEntitySubscriber *layer_subscriber, struct VSNode *node, struct VSLayer *layer, struct VSLayerValue *value) { struct Generic_Cmd *unset_value_cmd; unset_value_cmd = v_layer_unset_value_create(node->id, layer->id, value->id); return v_out_queue_push_tail(layer_subscriber->node_sub->session->out_queue, layer_subscriber->node_sub->prio, unset_value_cmd); }
/** * \brief This function sends Node_Create command to the subscriber of parent * node. */ int vs_node_send_create(struct VSNodeSubscriber *node_subscriber, struct VSNode *node, struct VSNode *avatar_node) { struct Generic_Cmd *node_create_cmd = NULL; struct VSEntityFollower *node_follower; /* Check if this node is in created/creating state */ if(!(node->state == ENTITY_CREATING || node->state == ENTITY_CREATED)) { v_print_log(VRS_PRINT_DEBUG_MSG, "This node: %d is in %d state\n", node->id, node->state); return 0; } /* Check if this command, has not been already sent */ node_follower = node->node_folls.first; while(node_follower != NULL) { if(node_follower->node_sub->session->session_id == node_subscriber->session->session_id && (node_follower->state == ENTITY_CREATING || node_follower->state == ENTITY_CREATED)) { v_print_log(VRS_PRINT_DEBUG_MSG, "Client already knows about node: %d\n", node->id); return 0; } node_follower = node_follower->next; } if(avatar_node != NULL){ node_create_cmd = v_node_create_create(node->id, avatar_node->id, node->owner->user_id, node->type); } else { node_create_cmd = v_node_create_create(node->id, node->parent_link->parent->id, node->owner->user_id, node->type); } if ( node_create_cmd != NULL && v_out_queue_push_tail(node_subscriber->session->out_queue, node_subscriber->prio, node_create_cmd) == 1) { /* Add this session to the list of session, that knows about this * node. Server could send them node_destroy in the future. */ node_follower = (struct VSEntityFollower*)calloc(1, sizeof(struct VSEntityFollower)); node_follower->node_sub = node_subscriber; node_follower->state = ENTITY_CREATING; v_list_add_tail(&node->node_folls, node_follower); return 1; } return 0; }
/** * \brief This function add TagCreate command to the queue of the session */ int vs_tag_send_create(struct VSEntitySubscriber *tg_subscriber, struct VSNode *node, struct VSTagGroup *tg, struct VSTag *tag) { struct Generic_Cmd *tag_create; struct VSEntityFollower *tag_follower; /* Check if this tag is in created/creating state */ if(!(tag->state == ENTITY_CREATING || tag->state == ENTITY_CREATED)) { v_print_log(VRS_PRINT_DEBUG_MSG, "This tag: %d in node: %d and tg: %d, is in %d state\n", tag->id, node->id, tg->id, tag->state); return 0; } /* Check if this command, has not been already sent */ tag_follower = tag->tag_folls.first; while(tag_follower != NULL) { if(tag_follower->node_sub->session == tg_subscriber->node_sub->session) { return 0; } tag_follower = tag_follower->next; } /* Create new Tag_Create command */ tag_create = v_tag_create_create(node->id, tg->id, tag->id, tag->data_type, tag->count, tag->custom_type); /* Put command to the outgoing queue */ if(tag_create == NULL) { return 0; } if(v_out_queue_push_tail(tg_subscriber->node_sub->session->out_queue, 0, tg_subscriber->node_sub->prio, tag_create) == 0) { return -1; } else { tag_follower = (struct VSEntityFollower*)calloc(1, sizeof(struct VSEntityFollower)); tag_follower->node_sub = tg_subscriber->node_sub; tag_follower->state = ENTITY_CREATING; v_list_add_tail(&tag->tag_folls, tag_follower); return 1; } return 0; }
/** * \brief This function send set layer value to the client */ int vs_layer_send_set_value(struct VSEntitySubscriber *layer_subscriber, struct VSNode *node, struct VSLayer *layer, struct VSLayerValue *value) { struct Generic_Cmd *set_value_cmd; set_value_cmd = v_layer_set_value_create(node->id, layer->id, value->id, layer->data_type, layer->num_vec_comp, value->value); return v_out_queue_push_tail(layer_subscriber->node_sub->session->out_queue, layer_subscriber->node_sub->prio, set_value_cmd); }
/** * \brief This function add any TagSet command to the queue of outgoing commands */ int vs_tag_send_set(struct VSession *vsession, uint8 prio, struct VSNode *node, struct VSTagGroup *tg, struct VSTag *tag) { struct Generic_Cmd *tag_set_cmd = NULL; tag_set_cmd = v_tag_set_create(node->id, tg->id, tag->id, tag->data_type, tag->count, tag->value); if(tag_set_cmd != NULL) { return v_out_queue_push_tail(vsession->out_queue, 0, prio, tag_set_cmd); } return 0; }
/** * \brief This function send Destroy_Node command to the all clients that * know about this node. * * This function only send Node_Destroy command. Own node destruction is done, * when all clients confirmed receiving of Node_Destroy command. */ static int vs_node_send_destroy(struct VSNode *node) { struct VSEntityFollower *node_follower; struct Generic_Cmd *node_destroy_cmd=NULL; int ret = 0; /* Has node any child? */ if(node->children_links.first != NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "node (id: %d) has children\n", node->id); goto end; } /* Send node_destroy to all clients, that knows about this node. These * clients received node_create command. */ node_follower = node->node_folls.first; while(node_follower!=NULL) { /* Node has to be in CREATED state */ if(node_follower->state == ENTITY_CREATED) { /* Create Destroy_Node command */ 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; ret = 1; } 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, "Can't delete node %d, because it isn't in CREATED state\n"); } node_follower = node_follower->next; } node->state = ENTITY_DELETING; end: return ret; }
/** * \brief This function send command layer_destroy to all followers of this * layer (all subscribers to parent node of this layer) * * When this layer has any child layer, then verse server will automatically * and recursively sends layer_destroy to all child layers of this layer. * * \param[in] *node The pointer at verse node * \param[in] *layer The pointer at verse layer */ int vs_layer_send_destroy(struct VSNode *node, struct VSLayer *layer) { struct VSLayer *child_layer; struct Generic_Cmd *layer_destroy_cmd; struct VSEntityFollower *layer_follower; int ret = 0; /* Send layer destroy to all child layers */ child_layer = layer->child_layers.first; while(child_layer != NULL) { child_layer->state = ENTITY_DELETING; vs_layer_send_destroy(node, child_layer); child_layer = child_layer->next; } layer_follower = layer->layer_folls.first; while(layer_follower != NULL) { if(layer_follower->state == ENTITY_CREATED) { /* Create TagGroup_Destroy command */ layer_destroy_cmd = v_layer_destroy_create(node->id, layer->id); /* Put this command to the outgoing queue */ if( layer_destroy_cmd != NULL && (v_out_queue_push_tail(layer_follower->node_sub->session->out_queue, layer_follower->node_sub->prio, layer_destroy_cmd) == 1)) { layer_follower->state = ENTITY_DELETING; ret = 1; } 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 { v_print_log(VRS_PRINT_DEBUG_MSG, "node_id: %d, layer_id: %d, layer is not in CREATED state (current state: %d)\n", node->id, layer->id, layer_follower->state); } layer_follower = layer_follower->next; } return ret; }
int vs_layer_send_create(struct VSNodeSubscriber *node_subscriber, struct VSNode *node, struct VSLayer *layer) { struct VSession *vsession = node_subscriber->session; struct VSEntityFollower *layer_follower; struct Generic_Cmd *layer_create_cmd; /* TODO: this could be more effective */ /* Check if this command, has not been already sent */ layer_follower = layer->layer_folls.first; while(layer_follower != NULL) { if(layer_follower->node_sub->session->session_id == node_subscriber->session->session_id) { v_print_log(VRS_PRINT_DEBUG_MSG, "Client already knows about this Layer: %d\n", layer->id); return 0; } layer_follower = layer_follower->next; } if(layer->parent != NULL) { layer_create_cmd = v_layer_create_create(node->id, layer->parent->id, layer->id, layer->data_type, layer->num_vec_comp, layer->type); } else { layer_create_cmd = v_layer_create_create(node->id, RESERVED_LAYER_ID, layer->id, layer->data_type, layer->num_vec_comp, layer->type); } if(layer_create_cmd != NULL && v_out_queue_push_tail(vsession->out_queue, node_subscriber->prio, layer_create_cmd) == 1) { /* Add this session to the list of session, that knows about this * layer. Server could send them layer_destroy in the future. */ layer_follower = (struct VSEntityFollower*)calloc(1, sizeof(struct VSEntityFollower)); layer_follower->node_sub = node_subscriber; layer_follower->state = ENTITY_CREATING; v_list_add_tail(&layer->layer_folls, layer_follower); return 1; } return 0; }
/** * \brief This function sends TagGroupDestroy command to the client */ int vs_taggroup_send_destroy(struct VSNode *node, struct VSTagGroup *tg) { struct VSEntityFollower *tg_follower; struct Generic_Cmd *tg_destroy_cmd; int ret = 0; tg_follower = tg->tg_folls.first; while(tg_follower != NULL) { /* Send this command only in situation, when FAKE_CMD_TAGGROUP_CREATE_ACK * was received */ if(tg_follower->state == ENTITY_CREATED) { /* Create TagGroup_Destroy command */ tg_destroy_cmd = v_taggroup_destroy_create(node->id, tg->id); /* Put this command to the outgoing queue */ if( tg_destroy_cmd != NULL && (v_out_queue_push_tail(tg_follower->node_sub->session->out_queue, 0, tg_follower->node_sub->prio, tg_destroy_cmd) == 1)) { tg_follower->state = ENTITY_DELETING; ret = 1; } else { v_print_log(VRS_PRINT_DEBUG_MSG, "TagGroup_Destroy (node_id: %d, taggroup_id: %d) wasn't added to the queue\n", node->id, tg->id); } } else { v_print_log(VRS_PRINT_DEBUG_MSG, "node_id: %d, taggroup_id: %d, tag_group is not in CREATED state (current state: %d)\n", node->id, tg->id, tg_follower->state); } tg_follower = tg_follower->next; } tg->state = ENTITY_DELETING; return ret; }
int32_t vrs_send_node_create(const uint8_t session_id, const uint8_t prio, const uint16_t type) { int i, ret; /* This function is more complicated, because avatar ID and user ID are * stored in session */ if(vc_ctx == NULL) { v_print_log(VRS_PRINT_ERROR, "Basic callback functions were not set.\n"); return VRS_NO_CB_FUNC; } else { /* Go through all sessions ... */ for(i=0; i<vc_ctx->max_sessions; i++) { /* ... and try to find session with session_id */ if(vc_ctx->vsessions[i]!=NULL && vc_ctx->vsessions[i]->session_id==session_id) { struct Generic_Cmd *node_create_cmd = v_node_create_create(VRS_RESERVED_NODE_ID, vc_ctx->vsessions[i]->avatar_id, vc_ctx->vsessions[i]->user_id, type); assert(node_create_cmd != NULL); ret = v_out_queue_push_tail(vc_ctx->vsessions[i]->out_queue, OUT_QUEUE_LIMITS, prio, node_create_cmd); if(ret == 1) return VRS_SUCCESS; else return VRS_FAILURE; } } } v_print_log(VRS_PRINT_ERROR, "Session %d does not exist.\n", session_id); return VRS_FAILURE; }
/** * \brief This function is generic function for putting command to outgoing * queue. Note: not all commands uses this function (node_create, node_lock * and node_unlock). */ static int vc_send_command(const uint8 session_id, const uint8 prio, struct Generic_Cmd *cmd) { int i, ret; assert(cmd != NULL); if(vc_ctx == NULL) { if(is_log_level(VRS_PRINT_ERROR)) { v_print_log(VRS_PRINT_ERROR, "Basic callback functions were not set.\n"); } v_cmd_destroy(&cmd); return VRS_NO_CB_FUNC; } else { /* Go through all sessions ... */ for(i=0; i<vc_ctx->max_sessions; i++) { /* ... and try to find session with session_id */ if(vc_ctx->vsessions[i]!=NULL && vc_ctx->vsessions[i]->session_id==session_id) { ret = v_out_queue_push_tail(vc_ctx->vsessions[i]->out_queue, OUT_QUEUE_LIMITS, prio, cmd); if(ret == 1) return VRS_SUCCESS; else return VRS_FAILURE; } } } if(is_log_level(VRS_PRINT_ERROR)) { v_print_log(VRS_PRINT_ERROR, "Session %d does not exist.\n", session_id); } v_cmd_destroy(&cmd); return VRS_FAILURE; }
/** * \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 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; }
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 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; }