Esempio n. 1
0
/**
 * \brief This function unsubscribe client from the layer
 */
int vs_layer_unsubscribe(struct VSLayer *layer, struct VSession *vsession)
{
	struct VSEntitySubscriber	*layer_subscriber;

	/* Try to find layer subscriber */
	layer_subscriber = layer->layer_subs.first;
	while(layer_subscriber != NULL) {
		if(layer_subscriber->node_sub->session->session_id == vsession->session_id) {
			break;
		}
		layer_subscriber = layer_subscriber->next;
	}

	/* Client has to be subscribed to the layer */
	if(layer_subscriber == NULL) {
		v_print_log(VRS_PRINT_DEBUG_MSG, "%s() client not subscribed to the layer (id: %d)\n",
								__FUNCTION__, layer->id);
		return 0;
	}

	/* Remove client from the list of subscribers */
	v_list_free_item(&layer->layer_subs, layer_subscriber);

	return 1;
}
Esempio n. 2
0
/**
 * \brief This function is called, when server receive ack command of packet
 * that contained node_destroy command that was sent to the client
 *
 * When this function is called, then we can be sure, that client knows, that
 * this node was destroyed. When the last one of follower acknowledge receiving
 * of this command, then this node could be deleted
 */
int vs_handle_node_destroy_ack(struct VS_CTX *vs_ctx,
		struct VSession *vsession,
		struct Generic_Cmd *cmd)
{
	struct VSNode *node;
	struct VSEntityFollower *node_follower, *next_node_follower;
	struct Node_Destroy_Ack_Cmd *node_destroy_ack = (struct Node_Destroy_Ack_Cmd*)cmd;

	/* Try to find node */
	if((node = vs_node_find(vs_ctx, node_destroy_ack->node_id)) == NULL) {
		v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n",
				__FUNCTION__, node_destroy_ack->node_id);
		return 0;
	}

	/* Remove corresponding follower from the list of followers */
	node_follower = node->node_folls.first;
	while(node_follower != NULL) {
		next_node_follower = node_follower->next;
		if(node_follower->node_sub->session->session_id == vsession->session_id) {
			node_follower->state = ENTITY_DELETED;
			v_list_free_item(&node->node_folls, node_follower);
			break;
		}
		node_follower = next_node_follower;
	}

	/* When node doesn't have any follower, then it is possible to destroy this node*/
	if(node->node_folls.first == NULL) {
		node->state = ENTITY_DELETED;
		vs_node_destroy(vs_ctx, node);
	}

	return 1;
}
Esempio n. 3
0
/**
 * \brief This function will try to remove node from the server. The node can't
 * have any child node or subscriber.
 */
static int vs_node_destroy(struct VS_CTX *vs_ctx, struct VSNode *node)
{
	/* Node can't have any followers. The VSNode can be destroyed, when server
	 * receive ack of node_destroy command from all clients */
	if(node->node_folls.first == NULL) {
		/* Node can't have any child node */
		if(node->children_links.first == NULL) {

			/* Remove node permissions */
			if(node->permissions.first != NULL) {
				v_list_free(&node->permissions);
			}

			/* Remove link on this node from parent node */
			if(node->parent_link != NULL) {
				struct VSNode *parent_node = node->parent_link->parent;
				v_list_free_item(&parent_node->children_links, node->parent_link);
			}

			/* Remove all tag groups and tags */
			if(node->tag_groups.lb.first != NULL) {
				vs_node_taggroups_destroy(node);
			}
			v_hash_array_destroy(&node->tag_groups);

			/* Remove all layers */
			if(node->layers.lb.first != NULL) {
				vs_node_layers_destroy(node);
			}
			v_hash_array_destroy(&node->layers);

			v_print_log(VRS_PRINT_DEBUG_MSG, "Node: %d destroyed\n", node->id);

			/* Remove node from the hashed linked list of nodes */
			v_hash_array_remove_item(&vs_ctx->data.nodes, node);
			free(node);

			return 1;
		} else {
			/* This should never happen */
			v_print_log(VRS_PRINT_DEBUG_MSG,
					"%s(): node (id: %d) with child nodes can't be destroyed\n",
					__FUNCTION__, node->id);
			return 0;
		}
	} else {
		/* This should never happen */
		v_print_log(VRS_PRINT_WARNING,
				"%(): node (id: %d) with followers can't be destroyed\n",
				__FUNCTION__, node->id);
		return 0;
	}
}
Esempio n. 4
0
/**
 * \brief This function unsubscribes client from the tag group
 */
int vs_taggroup_unsubscribe(struct VSTagGroup *tg,
		struct VSession *vsession)
{
	struct VSEntitySubscriber	*tg_subscriber;

	/* If client is subscribed to this tag group, then remove this client
	 * from list of subscribers */
	tg_subscriber = tg->tg_subs.first;
	while(tg_subscriber != NULL) {
		if(tg_subscriber->node_sub->session == vsession) {
			VSTag *tag;
			VBucket *bucket;
			struct VSEntityFollower	*tag_follower;

			/* Go through all tags in this tag group */
			bucket = tg->tags.lb.first;
			while(bucket != NULL) {
				tag = (struct VSTag*)bucket->data;
				tag_follower = tag->tag_folls.first;
				/* Remove client from list of tag followers */
				while(tag_follower != NULL) {
					if(tag_follower->node_sub->session == vsession) {
						v_list_free_item(&tag->tag_folls, tag_follower);
						break;
					}
					tag_follower = tag_follower->next;
				}
				bucket = bucket->next;
			}

			/* Remove client from list of tag group subscribers */
			v_list_free_item(&tg->tg_subs, tg_subscriber);

			return 1;
		}
		tg_subscriber = tg_subscriber->next;
	}

	return 0;
}
Esempio n. 5
0
int vs_handle_taggroup_destroy_ack(struct VS_CTX *vs_ctx,
		struct VSession *vsession,
		struct Generic_Cmd *cmd)
{
	struct VSNode *node;
	struct VSTagGroup *tg;
	struct VSEntityFollower *tg_foll, *next_tg_foll;
	struct TagGroup_Destroy_Ack_Cmd *cmd_tg_destroy_ack = (struct TagGroup_Destroy_Ack_Cmd*)cmd;

	/* Try to find node */
	if((node = vs_node_find(vs_ctx, cmd_tg_destroy_ack->node_id)) == NULL) {
		v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n",
				__FUNCTION__, cmd_tg_destroy_ack->node_id);
		return 0;
	}

	if( (tg = vs_taggroup_find(node, cmd_tg_destroy_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_destroy_ack->taggroup_id,
				cmd_tg_destroy_ack->node_id);
		return 0;
	}

	tg_foll = tg->tg_folls.first;
	while(tg_foll != NULL) {
		next_tg_foll = tg_foll->next;
		if(tg_foll->node_sub->session->session_id == vsession->session_id) {
			tg_foll->state = ENTITY_DELETED;
			v_list_free_item(&tg->tg_folls, tg_foll);
		}
		tg_foll = next_tg_foll;
	}

	/* When taggroup doesn't have any follower, then it is possible to destroy
	 * this taggroup */
	if(tg->tg_folls.first == NULL) {
		tg->state = ENTITY_DELETED;
		vs_taggroup_destroy(node, tg);
	}

	return 1;
}
Esempio n. 6
0
int vs_handle_layer_destroy_ack(struct VS_CTX *vs_ctx,
		struct VSession *vsession,
		struct Generic_Cmd *cmd)
{
	struct VSNode *node;
	struct VSLayer *layer;
	struct VSEntityFollower *layer_foll, *next_layer_foll;
	struct Layer_Destroy_Ack_Cmd *layer_destroy_cmd = (struct Layer_Destroy_Ack_Cmd*)cmd;

	/* Try to find node */
	if((node = vs_node_find(vs_ctx, layer_destroy_cmd->node_id)) == NULL) {
		v_print_log(VRS_PRINT_DEBUG_MSG, "%s() node (id: %d) not found\n",
				__FUNCTION__, layer_destroy_cmd->node_id);
		return 0;
	}

	/* Try to find layer */
	if( (layer = vs_layer_find(node, layer_destroy_cmd->layer_id)) == NULL) {
		v_print_log(VRS_PRINT_DEBUG_MSG, "%s() layer (id: %d) in node (id: %d) not found\n",
				__FUNCTION__, layer_destroy_cmd->layer_id, layer_destroy_cmd->node_id);
		return 0;
	}

	/* Mark the layer in this session as DELETED and remove this follower from
	 * the list of layer followers */
	layer_foll = layer->layer_folls.first;
	while(layer_foll != NULL) {
		next_layer_foll = layer_foll->next;
		if(layer_foll->node_sub->session->session_id == vsession->session_id) {
			layer_foll->state = ENTITY_DELETED;
			v_list_free_item(&layer->layer_folls, layer_foll);
		}
		layer_foll = next_layer_foll;
	}

	/* When layer doesn't have any follower, then it is possible to destroy
	 * this layer */
	if(layer->layer_folls.first == NULL) {
		layer->state = ENTITY_DELETED;
		vs_layer_destroy(node, layer);
	}

	return 0;
}
Esempio n. 7
0
/**
 * \brief This function do recursive unsubscribing from node
 */
static int vs_node_unsubscribe(struct VSNode *node,
		struct VSNodeSubscriber *node_subscriber,
		int level)
{
	struct VSNode *child_node;
	struct VSLink *link;
	struct VBucket *tg_bucket, *layer_bucket;
	struct VSTagGroup *tg;
	struct VSLayer *layer;
	struct VSNodeSubscriber *_node_subscriber, *_next_node_subscriber;
	struct VSEntityFollower *node_follower;
	struct VSEntityFollower	*taggroup_follower;
	struct VSEntityFollower	*layer_follower;

	/* Unsubscribe from all child nodes */
	link = node->children_links.first;
	while(link != NULL) {
		child_node = link->child;

		_node_subscriber = child_node->node_subs.first;
		while(_node_subscriber != NULL) {
			_next_node_subscriber = _node_subscriber->next;
			if(_node_subscriber->session->session_id == node_subscriber->session->session_id) {
				/* Unsubscribe from child node */
				vs_node_unsubscribe(child_node, _node_subscriber, level+1);
				break;
			}
			_node_subscriber = _next_node_subscriber;
		}

		link = link->next;
	}

	/* Unsubscribe client from all tag groups */
	tg_bucket = node->tag_groups.lb.first;
	while(tg_bucket != NULL) {
		tg = (struct VSTagGroup*)tg_bucket->data;

		/* Remove client from the list of TagGroup subscribers */
		vs_taggroup_unsubscribe(tg, node_subscriber->session);

		/* Remove client from the list of TagGroup followers */
		taggroup_follower = tg->tg_folls.first;
		while(taggroup_follower != NULL) {
			if(taggroup_follower->node_sub->session->session_id == node_subscriber->session->session_id) {
				v_list_free_item(&tg->tg_folls, taggroup_follower);
				break;
			}
			taggroup_follower = taggroup_follower->next;
		}

		tg_bucket = tg_bucket->next;
	}

	/* Unsubscribe client from all layers */
	layer_bucket = node->layers.lb.first;
	while(layer_bucket != NULL) {
		layer = (struct VSLayer*)layer_bucket->data;

		/* Remove client from the list of Layer subscribers */
		vs_layer_unsubscribe(layer, node_subscriber->session);

		/* Remove client from the list of Layer followers */
		layer_follower = layer->layer_folls.first;
		while(layer_follower != NULL) {
			if(layer_follower->node_sub->session->session_id == node_subscriber->session->session_id) {
				v_list_free_item(&layer->layer_folls, layer_follower);
				break;
			}
			layer_follower = layer_follower->next;
		}
		layer_bucket = layer_bucket->next;
	}

	if(level > 0) {
		/* Remove this session from list of followers too */
		node_follower = node->node_folls.first;
		while(node_follower != NULL) {
			if(node_follower->node_sub->session->session_id == node_subscriber->session->session_id) {
				/* Remove client from list of clients, that knows about this node */
				v_print_log(VRS_PRINT_DEBUG_MSG,
						"Removing session: %d from the list of node: %d followers\n",
						node_subscriber->session->session_id, node->id);
				v_list_free_item(&node->node_folls, node_follower);
				break;
			}
			node_follower = node_follower->next;
		}
	}

	/* Finally remove this session from list of node subscribers */
	v_list_free_item(&node->node_subs, node_subscriber);

	return 1;
}
Esempio n. 8
0
/**
 * \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;
}
Esempio n. 9
0
/**
 * \brief This function is called, when acknowledgment packet was received.
 *
 * This function processes all ACK and NAK commands and it add not obsolete
 * commands from the history of sent packets to the out queue again. This
 * function also removes positively and negatively acknowledged packets from
 * history of sent packets. ANK ID is updated.
 *
 * \param[in] *C	The verse context.
 *
 * \return	This function returns index of last ACK command in sequence of
 * system command, when ACK and NAK commands are the beginning of system
 * commands, otherwise it returns -2. When no ACK or NAK command was found,
 * then -1 is returned;
 */
static int handle_ack_nak_commands(struct vContext *C)
{
	struct VSession *vsession = CTX_current_session(C);
	struct VDgramConn *vconn = CTX_current_dgram_conn(C);
	struct VPacket *r_packet = CTX_r_packet(C);
	struct VSent_Packet *sent_packet;
	struct VSent_Command *sent_cmd, *sent_cmd_prev;
	unsigned long int rtt = ULONG_MAX;
	struct timeval tv;
	uint32 ack_id, nak_id;
	int i, ret=-1;

	gettimeofday(&tv, NULL);

	/* Compute SRTT */
	if(r_packet->sys_cmd[0].cmd.id==CMD_ACK_ID) {
		unsigned long int tmp;
		int i=0;

		/* Try to find the smallest RTT from acknowledged packets */
		for(i=0; r_packet->sys_cmd[i].cmd.id!=CMD_RESERVED_ID; i++) {
			if(r_packet->sys_cmd[i].cmd.id==CMD_ACK_ID) {
				sent_packet = v_packet_history_find_packet(&vconn->packet_history,
					r_packet->sys_cmd[i].ack_cmd.pay_id);
				if(sent_packet!=NULL) {
					tmp = packet_rtt(sent_packet, &tv);
					if(tmp<rtt) rtt=tmp;
				}
			}
		}

		if(rtt<ULONG_MAX) {
			/* Computation of SRTT as described in RFC */
			if(vconn->srtt==0) {
				vconn->srtt = rtt;
			} else {
				vconn->srtt = RTT_ALPHA*vconn->srtt + (1-RTT_ALPHA)*rtt;
			}
			v_print_log(VRS_PRINT_DEBUG_MSG, "RTT: %d [us]\n", rtt);
			v_print_log(VRS_PRINT_DEBUG_MSG, "SRTT: %d [us]\n", vconn->srtt);
		}
	}


	/* Process all ACK and NAK commands. ACK and NAK commands should be first
	 * and there should not be other system commands between ACK and NAK
	 * commands. */
	for(i=0;
			r_packet->sys_cmd[i].cmd.id == CMD_NAK_ID ||
					r_packet->sys_cmd[i].cmd.id == CMD_ACK_ID;
			i++) {

		if(r_packet->sys_cmd[i].cmd.id == CMD_ACK_ID) {
			/* Check if ACK and NAK commands are the first system commands */
			if(ret!=-2 && ret==i-1) {
				ret = i;
			} else {
				ret = -2;
			}
			/* If this is not the last ACK command in the sequence of
			 * ACK/NAK commands, then remove all packets from history of
			 * sent packet, that are in following sub-sequence of ACK
			 * commands */
			if(r_packet->sys_cmd[i+1].cmd.id == CMD_NAK_ID ||
					r_packet->sys_cmd[i+1].cmd.id == CMD_ACK_ID)
			{
				/* Remove all acknowledged payload packets from the history
				 * of sent payload packets */
				for(ack_id = r_packet->sys_cmd[i].ack_cmd.pay_id;
						ack_id < r_packet->sys_cmd[i+1].nak_cmd.pay_id;
						ack_id++)
				{
					v_packet_history_rem_packet(C, ack_id);
				}
			} else {
				/* Remove this acknowledged payload packets from the history
				 * of sent payload packets */
				v_packet_history_rem_packet(C, r_packet->sys_cmd[i].ack_cmd.pay_id);
				/* This is the last ACK command in the sequence of ACK/NAK
				 * commands. Update ANK ID. */
				vconn->ank_id = r_packet->sys_cmd[i].ack_cmd.pay_id;
			}
		} else if(r_packet->sys_cmd[i].cmd.id == CMD_NAK_ID) {
			/* Check if ACK and NAK commands are the first system commands */
			if(ret!=-2 && ret==i-1) {
				ret = i;
			} else {
				ret = -2;
			}
			/* Go through the sub-sequence of NAk commands and try to re-send
			 * not-obsolete data from these packets */
			for(nak_id = r_packet->sys_cmd[i].nak_cmd.pay_id;
					nak_id < r_packet->sys_cmd[i+1].ack_cmd.pay_id;
					nak_id++)
			{
				/* Add not obsolete data of lost packet to the outgoing queue */
				/* Update ANK ID */
				sent_packet = v_packet_history_find_packet(&vconn->packet_history, nak_id);
				if(sent_packet != NULL) {
					v_print_log(VRS_PRINT_DEBUG_MSG, "Try to re-send packet: %d\n", nak_id);
					sent_cmd = sent_packet->cmds.last;

					/* Go through all commands in command list and add not
					 * obsolete commands to the outgoing queue */
					while(sent_cmd != NULL) {
						sent_cmd_prev = sent_cmd->prev;
						if(sent_cmd->vbucket != NULL && sent_cmd->vbucket->data != NULL) {

							/* Try to add command back to the outgoing command queue */
							if(v_out_queue_push_head(vsession->out_queue,
									sent_cmd->prio,
									(struct Generic_Cmd*)sent_cmd->vbucket->data) == 1)
							{
								/* Remove bucket from the history of sent commands too */
								v_hash_array_remove_item(&vconn->packet_history.cmd_hist[sent_cmd->id]->cmds, sent_cmd->vbucket->data);

								/* When command was added back to the queue,
								 * then delete only sent command */
								v_list_free_item(&sent_packet->cmds, sent_cmd);

							}
						}
						sent_cmd = sent_cmd_prev;
					}

					/* When all not obsolete commands are added to outgoing
					 * queue, then this packet could be removed from packet
					 * history*/
					v_packet_history_rem_packet(C, nak_id);
				}
			}
		}
	}

	return ret;
}
Esempio n. 10
0
File: vs_tag.c Progetto: verse/verse
/**
 * \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;
}