Пример #1
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;
}
Пример #2
0
void vc_REQUEST_init_send_packet(struct vContext *C)
{
	struct VC_CTX *vc_ctx = CTX_client_ctx(C);
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct VSession *vsession = CTX_current_session(C);
	struct VPacket *s_packet = CTX_s_packet(C);
	int cmd_rank = 0;
	static const uint8 cc_none = CC_NONE,
			cmpr_none = CMPR_NONE,
			cmpr_addr_share = CMPR_ADDR_SHARE;

	/* Verse packet header */
	s_packet->header.version = 1;
	s_packet->header.flags = PAY_FLAG | SYN_FLAG;
	s_packet->header.window = dgram_conn->rwin_host >> dgram_conn->rwin_host_scale;
	s_packet->header.payload_id = dgram_conn->host_id;
	s_packet->header.ack_nak_id = 0;
	s_packet->header.ank_id = 0;

	/* System commands */
	if(vsession->host_token.str!=NULL) {
		/* Add negotiated token */
		cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
				CMD_CHANGE_L_ID, FTR_TOKEN, vsession->host_token.str, NULL);
	}

	/* Add CC (local) proposal */
	cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
			CMD_CHANGE_L_ID, FTR_CC_ID, &cc_none, NULL);

	/* Add CC (remote) proposal */
	cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
			CMD_CHANGE_R_ID, FTR_CC_ID, &cc_none, NULL);

	/* Add Scale Window proposal */
	cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
			CMD_CHANGE_L_ID, FTR_RWIN_SCALE, &vc_ctx->rwin_scale, NULL);

	/* Add command compression proposal */
	if(vsession->flags & VRS_CMD_CMPR_NONE) {
		/* Client doesn't want to send compressed commands (local proposal) */
		cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
				CMD_CHANGE_L_ID, FTR_CMD_COMPRESS, &cmpr_none, NULL);
		/* Client isn't able to receive compressed commands (remote proposal) */
		cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
				CMD_CHANGE_R_ID, FTR_CMD_COMPRESS, &cmpr_none, NULL);
	} else {
		/* Client wants to send compressed commands (local proposal) */
		cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
				CMD_CHANGE_L_ID, FTR_CMD_COMPRESS, &cmpr_addr_share, NULL);
		/* Client is able to receive compressed commands (remote proposal) */
		cmd_rank += v_add_negotiate_cmd(s_packet->sys_cmd, cmd_rank,
				CMD_CHANGE_R_ID, FTR_CMD_COMPRESS, &cmpr_addr_share, NULL);
	}
}
Пример #3
0
int vc_send_packet(struct vContext *C)
{
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VPacket *s_packet = CTX_s_packet(C);
	int error_num;
	struct timeval tv;
	unsigned short buffer_pos = 0;
	int ret;

	v_print_send_packet(C);

	/* Fill buffer */
	buffer_pos += v_pack_packet_header(s_packet, &io_ctx->buf[buffer_pos]);
	buffer_pos += v_pack_dgram_system_commands(s_packet, &io_ctx->buf[buffer_pos]);
	io_ctx->buf_size = buffer_pos;

	/* Send buffer */
	ret = v_send_packet(io_ctx, &error_num);

	if(ret == SEND_PACKET_SUCCESS) {

		/* Update time of sending last packet */
		gettimeofday(&tv, NULL);
		dgram_conn->tv_pay_send.tv_sec = tv.tv_sec;
		dgram_conn->tv_pay_send.tv_usec = tv.tv_usec;

		/* Update counter of sent packets */
		switch(dgram_conn->host_state) {
		case UDP_CLIENT_STATE_REQUEST:
			dgram_conn->count_s_pay = 1;
			dgram_conn->count_s_ack = 0;
			break;
		case UDP_CLIENT_STATE_PARTOPEN:
			dgram_conn->count_s_pay = 2;
			dgram_conn->count_s_ack = 1;
			break;
		case UDP_CLIENT_STATE_OPEN:
			dgram_conn->count_s_pay++;
			dgram_conn->count_s_ack++;
			break;
		case UDP_CLIENT_STATE_CLOSING:
			break;
		case UDP_CLIENT_STATE_CLOSED:
			break;
		}
	}

	return ret;
}
Пример #4
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);
	}
}
Пример #5
0
void v_print_send_packet(struct vContext *C)
{
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct VPacket *s_packet = CTX_s_packet(C);

	if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
		printf("%c[%d;%dm", 27, 1, 32);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Send packet: ");
		v_print_log_simple(VRS_PRINT_DEBUG_MSG, "Socket: %d, ", io_ctx->sockfd);
		v_print_addr_port(VRS_PRINT_DEBUG_MSG, &io_ctx->peer_addr);
		v_print_packet_header(VRS_PRINT_DEBUG_MSG, s_packet);
		v_print_log(VRS_PRINT_DEBUG_MSG, "Shift: %d -> Window: %d\n", dgram_conn->rwin_host_scale, (unsigned int)s_packet->header.window << dgram_conn->rwin_host_scale);
		v_print_packet_sys_cmds(VRS_PRINT_DEBUG_MSG, s_packet);
		printf("%c[%dm", 27, 0);
	}
}
Пример #6
0
void vc_CLOSING_init_send_packet(struct vContext *C)
{
	struct VDgramConn *dgram_conn = CTX_current_dgram_conn(C);
	struct VPacket *s_packet = CTX_s_packet(C);

	/* Verse packet header */
	s_packet->header.version = 1;
	s_packet->header.flags = PAY_FLAG | FIN_FLAG;
	s_packet->header.window = dgram_conn->rwin_host >> dgram_conn->rwin_host_scale;
	s_packet->header.payload_id = dgram_conn->host_id + dgram_conn->count_s_pay;
	s_packet->header.ack_nak_id = dgram_conn->count_s_ack;
	s_packet->header.ank_id = 0;

	/* System commands */
	/* TODO: send ack and nak commands */
	s_packet->sys_cmd[0].cmd.id = CMD_RESERVED_ID;
}
Пример #7
0
/**
 * \brief This function send packets in OPEN and CLOSEREQ state.
 */
int send_packet_in_OPEN_CLOSEREQ_state(struct vContext *C)
{
	struct VDgramConn *vconn = CTX_current_dgram_conn(C);
	struct IO_CTX *io_ctx = CTX_io_ctx(C);
	struct VSession *vsession = CTX_current_session(C);
	struct VPacket *s_packet = CTX_s_packet(C);
	struct VSent_Packet *sent_packet = NULL;
	unsigned short buffer_pos = 0;
	struct timeval tv;
	int ret, keep_alive_packet = -1, full_packet = 0;
	int error_num;
	uint16 swin, prio_win, sent_size = 0;
	uint32 rwin;
	int cmd_rank = 0;

	/* Verse packet header */
	s_packet->header.version = 1;

	/* Clear header flags */
	s_packet->header.flags = 0;

	/* Check if it is necessary to send payload packet */
	ret = check_pay_flag(C);
	if(ret!=0) {
		s_packet->header.flags |= PAY_FLAG;
		if(ret==2) {
			keep_alive_packet = 1;
		}
	}

	/* When server is in CLOSEREQ state, then FIN flag should be set up */
	if(vconn->host_state == UDP_SERVER_STATE_CLOSEREQ) {
		s_packet->header.flags |= FIN_FLAG;
	}

	/* Check if it is necessary to send acknowledgment of received payload
	 * packet */
	ret = check_ack_nak_flag(C);
	if(ret==1) {
		s_packet->header.flags |= ACK_FLAG;

		/* Update last acknowledged Payload packet */
		vconn->last_acked_pay = vconn->last_r_pay;

		/* Add ACK and NAK commands from the list of ACK and NAK commands to the
		 * packet (only max count of ACK and NAK commands could be added to
		 * the packet) */
		for(cmd_rank = 0;
				cmd_rank < vconn->ack_nak.count &&
				cmd_rank < MAX_SYSTEM_COMMAND_COUNT;
				cmd_rank++)
		{
			s_packet->sys_cmd[cmd_rank].ack_cmd.id = vconn->ack_nak.cmds[cmd_rank].id;
			s_packet->sys_cmd[cmd_rank].ack_cmd.pay_id = vconn->ack_nak.cmds[cmd_rank].pay_id;
		}
		s_packet->sys_cmd[cmd_rank].cmd.id = CMD_RESERVED_ID;

	}

	/* If there is no need to send Payload or AckNak packet, then cancel
	 * sending of packet */
	if(! ((s_packet->header.flags & PAY_FLAG) ||
			(s_packet->header.flags & ACK_FLAG)) ) return SEND_PACKET_CANCELED;

	s_packet->header.flags |= ANK_FLAG;
	s_packet->header.ank_id = vconn->ank_id;

	/* Compute current windows for flow control and congestion control */
	set_host_rwin(C);
	set_host_cwin(C);

	/* Set window of flow control that will sent to receiver */
	rwin = vconn->rwin_host >> vconn->rwin_host_scale;
	s_packet->header.window = (unsigned short)(rwin > 0xFFFF) ? 0xFFFF : rwin;
	/*printf("\t---real window: %d---\n", s_packet->header.window);*/

	/* Compute how many data could be sent to not congest receiver */
	rwin = vconn->rwin_peer - vconn->sent_size;

	/* Select smallest window for sending (congestion control window or flow control window)*/
	swin = (vconn->cwin < rwin) ? vconn->cwin : rwin;

	/* Set up Payload ID, when there is need to send payload packet */
	if(s_packet->header.flags & PAY_FLAG)
		s_packet->header.payload_id = vconn->host_id + vconn->count_s_pay;
	else
		s_packet->header.payload_id  = 0;

	/* Set up AckNak ID, when there are some ACK or NAK command in the packet */
	if(s_packet->header.flags & ACK_FLAG)
		s_packet->header.ack_nak_id = vconn->count_s_ack;
	else
		s_packet->header.ack_nak_id = 0;

	/* 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_packet->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_packet->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;
		}
	}

	v_print_send_packet(C);

	/* Fill buffer */
	buffer_pos += v_pack_packet_header(s_packet, &io_ctx->buf[buffer_pos]);
	buffer_pos += v_pack_dgram_system_commands(s_packet, &io_ctx->buf[buffer_pos]);

	/* When this is not pure keep alive packet */
	if(s_packet->header.flags & PAY_FLAG) {

		sent_packet = v_packet_history_add_packet(&vconn->packet_history, s_packet->header.payload_id);

		assert(sent_packet != NULL);

		if(keep_alive_packet != 1) {
			real32 prio_sum_high, prio_sum_low, r_prio;
			uint32 prio_count;
			int16 prio, max_prio, min_prio;
			uint16 tot_cmd_size;

			/* Print outgoing command with green color */
			if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
				printf("%c[%d;%dm", 27, 1, 32);
			}

			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--)
			{
				/* TODO: Add better check here */
				if(prio <= VRS_DEFAULT_PRIORITY && buffer_pos >= vconn->io_ctx.mtu) {
					break;
				}

				prio_count = v_out_queue_get_count_prio(vsession->out_queue, prio);

				if(prio_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_count, r_prio, prio_win);

					/* Get total size of commands that were stored in queue (sent_size) */
					tot_cmd_size = 0;
					/* Pack commands from queues with high priority to the buffer */
					buffer_pos = pack_prio_queue(C, sent_packet, buffer_pos, prio, prio_win, &tot_cmd_size);
					sent_size += tot_cmd_size;
				}
			}

			/* Use default color for output */
			if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
				printf("%c[%dm", 27, 0);
			}
		} else {
			if(is_log_level(VRS_PRINT_DEBUG_MSG)) {
				printf("%c[%d;%dm", 27, 1, 32);
				v_print_log(VRS_PRINT_DEBUG_MSG, "Keep alive packet\n");
				printf("%c[%dm", 27, 0);
			}
		}
	}

	/* Update sent_size */
	vconn->sent_size += sent_size;

	io_ctx->buf_size = buffer_pos;

	/* Send buffer */
	ret = v_send_packet(io_ctx, &error_num);

	if(ret==SEND_PACKET_SUCCESS) {
		gettimeofday(&tv, NULL);

		/* Update time of sending last payload packet */
		if(s_packet->header.flags & PAY_FLAG) {
			vconn->tv_pay_send.tv_sec = tv.tv_sec;
			vconn->tv_pay_send.tv_usec = tv.tv_usec;
			/* Store time of sending packet in history of sent packets. It is
			 * used for computing RTT and SRTT */
			if(sent_packet != NULL) {
				sent_packet->tv.tv_sec = tv.tv_sec;
				sent_packet->tv.tv_usec = tv.tv_usec;
			}
		}

		/* Update time of sending last acknowledgment packet */
		if(s_packet->header.flags & ACK_FLAG) {
			vconn->tv_ack_send.tv_sec = tv.tv_sec;
			vconn->tv_ack_send.tv_usec = tv.tv_usec;
		}

		/* Update counter of sent packets */
		if(s_packet->header.flags & PAY_FLAG) vconn->count_s_pay++;
		if(s_packet->header.flags & ACK_FLAG) vconn->count_s_ack++;

		/* If the packet was sent full and there are some pending data to send
		 * then modify returned value*/
		if(full_packet == 1) {
			ret = SEND_PACKET_FULL;
		}
	} else {
		/* When packet wasn't sent, then remove this packet from history */
		if(sent_packet != NULL) {
			v_packet_history_rem_packet(C, s_packet->header.payload_id);
		}
	}

	/*v_print_packet_history(&vconn->packet_history);*/

	return ret;
}