Example #1
0
/**
 * \brief This function add command to the head of the queue
 */
int v_out_queue_push_head(struct VOutQueue *out_queue, uint8 prio, struct Generic_Cmd *cmd)
{
	struct VBucket *vbucket;
	int ret = 0;

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

	/* Try to find command with the same address, when duplicities are not
	 * allowed in command queue */
	if(out_queue->cmds[cmd->id]->flag & REMOVE_HASH_DUPS) {
		vbucket = v_hash_array_find_item(&out_queue->cmds[cmd->id]->cmds, (void*)cmd);
		/* Add command from history of sent command to the outgoing queue
		 * only in situation, when there isn't already newer command in the
		 * queue */
		if(vbucket==NULL) {
			v_print_log_simple(VRS_PRINT_DEBUG_MSG, "\tRe-sending command: %d\n", cmd->id);
			v_cmd_print(VRS_PRINT_DEBUG_MSG, (struct Generic_Cmd*)cmd);

			ret = _v_out_queue_push(out_queue, OUT_QUEUE_ADD_HEAD, prio, cmd);
		}
	} else {
		v_print_log_simple(VRS_PRINT_DEBUG_MSG, "\tRe-sending command: %d\n", cmd->id);
		v_cmd_print(VRS_PRINT_DEBUG_MSG, (struct Generic_Cmd*)cmd);

		ret = _v_out_queue_push(out_queue, OUT_QUEUE_ADD_HEAD, prio, cmd);
	}

	pthread_mutex_unlock(&out_queue->lock);

	return ret;
}
Example #2
0
/**
 * \brief		This function prints history of sent packets
 * \param[in]	*history	The history of sent packets.
 */
void v_print_packet_history(struct VPacket_History *history)
{
	struct VSent_Packet *packet;
	struct VBucket *vbucket;
	int cmd_id;

	v_print_log(VRS_PRINT_DEBUG_MSG, "Packet history:\n\t");
	packet = history->packets.first;
	while(packet!=NULL) {
		v_print_log_simple(VRS_PRINT_DEBUG_MSG, "%d, ", packet->id);
		packet = packet->next;
	}
	v_print_log_simple(VRS_PRINT_DEBUG_MSG, "\n");

	v_print_log(VRS_PRINT_DEBUG_MSG, "Command history:\n");
	for(cmd_id=0; cmd_id<=MAX_CMD_ID; cmd_id++) {
		if(history->cmd_hist[cmd_id] != NULL) {
			vbucket = history->cmd_hist[cmd_id]->cmds.lb.first;
			while(vbucket != NULL) {
				v_cmd_print(VRS_PRINT_DEBUG_MSG, (struct Generic_Cmd*)vbucket->data);
				vbucket = vbucket->next;
			}
		}
	}
}
Example #3
0
/**
 * \brief This function try to pack message that is going to be
 * sent in STREAM OPEN state
 *
 * \param[in] *C The pointer at context
 *
 * \return This function return 1, when there is something to send,
 * it returns -1, when there is nothing to send and it returns 0, when
 * there is some error
 */
int v_STREAM_pack_message(struct vContext *C)
{
	struct VS_CTX *vs_ctx = CTX_server_ctx(C);
	struct VSession *vsession = CTX_current_session(C);
	struct VStreamConn *conn = CTX_current_stream_conn(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VMessage *s_message = CTX_s_message(C);
	struct Generic_Cmd *cmd, *fake_cmd;
	int ret = -1, queue_size = 0, buffer_pos = 0, prio_cmd_count, cmd_rank=0;
	int8 cmd_share;
	int16 prio, max_prio, min_prio;
	uint16 cmd_count, cmd_len, prio_win, swin, sent_size, tot_cmd_size;
	real32 prio_sum_high, prio_sum_low, r_prio;
	int is_fake_cmd_received = 0;

	/* Is here something to send? */
	if((v_out_queue_get_count(vsession->out_queue) > 0) ||
			(vsession->tmp_flags & SYS_CMD_NEGOTIATE_FPS))
	{

		/* Get current size of data in TCP outgoing buffer */
#ifdef __linux__
		if( ioctl(io_ctx->sockfd, SIOCOUTQ, &queue_size) == -1 ) {
			v_print_log(VRS_PRINT_ERROR,
					"ioctl(%d, SIOCOUTQ, ...): %s\n",
					io_ctx->sockfd,
					strerror(errno));
			return 0;
		}
#endif

		/* Compute, how many data could be added to the TCP stack? */
		swin = conn->socket_buffer_size - queue_size;

		buffer_pos = VERSE_MESSAGE_HEADER_SIZE;

		s_message->sys_cmd[0].cmd.id = CMD_RESERVED_ID;

		/* When negotiated and used FPS is different, then pack negotiate command
		 * for FPS */
		if(vsession->fps_host != vsession->fps_peer) {
			cmd_rank += v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank,
					CMD_CHANGE_L_ID, FTR_FPS, &vsession->fps_host, NULL);
		} else {
			if(vsession->tmp_flags & SYS_CMD_NEGOTIATE_FPS) {
				cmd_rank += v_add_negotiate_cmd(s_message->sys_cmd, cmd_rank,
						CMD_CONFIRM_L_ID, FTR_FPS, &vsession->fps_peer, NULL);
				/* Send confirmation only once for received system command */
				vsession->tmp_flags &= ~SYS_CMD_NEGOTIATE_FPS;
			}
		}

		buffer_pos += v_pack_stream_system_commands(s_message, &io_ctx->buf[buffer_pos]);

		max_prio = v_out_queue_get_max_prio(vsession->out_queue);
		min_prio = v_out_queue_get_min_prio(vsession->out_queue);

		prio_sum_high = v_out_queue_get_prio_sum_high(vsession->out_queue);
		prio_sum_low = v_out_queue_get_prio_sum_low(vsession->out_queue);

		v_print_log(VRS_PRINT_DEBUG_MSG, "Packing prio queues, cmd count: %d\n",
				v_out_queue_get_count(vsession->out_queue));

		/* Go through all priorities and pick commands from priority queues */
		for(prio = max_prio; prio >= min_prio; prio--)
		{
			prio_cmd_count = v_out_queue_get_count_prio(vsession->out_queue, prio);

			if(prio_cmd_count > 0) {

				r_prio = v_out_queue_get_prio(vsession->out_queue, prio);

				/* Compute size of buffer that could be occupied by
				 * commands from this queue */
				if(prio >= VRS_DEFAULT_PRIORITY) {
					prio_win = ((swin - buffer_pos)*r_prio)/prio_sum_high;
				} else {
					prio_win = ((swin - buffer_pos)*r_prio)/prio_sum_low;
				}

				/* Debug print */
				v_print_log(VRS_PRINT_DEBUG_MSG, "Queue: %d, count: %d, r_prio: %6.3f, prio_win: %d\n",
						prio, prio_cmd_count, r_prio, prio_win);

				/* Get total size of commands that were stored in queue (sent_size) */
				sent_size = 0;
				tot_cmd_size = 0;

				while(prio_cmd_count > 0) {
					cmd_share = 0;
					cmd_count = 0;
					cmd_len = prio_win - sent_size;

					/* Pack commands from queues with high priority to the buffer */
					cmd = v_out_queue_pop(vsession->out_queue, prio, &cmd_count, &cmd_share, &cmd_len);
					if(cmd != NULL) {

						/* Is this command fake command? */
						if(cmd->id < MIN_CMD_ID) {
							if(cmd->id == FAKE_CMD_CONNECT_TERMINATE) {
								/* Close connection */
								struct VS_CTX *vs_ctx = CTX_server_ctx(C);
								if(vs_ctx != NULL) {
									vsession->stream_conn->host_state = TCP_SERVER_STATE_CLOSING;
								} else {
									vsession->stream_conn->host_state = TCP_CLIENT_STATE_CLOSING;
								}
							} else if(cmd->id == FAKE_CMD_FPS) {
								struct Fps_Cmd *fps_cmd = (struct Fps_Cmd*)cmd;
								/* Change value of FPS. It will be sent in negotiate command
								 * until it is confirmed be the peer (server) */
								vsession->fps_host = fps_cmd->fps;
							}
						} else {
							buffer_pos += tot_cmd_size = v_cmd_pack(&io_ctx->buf[buffer_pos], cmd, v_cmd_size(cmd), 0);
							if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
								printf("%c[%d;%dm", 27, 1, 32);
								v_cmd_print(VRS_PRINT_DEBUG_MSG, cmd);
								printf("%c[%dm", 27, 0);
							}
							sent_size += tot_cmd_size;
						}

						fake_cmd = v_cmd_fake_ack(cmd);

						if(fake_cmd != NULL) {
							is_fake_cmd_received = 1;
							/* Push command to the queue of incoming 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);
						}

						/* It is not necessary to put cmd to history of sent commands,
						 * when TCP is used. */
						v_cmd_destroy(&cmd);
						prio_cmd_count--;
					} else {
						break;
					}
				}
			}
		}

		s_message->header.len = io_ctx->buf_size = buffer_pos;
		s_message->header.version = VRS_VERSION;

		/* Pack header to the beginning of the buffer */
		v_pack_message_header(s_message, io_ctx->buf);

		/* Debug print of command to be send */
		if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
			v_print_send_message(C);
		}

		/* 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)) {
			sem_post(vs_ctx->data.sem);
		}

		ret = 1;

	}

	return ret;
}
Example #4
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;
}
Example #5
0
/**
 * \brief This function packs and compress command to the packet from one
 * priority queue.
 *
 * \param[in]	*C	The verse context
 * \param[in]	*sent_packet	The pointer at structure with send packet
 * \param[in]	buffer_pos		The curent size of buffer of sent packet
 * \param[in]	prio			The priority of sub queue
 * \param[in]	prio_win		The window size of current prio queue
 * \param[out]	tot_cmd_size	The total size of commands that were poped from prio queue
 */
static int pack_prio_queue(struct vContext *C,
		struct VSent_Packet *sent_packet,
		int buffer_pos,
		uint8 prio,
		uint16 prio_win,
		uint16 *tot_cmd_size)
{
	struct VSession *vsession = CTX_current_session(C);
	struct VDgramConn *vconn = CTX_current_dgram_conn(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct Generic_Cmd *cmd;
	int ret, last_cmd_count = 0;
	uint16 cmd_count, cmd_len, cmd_size, sum_len=0;
	int8 cmd_share;
	uint8  last_cmd_id = CMD_RESERVED_ID;

	while( (v_out_queue_get_count_prio(vsession->out_queue, prio) > 0) &&
			(sum_len < prio_win) &&
			(buffer_pos < vconn->io_ctx.mtu))
	{
		cmd_count = 0;
		cmd_share = 0;

		/* Compute how many commands could be compressed to the packet
		 * and compute right length of compressed commands. */
		cmd_len = ((prio_win - sum_len)<(vconn->io_ctx.mtu - buffer_pos)) ?
				(prio_win - sum_len) :
				(vconn->io_ctx.mtu - buffer_pos);

		/* Remove command from queue */
		cmd = v_out_queue_pop(vsession->out_queue, prio, &cmd_count, &cmd_share, &cmd_len);

		/* When it is not possible to pop more commands from queue, then break
		 * while loop */
		if(cmd == NULL) {
			break;
		}

		/* Is this command fake command? */
		if(cmd->id < MIN_CMD_ID) {
			if(cmd->id == FAKE_CMD_CONNECT_TERMINATE) {
				struct VS_CTX *vs_ctx = CTX_server_ctx(C);
				if(vs_ctx != NULL) {
					vconn->host_state = UDP_SERVER_STATE_CLOSEREQ;
				} else {
					vconn->host_state = UDP_CLIENT_STATE_CLOSING;
				}
			} else if(cmd->id == FAKE_CMD_FPS) {
				struct Fps_Cmd *fps_cmd = (struct Fps_Cmd*)cmd;
				/* Change value of FPS. It will be sent in negotiate command
				 * until it is confirmed be the peer (server) */
				vsession->fps_host = fps_cmd->fps;
			}
			v_cmd_destroy(&cmd);
		} else {

			/* What was size of command in queue */
			cmd_size = v_cmd_size(cmd);

			if(!(buffer_pos < (vconn->io_ctx.mtu - cmd_size))) {
				/* When there is not enough space for other command,
				 * then push command back to the beginning of queue. */
				v_out_queue_push_head(vsession->out_queue, prio, cmd);
				break;
			} else {

				/* Update total size of commands that were poped from queue */
				*tot_cmd_size += cmd_size;

				/* When compression is not allowed, then add this command as is */
				if( vconn->host_cmd_cmpr == CMPR_NONE) {
					cmd_count = 0;
					cmd_len = cmd_size;
					/* Debug print */
					v_print_log(VRS_PRINT_DEBUG_MSG, "Cmd: %d, count: %d, length: %d\n",
							cmd->id, cmd_count, cmd_len);
					/* Add command to the buffer */
					buffer_pos += v_cmd_pack(&io_ctx->buf[buffer_pos], cmd, cmd_len, 0);
				} else {
					/* When command compression is allowed and was ID of command changed? */
					if( (cmd->id != last_cmd_id) || (last_cmd_count <= 0) )	{
						/* When this command is alone, then use default command size */
						if(cmd_count == 0) {
							cmd_len = cmd_size;
						} else {
							/* FIXME: do not recompute command length here, but do it right,
							 * when command is added to the queue */
							cmd_len = v_cmds_len(cmd, cmd_count, cmd_share, cmd_len);
						}
						/* Debug print */
						v_print_log(VRS_PRINT_DEBUG_MSG, "Cmd: %d, count: %d, length: %d\n",
								cmd->id, cmd_count, cmd_len);
						/* Add command to the buffer */
						buffer_pos += v_cmd_pack(&io_ctx->buf[buffer_pos], cmd, cmd_len, cmd_share);
						/* Set up current count of commands in the line */
						last_cmd_count = cmd_count;
						/* Update summary of commands length */
						sum_len += cmd_len;
					} else {
						buffer_pos += v_cmd_pack(&io_ctx->buf[buffer_pos], cmd, 0, cmd_share);
					}
				}

				/* Print command */
				v_cmd_print(VRS_PRINT_DEBUG_MSG, cmd);

				/* TODO: remove command alias here (layer value set/unset) */

				/* Add command to the packet history */
				ret = v_packet_history_add_cmd(&vconn->packet_history, sent_packet, cmd, prio);
				assert(ret==1);

				/* Update last command id */
				last_cmd_id = cmd->id;
				/* Decrement counter of commands in queue */
				last_cmd_count--;
			}
		}
	}

	return buffer_pos;
}
Example #6
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;
}