/** * \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; }
END_TEST /** * \brief Test of packing and unpacking negotiate command with string value. */ START_TEST ( test_pack_unpack_negotiate_cmd_long_string_value ) { union VSystemCommands send_sys_cmd[1], recv_sys_cmd[1]; uint8 cmd_op_code = CMD_CHANGE_R_ID; uint8 ftr_op_code = FTR_CLIENT_NAME; char string[470] = "Lorem ipsum dolor sit amet, consectetuer adipiscing " "elit. Ut enim ad minim veniam, quis nostrud exercitation ullamco " "laboris nisi ut aliquip ex ea commodo consequat. Nullam at arcu " "a est sollicitudin euismod. Fusce consectetuer risus a nunc. " "Cras pede libero, dapibus nec, pretium sit amet, tempor quis. " "Etiam dictum tincidunt diam. Nullam lectus justo, vulputate " "eget mollis sed, tempor sed magna. Vivamus porttitor turpis ac " "leo. Suspendisse sagittis ultrices augue."; char buffer[512]; int ret, buffer_pos = 0, cmd_len; ret = v_add_negotiate_cmd(send_sys_cmd, 0, cmd_op_code, ftr_op_code, string, NULL); fail_unless( ret == 1, "Adding negotiate command failed"); /* Pack negotiate command */ buffer_pos += v_raw_pack_negotiate_cmd(buffer, &send_sys_cmd[0].negotiate_cmd); fail_unless( buffer_pos == 261, "Length of packed cmd: %d != %d", buffer_pos, 8); /* Unpack system command */ cmd_len = v_raw_unpack_negotiate_cmd(buffer, buffer_pos, &recv_sys_cmd[0].negotiate_cmd); fail_unless( cmd_len == buffer_pos, "Length of packed and unpacked cmd: %d != %d", buffer_pos, cmd_len); fail_unless( recv_sys_cmd->negotiate_cmd.id == cmd_op_code, "Negotiate command OpCode: %d != %d", recv_sys_cmd->negotiate_cmd.id, cmd_op_code); fail_unless( recv_sys_cmd->negotiate_cmd.feature == ftr_op_code, "Negotiate command feature: %d != %d", recv_sys_cmd->negotiate_cmd.feature, ftr_op_code); fail_unless( recv_sys_cmd->negotiate_cmd.count == 1, "Negotiate command feature count: %d != %d", recv_sys_cmd->negotiate_cmd.count, 1); fail_unless( recv_sys_cmd->negotiate_cmd.value[0].string8.length == 255, "Negotiate command value (string length): %d != %d", recv_sys_cmd->negotiate_cmd.value[0].string8.length, 255); /* Make original string 255 bytes long */ string[255] = '\0'; fail_unless( strncmp((char*)recv_sys_cmd->negotiate_cmd.value[0].string8.str, string, 255) == 0, "Negotiate command value (string): %s != %s", recv_sys_cmd->negotiate_cmd.value[0].string8.str, string); }
END_TEST /** * \brief Test of packing and unpacking negotiate command with * two string values. */ START_TEST ( test_pack_unpack_negotiate_cmd_multiple_string_values ) { union VSystemCommands send_sys_cmd[1], recv_sys_cmd[1]; uint8 cmd_op_code = CMD_CONFIRM_R_ID; uint8 ftr_op_code = FTR_CLIENT_NAME; char string_val0[5] = {'a', 'h', 'o', 'y', '\0'}; char string_val1[4] = {'h', 'e', 'y', '\0'}; char buffer[255]; int ret, buffer_pos = 0, cmd_len; ret = v_add_negotiate_cmd(send_sys_cmd, 0, cmd_op_code, ftr_op_code, string_val0, string_val1, NULL); fail_unless( ret == 1, "Adding negotiate command failed"); /* Pack negotiate command */ buffer_pos += v_raw_pack_negotiate_cmd(buffer, &send_sys_cmd[0].negotiate_cmd); fail_unless( buffer_pos == 12, "Length of packed cmd: %d != %d", buffer_pos, 12); /* Unpack system command */ cmd_len = v_raw_unpack_negotiate_cmd(buffer, buffer_pos, &recv_sys_cmd[0].negotiate_cmd); fail_unless( cmd_len == buffer_pos, "Length of packed and unpacked cmd: %d != %d", buffer_pos, cmd_len); fail_unless( recv_sys_cmd->negotiate_cmd.id == cmd_op_code, "Negotiate command OpCode: %d != %d", recv_sys_cmd->negotiate_cmd.id, cmd_op_code); fail_unless( recv_sys_cmd->negotiate_cmd.feature == ftr_op_code, "Negotiate command feature: %d != %d", recv_sys_cmd->negotiate_cmd.feature, ftr_op_code); fail_unless( recv_sys_cmd->negotiate_cmd.count == 2, "Negotiate command feature count: %d != %d", recv_sys_cmd->negotiate_cmd.count, 2); fail_unless( recv_sys_cmd->negotiate_cmd.value[0].string8.length == 4, "Negotiate command value (string length): %d != %d", recv_sys_cmd->negotiate_cmd.value[0].string8.length, 4); fail_unless( strcmp((char*)recv_sys_cmd->negotiate_cmd.value[0].string8.str, "ahoy") == 0, "Negotiate command value (string): %s != ahoy", recv_sys_cmd->negotiate_cmd.value[0].string8.str); fail_unless( recv_sys_cmd->negotiate_cmd.value[1].string8.length == 3, "Negotiate command value (string length): %d != %d", recv_sys_cmd->negotiate_cmd.value[1].string8.length, 3); fail_unless( strcmp((char*)recv_sys_cmd->negotiate_cmd.value[1].string8.str, "hey") == 0, "Negotiate command value (string): %s != hey", recv_sys_cmd->negotiate_cmd.value[1].string8.str); }
END_TEST /** * \brief Test simple adding negotiate command to the list of system commands */ START_TEST ( test_print_negotiate_cmds ) { union VSystemCommands sys_cmd[1]; uint8 cmd_op_code; uint8 ftr_op_code; uint8 uint8_value = 1; real32 real32_value = 60.0f; char string[5] = {'a', 'h', 'o', 'y', '\0'}; int ret; cmd_op_code = CMD_CHANGE_R_ID; ftr_op_code = FTR_FC_ID; ret = v_add_negotiate_cmd(sys_cmd, 0, cmd_op_code, ftr_op_code, &uint8_value, NULL); fail_unless( ret == 1, "Adding negotiate command failed"); v_print_negotiate_cmd(VRS_PRINT_NONE, &sys_cmd->negotiate_cmd); cmd_op_code = CMD_CONFIRM_L_ID; ftr_op_code = FTR_CC_ID; ret = v_add_negotiate_cmd(sys_cmd, 0, cmd_op_code, ftr_op_code, &uint8_value, NULL); fail_unless( ret == 1, "Adding negotiate command failed"); v_print_negotiate_cmd(VRS_PRINT_NONE, &sys_cmd->negotiate_cmd); cmd_op_code = CMD_CONFIRM_R_ID; ftr_op_code = FTR_HOST_URL; ret = v_add_negotiate_cmd(sys_cmd, 0, cmd_op_code, ftr_op_code, &string, NULL); fail_unless( ret == 1, "Adding negotiate command failed"); v_print_negotiate_cmd(VRS_PRINT_NONE, &sys_cmd->negotiate_cmd); cmd_op_code = CMD_CHANGE_L_ID; ftr_op_code = FTR_TOKEN; ret = v_add_negotiate_cmd(sys_cmd, 0, cmd_op_code, ftr_op_code, &string, NULL); fail_unless( ret == 1, "Adding negotiate command failed"); v_print_negotiate_cmd(VRS_PRINT_NONE, &sys_cmd->negotiate_cmd); cmd_op_code = CMD_CONFIRM_L_ID; ftr_op_code = FTR_DED; ret = v_add_negotiate_cmd(sys_cmd, 0, cmd_op_code, ftr_op_code, &string, NULL); fail_unless( ret == 1, "Adding negotiate command failed"); v_print_negotiate_cmd(VRS_PRINT_NONE, &sys_cmd->negotiate_cmd); cmd_op_code = CMD_CONFIRM_L_ID; ftr_op_code = FTR_RWIN_SCALE; ret = v_add_negotiate_cmd(sys_cmd, 0, cmd_op_code, ftr_op_code, &uint8_value, NULL); fail_unless( ret == 1, "Adding negotiate command failed"); v_print_negotiate_cmd(VRS_PRINT_NONE, &sys_cmd->negotiate_cmd); cmd_op_code = CMD_CONFIRM_L_ID; ftr_op_code = FTR_FPS; ret = v_add_negotiate_cmd(sys_cmd, 0, cmd_op_code, ftr_op_code, &real32_value, NULL); fail_unless( ret == 1, "Adding negotiate command failed"); v_print_negotiate_cmd(VRS_PRINT_NONE, &sys_cmd->negotiate_cmd); cmd_op_code = CMD_CONFIRM_L_ID; ftr_op_code = FTR_CMD_COMPRESS; ret = v_add_negotiate_cmd(sys_cmd, 0, cmd_op_code, ftr_op_code, &uint8_value, NULL); fail_unless( ret == 1, "Adding negotiate command failed"); v_print_negotiate_cmd(VRS_PRINT_NONE, &sys_cmd->negotiate_cmd); cmd_op_code = CMD_CONFIRM_L_ID; ftr_op_code = FTR_CLIENT_NAME; ret = v_add_negotiate_cmd(sys_cmd, 0, cmd_op_code, ftr_op_code, &string, NULL); fail_unless( ret == 1, "Adding negotiate command failed"); v_print_negotiate_cmd(VRS_PRINT_NONE, &sys_cmd->negotiate_cmd); cmd_op_code = CMD_CONFIRM_L_ID; ftr_op_code = FTR_CLIENT_VERSION; ret = v_add_negotiate_cmd(sys_cmd, 0, cmd_op_code, ftr_op_code, &string, NULL); fail_unless( ret == 1, "Adding negotiate command failed"); v_print_negotiate_cmd(VRS_PRINT_NONE, &sys_cmd->negotiate_cmd); }