Ejemplo n.º 1
0
Archivo: vs_tag.c Proyecto: verse/verse
/**
 * \brief This function destroy structure storing information about tag. This
 * function should be called only in situation, when all clients received
 * TagDestroy command.
 */
int vs_tag_destroy(struct VSTagGroup *tg, struct VSTag *tag)
{
    if(tag->tag_folls.first == NULL) {

        /* Free value */
        if(tag->value != NULL) {
            free(tag->value);
            tag->value = NULL;
        }

        /* Remove tag from tag group */
        v_hash_array_remove_item(&tg->tags, tag);

        free(tag);

        vs_taggroup_inc_version(tg);

        return 1;
    } else {
        /* This should never happen */
        v_print_log(VRS_PRINT_WARNING, "%s(): tag (id: %d) with followers can't be destroyed\n",
                    __FUNCTION__, tag->id);
        return 0;
    }

    return 0;
}
Ejemplo n.º 2
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;
	}
}
Ejemplo n.º 3
0
/**
 * \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;
}
Ejemplo n.º 4
0
/**
 * \brief This function removes all tag groups and tags from the VSNode. This
 * function doesn't check, if any client is subscribed to tag groups or not.
 * This function should be called only in situation, when node is destroyed.
 */
int vs_node_taggroups_destroy(struct VSNode *node)
{
	struct VBucket *tg_bucket, *tg_bucket_next, *bucket;
	struct VSTagGroup *tg;
	struct VSTag *tag;

	tg_bucket = node->tag_groups.lb.first;
	while(tg_bucket != NULL) {
		tg_bucket_next = tg_bucket->next;
		tg = (struct VSTagGroup*)tg_bucket->data;

		/* Free all data allocated in tags at the first time */
		bucket = tg->tags.lb.first;
		while(bucket != NULL) {
			tag = (struct VSTag*)bucket->data;

			if(tag->value) {
				free(tag->value);
				tag->value = NULL;
			}

			free(tag);

			bucket = bucket->next;
		}

		/* Destroy all tags in this taggroup */
		v_hash_array_destroy(&tg->tags);

		/* Free list of followers and subscribers */
		v_list_free(&tg->tg_folls);
		v_list_free(&tg->tg_subs);

		/* Destroy this tag group itself */
		v_hash_array_remove_item(&node->tag_groups, tg);
		free(tg);

		tg_bucket = tg_bucket_next;
	}

	return 1;
}
Ejemplo n.º 5
0
/**
 * \brief This function destroys layer stored at verse server
 */
void vs_layer_destroy(struct VSNode *node, struct VSLayer *layer)
{
	struct VSLayer *child_layer;
	struct VSLayerValue *item;
	struct VBucket *vbucket;

	/* Free values in all items */
	vbucket = (struct VBucket*)layer->values.lb.first;
	while(vbucket != NULL) {
		item = (struct VSLayerValue*)vbucket->data;
		free(item->value);
		vbucket = vbucket->next;
	}

	/* Destroy hashed array with items */
	v_hash_array_destroy(&layer->values);

	/* Set references to parent layer in all child layers to NULL */
	child_layer = layer->child_layers.first;
	while(child_layer != NULL) {
		child_layer->parent = NULL;
		child_layer = child_layer->next;
	}
	layer->child_layers.first = NULL;
	layer->child_layers.last = NULL;

	/* If this layer has parent layer, then remove this layer from
	 * parent linked list of child layers */
	if(layer->parent != NULL) {
		v_list_rem_item(&layer->parent->child_layers, layer);
	}

	/* Free list of followers and subscribers */
	v_list_free(&layer->layer_folls);
	v_list_free(&layer->layer_subs);

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

	/* Destroy this layer itself */
	v_hash_array_remove_item(&node->layers, layer);
	free(layer);
}
Ejemplo n.º 6
0
/**
 * \brief This function destroy tag group and all tags included in this tag
 * group. This function should be called only in situation, when all clients
 * received command 'TagGroup Destroy'.
 */
int vs_taggroup_destroy(struct VSNode *node, struct VSTagGroup *tg)
{
	struct VBucket *bucket;
	struct VSTag *tag;

	/* All clients had to received TagGroup_Destroy command */
	assert(tg->tg_folls.first == NULL);

	/* Free all data allocated in tags at the first time */
	bucket = tg->tags.lb.first;
	while(bucket != NULL) {
		tag = (struct VSTag*)bucket->data;

		if(tag->value != NULL) {
			free(tag->value);
			tag->value = NULL;
		}

		free(tag);

		bucket = bucket->next;
	}

	/* Destroy all tags in this taggroup */
	v_hash_array_destroy(&tg->tags);

	/* Free list of followers and subscribers */
	v_list_free(&tg->tg_folls);
	v_list_free(&tg->tg_subs);

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

	/* Destroy this tag group itself */
	v_hash_array_remove_item(&node->tag_groups, tg);
	free(tg);

	vs_node_inc_version(node);

	return 1;
}
Ejemplo n.º 7
0
/*
 * \brief This function pop command from queue with specific priority.
 *
 * Returned command is allocated on the heap and have to be free from calling
 * function. When *count is not NULL, then this function will write number of
 * commands with same ID that could be compressed on this address. When *len
 * is not NULL, then this function will write length of compressed commands
 * at this address. When *len value is not 0, then this value represents maximal
 * size of commands that could be removed from this priority queue.
 *
 * \param[in]	*out_queue	The pointer at list of priority queues
 * \param[in]	prio		The value of priority
 * \param[out]	*count		The pointer at count of commands with same id that
 * could be compressed.
 * \param[out]	*share		The size of address that could be shared
 * \param[out]	*len		The length of compressed commands.
 *
 * \return This function returns pointer at command. This command is allocated
 * at the heap.
 */
struct Generic_Cmd *v_out_queue_pop(struct VOutQueue *out_queue,
		uint8 prio,
		uint16 *count,
		int8 *share,
		uint16 *len)
{
	struct VPrioOutQueue *prio_queue = out_queue->queues[prio];
	struct VOutQueueCommand *queue_cmd;
	struct Generic_Cmd *cmd=NULL;
	int i, can_pop_cmd = 1;

	/* Lock mutex */
	pthread_mutex_lock(&out_queue->lock);

	/*printf("\tcount: %u, share: %u, len: %u\n", *count, *share, *len);*/

	queue_cmd = prio_queue->cmds.first;

	if(queue_cmd != NULL ) {
		cmd = (struct Generic_Cmd *)queue_cmd->vbucket->data;

		assert(cmd != NULL);

		/* Return value of count and length of compressed commands */
		if(queue_cmd->counter != NULL) {
			if(count != NULL) {
				*count = *queue_cmd->counter;
			}
			if(share != NULL) {
				*share = *queue_cmd->share;
			}
			if(len != NULL) {
				/* When *len value is not 0, then this value represents maximal
				 * size of buffer that could be filled with this priority queue. This
				 * function should return value, that is smaller or equal than this
				 * maximum. */
				if(*len != 0) {
					if(*len < *queue_cmd->len) {
						if (count != NULL) {
							*count = v_cmd_count(cmd, *len, *queue_cmd->share);
							/* FIXME: compute length and count correctly, when command is added to the queue */
							*count = ((*count) > (*queue_cmd->counter)) ? *queue_cmd->counter : *count;
							/* Is enough space in buffer to unpack this command? */
							if(*count == 0) {
								can_pop_cmd = 0;
							}
							*len = v_cmds_len(cmd, *count, *queue_cmd->share, 0);
						} else {
							can_pop_cmd = 0;
						}
					} else {
						*len = *queue_cmd->len;
					}
				} else {
					*len = *queue_cmd->len;
				}
			}
		} else {
			if(count != NULL) {
				*count = 0;
			}
			if(share != NULL) {
				*share = 0;
			}
			if(len != NULL) {
				if(v_cmd_size(cmd) > *len) {
					can_pop_cmd = 0;
				}
				*len = 0;
			}
		}

		/* Is it possible to pop command from the queue */
		if(can_pop_cmd == 1) {
			/* Remove command from hashed linked list */
			v_hash_array_remove_item(&out_queue->cmds[cmd->id]->cmds, (void*)cmd);

			/* Remove command from priority queue */
			v_list_rem_item(&prio_queue->cmds, queue_cmd);

			/* Update total count and size of commands */
			out_queue->count--;
			out_queue->size -= out_queue->cmds[cmd->id]->item_size;

			/* Update count and size of commands in subqueue with priority prio */
			out_queue->queues[prio]->count--;
			out_queue->queues[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;
				/* Free values, when it's last command in the queue */
				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 and it is possibly necessary to change maximal
			 * or minimal priority queue*/
			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;
				}

				if(out_queue->max_prio == prio && out_queue->min_prio != prio) {
					for(i=prio; i>=out_queue->min_prio; i--) {
						if(out_queue->queues[i]->count != 0) {
							out_queue->max_prio = i;
							break;
						}
					}
				} else if(out_queue->min_prio == prio && out_queue->max_prio != prio) {
					for(i=prio; i<=out_queue->max_prio; i++) {
						if(out_queue->queues[i]->count != 0) {
							out_queue->min_prio = i;
							break;
						}
					}
				} else if(out_queue->min_prio == prio && out_queue->max_prio == prio) {
					out_queue->min_prio = out_queue->max_prio = VRS_DEFAULT_PRIORITY;
				}
			}

			/* Free queue command */
			free(queue_cmd);
		} else {
			cmd = NULL;
		}
	}

	pthread_mutex_unlock(&out_queue->lock);

	return cmd;
}
Ejemplo n.º 8
0
/**
 * \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;
}
Ejemplo 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;
}
Ejemplo n.º 10
0
/**
 * \brief This function removes packet with id from history of sent packets.
 * It removes all its commands from the command history too.
 *
 * \param[in]	*C		The verse context.
 * \param[in]	id		The ID of packet, the will be removed from the history.
 *
 * \return		This function returns 1, then packet with id was found in the history
 * and it returns 0 otherwise.
 */
int v_packet_history_rem_packet(struct vContext *C, uint32 id)
{
	struct VS_CTX *vs_ctx = CTX_server_ctx(C);
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct VPacket_History *history = &dgram_conn->packet_history;
	struct VPacket *r_packet = CTX_r_packet(C);
	struct VSent_Packet *sent_packet;
	int ret = 0, is_fake_cmd_received = 0;

	sent_packet = v_packet_history_find_packet(history, id);

	if(sent_packet != NULL) {
		struct VSent_Command *sent_cmd;

		v_print_log(VRS_PRINT_DEBUG_MSG, "Removing packet: %d from history\n", sent_packet->id);

		/* Go through the whole list of sent commands and free them from the
		 * hashed linked list */
		sent_cmd = sent_packet->cmds.first;
		while(sent_cmd != NULL) {
			/* Remove own command from hashed linked list if it wasn't already
			 * removed, when command was obsoleted by some newer packet */
			if(sent_cmd->vbucket!=NULL) {
				struct Generic_Cmd *cmd = (struct Generic_Cmd*)sent_cmd->vbucket->data;

				/* Bucket has to include some data */
				assert(sent_cmd->vbucket->data!=NULL);

				/* Decrease total size of commands that were sent and wasn't acknowladged yet*/
				dgram_conn->sent_size -= v_cmd_size(cmd);

				/* Put fake command for create/destroy commands at verse server */
				if(vs_ctx != NULL) {
					struct VSession *vsession = CTX_current_session(C);
					struct Generic_Cmd *fake_cmd = NULL;

					switch(cmd->id) {
					case CMD_NODE_CREATE:
						fake_cmd = v_fake_node_create_ack_create(UINT32(cmd->data[UINT16_SIZE + UINT32_SIZE]));
						break;
					case CMD_NODE_DESTROY:
						fake_cmd = v_fake_node_destroy_ack_create(UINT32(cmd->data[0]));
						break;
					case CMD_TAGGROUP_CREATE:
						fake_cmd = v_fake_taggroup_create_ack_create(UINT32(cmd->data[0]),
								UINT16(cmd->data[UINT32_SIZE]));
						break;
					case CMD_TAGGROUP_DESTROY:
						fake_cmd = v_fake_taggroup_destroy_ack_create(UINT32(cmd->data[0]),
								UINT16(cmd->data[UINT32_SIZE]));
						break;
					case CMD_TAG_CREATE:
						fake_cmd = v_tag_create_ack_create(UINT32(cmd->data[0]),
								UINT16(cmd->data[UINT32_SIZE]),
								UINT16(cmd->data[UINT32_SIZE + UINT16_SIZE]));
						break;
					case CMD_TAG_DESTROY:
						fake_cmd = v_tag_destroy_ack_create(UINT32(cmd->data[0]),
								UINT16(cmd->data[UINT32_SIZE]),
								UINT16(cmd->data[UINT32_SIZE + UINT16_SIZE]));
						break;
					case CMD_LAYER_CREATE:
						fake_cmd = v_fake_layer_create_ack_create(UINT32(cmd->data[0]),
								UINT16(cmd->data[UINT32_SIZE + UINT16_SIZE]));
						break;
					case CMD_LAYER_DESTROY:
						fake_cmd = v_fake_layer_destroy_ack_create(UINT32(cmd->data[0]),
								UINT16(cmd->data[UINT32_SIZE]));
						break;
					default:
						break;
					}

					if(fake_cmd != NULL) {
						is_fake_cmd_received = 1;
						/* Push command to the queue of incomming commands */
						v_in_queue_push(vsession->in_queue, fake_cmd);
						/* Print content of fake command */
						v_fake_cmd_print(VRS_PRINT_DEBUG_MSG, fake_cmd);
					}
				}

				/* Remove command from the history of sent commands */
				ret = v_hash_array_remove_item(&history->cmd_hist[sent_cmd->id]->cmds, sent_cmd->vbucket->data);

				if(ret == 1) {
					/* Destroy command */
					v_cmd_destroy(&cmd);
				} else {
					v_print_log(VRS_PRINT_ERROR, "Unable to remove command id: %d\n", sent_cmd->id);
					ret = 0;
				}
			}
			sent_cmd = sent_cmd->next;
		}

		/* Free linked list of sent commands */
		v_list_free(&sent_packet->cmds);

		/* Remove packet itself from the linked list of sent packet */
		v_list_rem_item(&history->packets, sent_packet);
		free(sent_packet);

		ret = 1;
	} else {
		/* When acknowledged payload packet is not found in history, then it
		 * is OK, because it is probably keep alive packet without any node
		 * commands */
		v_print_log(VRS_PRINT_DEBUG_MSG, "Packet with id: %d, not found in history\n", id);
	}

	/* When pure ack packet caused adding some fake commands to the queue, then
	 * poke server data thread */
	if( (vs_ctx != NULL) && (is_fake_cmd_received == 1) && (r_packet->data == NULL)) {
		sem_post(vs_ctx->data.sem);
	}

	return ret;
}
Ejemplo n.º 11
0
/**
 * \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;
}