예제 #1
0
int vc_CLOSING_handle_packet(struct vContext *C)
{
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct VPacket *r_packet = CTX_r_packet(C);

	/* Received packet has to have PAY flag (this packet have to be acknowledged),
	 * ACK flag (it has to acknowledge close request) and FIN flag (it is
	 * teardown packet) */
	if(r_packet->header.flags == (PAY_FLAG|ACK_FLAG|FIN_FLAG) &&
		/* Does this packet acknowledge right ID? (ACK command has to be first command!) */
			r_packet->sys_cmd[0].cmd.id==CMD_ACK_ID &&
			r_packet->sys_cmd[0].ack_cmd.pay_id==dgram_conn->host_id + dgram_conn->count_s_pay)
	{
		/* Client state */
		dgram_conn->host_state = UDP_CLIENT_STATE_CLOSED;

		/* Call callback functions for system commands */
		v_conn_dgram_handle_sys_cmds(C, UDP_CLIENT_STATE_CLOSING);

		/* Compute RWIN */
		dgram_conn->rwin_peer = r_packet->header.window << dgram_conn->rwin_peer_scale;
	}
	else {
		if(is_log_level(VRS_PRINT_WARNING)) v_print_log(VRS_PRINT_WARNING, "Packet with corrupted header was dropped.\n");
		return RECEIVE_PACKET_CORRUPTED;
	}

	return RECEIVE_PACKET_SUCCESS;
}
예제 #2
0
int vc_PARTOPEN_handle_packet(struct vContext *C)
{
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct VPacket *r_packet = CTX_r_packet(C);

	/* Verse packet header has to include some flags and verse packet has to contain ack command */
	if(r_packet->header.flags == (PAY_FLAG|ACK_FLAG|ANK_FLAG) &&
			/* Payload ID has to be incremented */
			r_packet->header.payload_id == dgram_conn->peer_id+1 &&
			/* Does this packet contain ANK ID of last acknowledged Payload ID? */
			r_packet->header.ank_id == dgram_conn->peer_id &&
			/* Does this packet acknowledge right ID? (ACK command has to be first command!) */
			r_packet->sys_cmd[0].cmd.id == CMD_ACK_ID &&
			r_packet->sys_cmd[0].ack_cmd.pay_id == dgram_conn->host_id+1 )
	{
		/* Client state */
		dgram_conn->host_state = UDP_CLIENT_STATE_OPEN;

		/* Call callback functions for system commands */
		if(v_conn_dgram_handle_sys_cmds(C, UDP_CLIENT_STATE_PARTOPEN) != 1) {
			v_print_log(VRS_PRINT_WARNING, "Received packet with wrong system command(s)\n");
			return RECEIVE_PACKET_CORRUPTED;
		}

		/* Compute RWIN */
		dgram_conn->rwin_peer = r_packet->header.window << dgram_conn->rwin_peer_scale;
	} else {
		if(is_log_level(VRS_PRINT_WARNING)) v_print_log(VRS_PRINT_WARNING, "Packet with bad header was dropped.\n");
		return RECEIVE_PACKET_CORRUPTED;
	}

	return RECEIVE_PACKET_SUCCESS;
}
예제 #3
0
int vc_REQUEST_handle_packet(struct vContext *C)
{
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct VPacket *r_packet = CTX_r_packet(C);

	/* Received packet has to have PAY flag (this packet have to be acknowledged),
	 * ACK flag (acknowledgment of request packet sent to the server) and
	 * SYN flag (it is handshake packet) */
	if(r_packet->header.flags == (PAY_FLAG|ACK_FLAG|SYN_FLAG) &&
			/* Does this packet acknowledge right ID? (ACK command has to be first command!) */
			r_packet->sys_cmd[0].cmd.id==CMD_ACK_ID &&
			r_packet->sys_cmd[0].ack_cmd.pay_id==dgram_conn->host_id)
	{
		/* Client state */
		dgram_conn->host_state = UDP_CLIENT_STATE_PARTOPEN;

		/* Save ID of received payload packet */
		dgram_conn->peer_id = r_packet->header.payload_id;

		/* Call callback functions for system commands */
		if(v_conn_dgram_handle_sys_cmds(C, UDP_CLIENT_STATE_REQUEST)!=1) {
			v_print_log(VRS_PRINT_WARNING, "Received packet with wrong system command(s)\n");
			return RECEIVE_PACKET_CORRUPTED;
		}

		/* Compute RWIN */
		dgram_conn->rwin_peer = r_packet->header.window << dgram_conn->rwin_peer_scale;
	}
	else {
		v_print_log(VRS_PRINT_WARNING, "Packet with corrupted header was dropped.\n");
		return RECEIVE_PACKET_CORRUPTED;
	}

	return RECEIVE_PACKET_SUCCESS;
}
예제 #4
0
/**
 * \brief Check if it is necessary to send acknowledgment packet?
 */
static int check_ack_nak_flag(struct vContext *C)
{
	struct VDgramConn *vconn = CTX_current_dgram_conn(C);
	struct VPacket *s_packet = CTX_s_packet(C);
	struct VPacket *last_r_packet = CTX_r_packet(C);
	int ret = 0;

	/* Is it necessary to acknowledge payload packet? Several conditions
	 * has to be accomplished */

	/* There has to be some ACK and NAK commands for sending */
	if( vconn->ack_nak.count > 0 ) {
		if(
			/* Piggy packing of AckNak packet to the payload packet */
			(s_packet->header.flags & PAY_FLAG)
				||
			/* Last received packet was payload packet (not only AckNak packet) ... */
			(
					(last_r_packet->header.flags & PAY_FLAG) &&
					(last_r_packet->acked == 0)
			)
		)
		{
			last_r_packet->acked = 1;
			ret = 1;
		}
	}

	return ret;
}
예제 #5
0
/**
 * \brief Call callback functions for all received system commands. Each state
 * could have different callback function that is stored in VConnection
 * structure.
 * \param[in]	*C			The Verse context;
 * \param[in]	state_id	The id of the current state
 * \return		The function returns 1, when all system commands were processes
 * without problem and it returns 0, when some error occurs.
 */
int v_conn_dgram_handle_sys_cmds(struct vContext *C, const unsigned short state_id)
{
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct VPacket *r_packet = CTX_r_packet(C);
	int cmd_rank, r, ret = 1;

	/* Parse system commands (not ACK and NAK messages ... these are proccessed separately) */
	for(cmd_rank=0;
			r_packet->sys_cmd[cmd_rank].cmd.id != CMD_RESERVED_ID &&
					cmd_rank < MAX_SYSTEM_COMMAND_COUNT;
			cmd_rank++)
	{
		switch (r_packet->sys_cmd[cmd_rank].cmd.id) {
		case CMD_ACK_ID:
			break;
		case CMD_NAK_ID:
			break;
		case CMD_CHANGE_L_ID:
			if(dgram_conn->state[state_id].CHANGE_L_cb) {
				r = dgram_conn->state[state_id].CHANGE_L_cb(C, &r_packet->sys_cmd[cmd_rank].cmd);
				ret = (ret==0)?0:r;
			}
			break;
		case CMD_CHANGE_R_ID:
			if(dgram_conn->state[state_id].CHANGE_R_cb) {
				r = dgram_conn->state[state_id].CHANGE_R_cb(C, &r_packet->sys_cmd[cmd_rank].cmd);
				ret = (ret==0)?0:r;
			}
			break;
		case CMD_CONFIRM_L_ID:
			if(dgram_conn->state[state_id].CONFIRM_L_cb) {
				r = dgram_conn->state[state_id].CONFIRM_L_cb(C, &r_packet->sys_cmd[cmd_rank].cmd);
				ret = (ret==0)?0:r;
			}
			break;
		case CMD_CONFIRM_R_ID:
			if(dgram_conn->state[state_id].CONFIRM_R_cb) {
				r = dgram_conn->state[state_id].CONFIRM_R_cb(C, &r_packet->sys_cmd[cmd_rank].cmd);
				ret = (ret==0)?0:r;
			}
			break;
		default:
			/* Unknown command ID */
			if(is_log_level(VRS_PRINT_WARNING)) {
				v_print_log(VRS_PRINT_WARNING, "Unknown system command ID: %d\n", r_packet->sys_cmd[cmd_rank].cmd.id);
			}
			break;
		}
	}

	return ret;
}
예제 #6
0
void vc_PARTOPEN_init_send_packet(struct vContext *C)
{
	struct VSession *vsession = CTX_current_session(C);
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct VPacket *s_packet = CTX_s_packet(C);
	struct VPacket *r_packet = CTX_r_packet(C);
	int cmd_rank = 0;

	/* Verse packet header */
	s_packet->header.version = 1;
	s_packet->header.flags = PAY_FLAG | ACK_FLAG ;
	s_packet->header.window = dgram_conn->rwin_host >> dgram_conn->rwin_host_scale;
	s_packet->header.payload_id = dgram_conn->host_id + 1;
	s_packet->header.ack_nak_id = 0;
	if(r_packet->sys_cmd[0].cmd.id == CMD_ACK_ID) {
		s_packet->header.flags |= ANK_FLAG;
		s_packet->header.ank_id = r_packet->sys_cmd[0].ack_cmd.pay_id;
		dgram_conn->ank_id = r_packet->sys_cmd[0].ack_cmd.pay_id;
	} else {
		s_packet->header.ank_id = 0;
	}

	/* System commands */
	s_packet->sys_cmd[cmd_rank].ack_cmd.id = CMD_ACK_ID;
	s_packet->sys_cmd[cmd_rank].ack_cmd.pay_id = dgram_conn->peer_id;
	cmd_rank++;

	/* Confirm proposed TOKEN */
	if(vsession->peer_token.str!=NULL) {
		cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
				CMD_CONFIRM_L_ID, FTR_TOKEN, vsession->peer_token.str, NULL);
	}

	/* Confirm proposed Flow Control ID */
	if(dgram_conn->fc_meth != FC_RESERVED) {
		cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
				CMD_CONFIRM_L_ID, FTR_FC_ID, &dgram_conn->fc_meth, NULL);
		cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
				CMD_CONFIRM_R_ID, FTR_FC_ID, &dgram_conn->fc_meth, NULL);
	}

	/* Confirm proposed shifting of Flow Control Window */
	if(dgram_conn->rwin_peer_scale != 0) {
		cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
				CMD_CONFIRM_L_ID, FTR_RWIN_SCALE, &dgram_conn->rwin_peer_scale, NULL);
	}
}
예제 #7
0
파일: v_network.c 프로젝트: donno/verse
void v_print_receive_packet(struct vContext *C)
{
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct VPacket *r_packet = CTX_r_packet(C);

	if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
		printf("%c[%d;%dm", 27, 1, 34);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Receive packet: ");
		v_print_log_simple(VRS_PRINT_DEBUG_MSG, "Socket: %d, ", io_ctx->sockfd);
		v_print_log_simple(VRS_PRINT_DEBUG_MSG, "bufsize: %d, ", io_ctx->buf_size);
		v_print_addr_port(VRS_PRINT_DEBUG_MSG, &io_ctx->peer_addr);
		v_print_packet_header(VRS_PRINT_DEBUG_MSG, r_packet);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Shift: %d -> Window: %d\n", dgram_conn->rwin_host_scale, (unsigned int)r_packet->header.window << dgram_conn->rwin_host_scale);
		v_print_packet_sys_cmds(VRS_PRINT_DEBUG_MSG, r_packet);
		printf("%c[%dm", 27, 0);
	}
}
예제 #8
0
/**
 * \brief This function handles node commands, when payload packet was received.
 *
 * This function also detects packet loss of previous not received payload
 * packets. All node commands are unpacked from the buffer and added to incoming queue.
 *
 * \param[in]	*C	The verse context.
 *
 * \return		This function returns RECEIVE_PACKET_DELAYED, when delayd packet
 * was received, otherwise it returns RECEIVE_PACKET_SUCCESS.
 */
static int handle_node_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 Ack_Nak_Cmd ack_nak_cmd;

	/* Note: when ACK and NAK command are add to the AckNak history,
	 * then this vector of commands is automatically compressed. */

	/* Was any packet lost since last receiving of packet? */
	if(r_packet->header.payload_id > vconn->last_r_pay+1) {
		v_print_log(VRS_PRINT_DEBUG_MSG, "Packet(s) lost: %d - %d\n",
				vconn->last_r_pay+1, r_packet->header.payload_id-1);
		/* Add NAK command to the list of ACK NAK commands */
		ack_nak_cmd.id = CMD_NAK_ID;
		ack_nak_cmd.pay_id = vconn->last_r_pay+1;
		v_ack_nak_history_add_cmd(&vconn->ack_nak, &ack_nak_cmd);
	/* Was some delayed packet received? */
	} else if(r_packet->header.payload_id < vconn->last_r_pay+1) {
		if(is_log_level(VRS_PRINT_WARNING))
			v_print_log(VRS_PRINT_WARNING, "Received unordered packet: %d, expected: %d\n", r_packet->header.payload_id, vconn->last_r_pay+1);
		/* Drop this packet */
		return RECEIVE_PACKET_UNORDERED;
	}

	/* ADD ACK command to the list of ACK NAK commands */
	ack_nak_cmd.id = CMD_ACK_ID;
	ack_nak_cmd.pay_id = r_packet->header.payload_id;
	v_ack_nak_history_add_cmd(&vconn->ack_nak, &ack_nak_cmd);

	/* Check if there are really node commands */
	if(r_packet->data!=NULL) {
		/* Unpack node commands and put them to the queue of incoming commands */
		v_cmd_unpack((char*)r_packet->data, r_packet->data_size, vsession->in_queue);
	}

	return RECEIVE_PACKET_SUCCESS;
}
예제 #9
0
/* Generic receiving and handling of packet */
int vc_receive_and_handle_packet(struct vContext *C, int handle_packet(struct vContext *C))
{
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VPacket *r_packet = CTX_r_packet(C);
	int ret, error_num;
	long int sec = 0, usec = 0;
	fd_set set;
	struct timeval tv;

	/* Initialize set */
	FD_ZERO(&set);
	FD_SET(dgram_conn->io_ctx.sockfd, &set);

	switch(dgram_conn->host_state) {
		case UDP_CLIENT_STATE_REQUEST:
		case UDP_CLIENT_STATE_PARTOPEN:
		case UDP_CLIENT_STATE_CLOSING:
			sec = INIT_TIMEOUT + (int) (v_exponential_backoff(dgram_conn->state[dgram_conn->host_state].attempts) * (rand() / (RAND_MAX + 1.0)));
			usec = 0;
			break;
		case UDP_CLIENT_STATE_OPEN:
			sec = 0;
			usec = 10000;
			break;
	}

	/* Initialize time value */
	tv.tv_sec = sec;
	tv.tv_usec = usec;

	/* Wait on response from server */
	if( (ret = select(io_ctx->sockfd+1, &set, NULL, NULL, &tv)) == -1 ) {
		if(is_log_level(VRS_PRINT_ERROR)) v_print_log(VRS_PRINT_ERROR, "%s:%s():%d select(): %s\n", __FILE__, __FUNCTION__,  __LINE__, strerror(errno));
		return RECEIVE_PACKET_ERROR;
	}
	/* Check if the event occurred on sockfd */
	else if(ret>0 && FD_ISSET(io_ctx->sockfd, &set)) {
		/* Try to receive packet from server */
		if(v_receive_packet(io_ctx, &error_num) == -1) {
			switch(error_num) {
				case ECONNREFUSED:	/* A remote host refused this connection */
					return RECEIVE_PACKET_ERROR;
				case EAGAIN:
				case EBADF:
				case EFAULT:
				case EINTR:
				case EINVAL:
				case ENOMEM:
				case ENOTCONN:
				case ENOTSOCK:
					break;
			}
		/* Address of received packet has to be same as address of server, when
		 * connection is not connected */
		} else if((io_ctx->flags & SOCKET_CONNECTED) ||
				v_compare_addr_and_port(&dgram_conn->peer_address, &dgram_conn->io_ctx.peer_addr))
		{
			/* The size of buffer must be bigger then zero */
			if(dgram_conn->io_ctx.buf_size>0) {
				int buffer_pos = 0;

				/* Get time of receiving packet */
				gettimeofday(&tv, NULL);

				/* Extract verse header from packet */
				ret = v_unpack_packet_header(io_ctx->buf,
						io_ctx->buf_size,
						r_packet);
				if(ret != VERSE_PACKET_HEADER_SIZE)
					return RECEIVE_PACKET_CORRUPTED;

				/* Check for right packet header version number */
				if(r_packet->header.version != VRS_VERSION) {
					if(is_log_level(VRS_PRINT_WARNING)) v_print_log(VRS_PRINT_WARNING, "Packet with unsupported version: %d was dropped.\n",
							r_packet->header.version);
					return RECEIVE_PACKET_CORRUPTED;
				}

				/* Compute RWIN */
				dgram_conn->rwin_peer = r_packet->header.window << dgram_conn->rwin_peer_scale;

				/* Extract system commands from packet */
				buffer_pos += v_unpack_packet_system_commands(io_ctx->buf,
						io_ctx->buf_size,
						r_packet);

				/* Are there some node commands in the buffer? */
				if(io_ctx->buf_size > buffer_pos) {
					/* Set pointer to not proceeded buffer */
					r_packet->data = (uint8*)&io_ctx->buf[buffer_pos];
					/* Set size of not proceeded buffer */
					r_packet->data_size = io_ctx->buf_size - buffer_pos;
				} else {
					r_packet->data = NULL;
					r_packet->data_size = 0;
				}

				/* When important things are done, then print content of the
				 * command (in debug mode) */
				v_print_receive_packet(C);

				/* Handle received packet and its data */
				ret = handle_packet(C);

				if(ret == RECEIVE_PACKET_SUCCESS) {
					/* Update information about last received packet payload
					 * packet */
					if(r_packet->header.flags & PAY_FLAG) {
						dgram_conn->last_r_pay = r_packet->header.payload_id;
						/* Update time of last received payload packet */
						dgram_conn->tv_pay_recv.tv_sec = tv.tv_sec;
						dgram_conn->tv_pay_recv.tv_usec = tv.tv_usec;
					}
					/* Update information about last received packet acknowledgment
					 * packet */
					if(r_packet->header.flags & ACK_FLAG) {
						dgram_conn->last_r_ack = r_packet->header.ack_nak_id;
					}
				}

				return ret;

			} else {
				if(is_log_level(VRS_PRINT_WARNING)) v_print_log(VRS_PRINT_WARNING, "Packet with zero size was dropped.\n");
				return RECEIVE_PACKET_CORRUPTED;
			}
		} else {
			/* When some 'bad' packet is received on this port, then do not increase counter
			 * of connection attempts (packet was received from address, that does not belong
			 * to the server) */
			if(is_log_level(VRS_PRINT_WARNING))
				v_print_log(VRS_PRINT_WARNING, "Packet from unknown address was dropped.\n");

			return RECEIVE_PACKET_FAKED;	/* This should not happen, because connect() function is used */
		}
	}

	return RECEIVE_PACKET_TIMEOUT;
}
예제 #10
0
int vc_OPEN_loop(struct vContext *C)
{
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct VPacket *r_packet = CTX_r_packet(C);
	struct Ack_Nak_Cmd ack_cmd;
	int ret;

	/* OPEN state */
	if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
		printf("%c[%d;%dm", 27, 1, 31);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Client state: OPEN\n");
		printf("%c[%dm", 27, 0);
	}

	/* Add ACK command to the list of ACK NAK commands to be send to the peer */
	ack_cmd.id = CMD_ACK_ID;
	ack_cmd.pay_id = r_packet->header.payload_id;
	v_ack_nak_history_add_cmd(&dgram_conn->ack_nak, &ack_cmd);

	/* Receiving of last packet in previous packet had to be successful, because
	 * client is in this state now :-). */
	ret = RECEIVE_PACKET_SUCCESS;

	while(dgram_conn->host_state == UDP_CLIENT_STATE_OPEN) {

		dgram_conn->state[UDP_CLIENT_STATE_OPEN].attempts++;

		/* Send payload data or keep-alive packet */
		if( vc_OPEN_send_packet(C) == SEND_PACKET_ERROR ) {
			return STATE_EXIT_ERROR;
		}

		/* Try to receive packet and handle received packet */
		ret = vc_receive_and_handle_packet(C, vc_OPEN_handle_packet);
		if(ret == RECEIVE_PACKET_SUCCESS) {
			continue;
		} else if(ret == RECEIVE_PACKET_TIMEOUT) {
			struct timeval tv;
			gettimeofday(&tv, NULL);
			/* When no valid packet received from server for defined time, then consider this
			 * connection as dead and return error */
			if((tv.tv_sec - dgram_conn->tv_pay_recv.tv_sec) >= VRS_TIMEOUT) {
				return STATE_EXIT_ERROR;
			} else {
				continue;
			}
		} else if(ret == RECEIVE_PACKET_CORRUPTED) {
			continue;
		} else if(ret == RECEIVE_PACKET_FAKED) {
			return STATE_EXIT_ERROR;
		} else if(ret == RECEIVE_PACKET_ERROR) {
			return STATE_EXIT_ERROR;
		}

#ifdef WITH_OPENSSL
		if(dgram_conn->io_ctx.flags & SOCKET_SECURED) {
			/* Did server close DTLS connection? */
			if((SSL_get_shutdown(dgram_conn->io_ctx.ssl) & SSL_RECEIVED_SHUTDOWN)) {
				return STATE_EXIT_ERROR;
			}
		}
#endif
	}

	return STATE_EXIT_SUCCESS;
}
예제 #11
0
/**
 * \brief This command handle received packets in OPEN state at client and
 * server in the same way.
 */
int handle_packet_in_OPEN_state(struct vContext *C)
{
	struct VDgramConn *vconn = CTX_current_dgram_conn(C);
	struct VSession *vsession = CTX_current_session(C);
	struct VPacket *r_packet = CTX_r_packet(C);
	int ret, first_sys_index, i;

	/* Does packet contains node commands? */
	if(r_packet->header.flags & PAY_FLAG) {
		ret = handle_node_commands(C);
		if(ret == RECEIVE_PACKET_UNORDERED)
			return ret;
		r_packet->acked=0;
	}

	/* Compute real RWIN of Flow Control */
	vconn->rwin_peer = r_packet->header.window << vconn->rwin_peer_scale;

	/* Was packet received with any ACK or NAK command? */
	if(r_packet->header.flags & ACK_FLAG) {
		ret = handle_ack_nak_commands(C);
	}

	/* Handle other system commands */
	if(ret>=0) {
		first_sys_index = ret;
	} else {
		first_sys_index = 0;
	}

	for(i=first_sys_index;
			i<MAX_SYSTEM_COMMAND_COUNT && r_packet->sys_cmd[i].cmd.id != CMD_RESERVED_ID;
			i++)
	{
		if(r_packet->sys_cmd[i].cmd.id == CMD_CHANGE_L_ID &&
				r_packet->sys_cmd[i].negotiate_cmd.feature == FTR_FPS &&
				r_packet->sys_cmd[i].negotiate_cmd.count > 0)
		{
			vsession->fps_host = vsession->fps_peer = r_packet->sys_cmd[i].negotiate_cmd.value->real32;
			vsession->tmp_flags |= SYS_CMD_NEGOTIATE_FPS;
		}

		if(r_packet->sys_cmd[i].cmd.id == CMD_CONFIRM_L_ID &&
				r_packet->sys_cmd[i].negotiate_cmd.feature == FTR_FPS &&
				r_packet->sys_cmd[i].negotiate_cmd.count > 0)
		{
			vsession->fps_peer = r_packet->sys_cmd[i].negotiate_cmd.value->real32;
		}
	}

	/* Was packet received with valid ANK ID? */
	if(r_packet->header.flags & ANK_FLAG) {
		/* Remove appropriate ACK and NAK commands form the history of ACK
		 * and NAK commands */
		v_ack_nak_history_remove_cmds(&vconn->ack_nak, r_packet->header.ank_id);
	}

	/* Does peer want to finish this connection? */
	if(r_packet->header.flags & FIN_FLAG) {
		/* Change host state. Main connection loop will do the rest. */
		vconn->host_state = UDP_CLIENT_STATE_CLOSING;
	}

	return RECEIVE_PACKET_SUCCESS;
}
예제 #12
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;
}
예제 #13
0
파일: v_history.c 프로젝트: donno/verse
/**
 * \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;
}