diff --git a/libfreerdp/core/rpc.c b/libfreerdp/core/rpc.c index 5df1923a2..1eabf71e7 100644 --- a/libfreerdp/core/rpc.c +++ b/libfreerdp/core/rpc.c @@ -458,7 +458,10 @@ int rpc_in_write(rdpRpc* rpc, BYTE* data, int length) status = tls_write_all(rpc->TlsIn, data, length); if (status > 0) + { rpc->VirtualConnection->DefaultInChannel->BytesSent += status; + rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow -= status; + } return status; } @@ -812,18 +815,31 @@ int rpc_recv_pdu(rdpRpc* rpc) if (header->common.ptype == PTYPE_RTS) /* RTS PDU */ { - return header->common.frag_length; + if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED) + return header->common.frag_length; + + printf("Receiving Out-of-Sequence RTS PDU\n"); + rts_recv_out_of_sequence_pdu(rpc); + return rpc_recv_pdu(rpc); } else if (header->common.ptype == PTYPE_FAULT) { rpc_recv_fault_pdu(header); return -1; } - else + + rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header->common.frag_length; + rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -= header->common.frag_length; + + /*printf("BytesReceived: %d ReceiverAvailableWindow: %d ReceiveWindow: %d\n", + rpc->VirtualConnection->DefaultOutChannel->BytesReceived, + rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow, + rpc->ReceiveWindow);*/ + + if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow < (rpc->ReceiveWindow / 2)) { - /* RTS PDUs are not subject to flow control */ - rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header->common.frag_length; - rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -= header->common.frag_length; + printf("Sending Flow Control Ack PDU\n"); + rts_send_flow_control_ack_pdu(rpc); } #ifdef WITH_DEBUG_RPC @@ -986,6 +1002,7 @@ void rpc_client_virtual_connection_init(rdpRpc* rpc, RpcVirtualConnection* conne connection->DefaultOutChannel->ReceiverAvailableWindow = rpc->ReceiveWindow; connection->DefaultOutChannel->ReceiveWindow = rpc->ReceiveWindow; connection->DefaultOutChannel->ReceiveWindowSize = rpc->ReceiveWindow; + connection->DefaultOutChannel->AvailableWindowAdvertised = rpc->ReceiveWindow; } RpcVirtualConnection* rpc_client_virtual_connection_new(rdpRpc* rpc) diff --git a/libfreerdp/core/rts.c b/libfreerdp/core/rts.c index 41aa33f7b..154a0c149 100644 --- a/libfreerdp/core/rts.c +++ b/libfreerdp/core/rts.c @@ -840,9 +840,12 @@ int rts_send_flow_control_ack_pdu(rdpRpc* rpc) DEBUG_RPC("Sending FlowControlAck RTS PDU"); BytesReceived = rpc->VirtualConnection->DefaultOutChannel->BytesReceived; - AvailableWindow = rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow; + AvailableWindow = rpc->VirtualConnection->DefaultOutChannel->AvailableWindowAdvertised; ChannelCookie = (BYTE*) &(rpc->VirtualConnection->DefaultOutChannelCookie); + rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow = + rpc->VirtualConnection->DefaultOutChannel->AvailableWindowAdvertised; + buffer = (BYTE*) malloc(header.frag_length); CopyMemory(buffer, ((BYTE*) &header), 20); /* RTS Header (20 bytes) */ @@ -1192,6 +1195,74 @@ BOOL rts_match_pdu_signature(rdpRpc* rpc, RtsPduSignature* signature, rpcconn_rt return TRUE; } +int rts_extract_pdu_signature(rdpRpc* rpc, RtsPduSignature* signature, rpcconn_rts_hdr_t* rts) +{ + int i; + int status; + BYTE* buffer; + UINT32 length; + UINT32 offset; + UINT32 CommandType; + UINT32 CommandLength; + + signature->Flags = rts->Flags; + signature->NumberOfCommands = rts->NumberOfCommands; + + buffer = (BYTE*) rts; + offset = RTS_PDU_HEADER_LENGTH; + length = rts->frag_length - offset; + + for (i = 0; i < rts->NumberOfCommands; i++) + { + CommandType = *((UINT32*) &buffer[offset]); /* CommandType (4 bytes) */ + offset += 4; + + signature->CommandTypes[i] = CommandType; + + status = rts_command_length(rpc, CommandType, &buffer[offset], length); + + if (status < 0) + return FALSE; + + CommandLength = (UINT32) status; + offset += CommandLength; + + length = rts->frag_length - offset; + } + + return 0; +} + +int rts_print_pdu_signature(rdpRpc* rpc, RtsPduSignature* signature) +{ + int i, j; + RtsPduSignature* pSignature; + + printf("RTS PDU Signature: Flags: 0x%04X NumberOfCommands: %d\n", + signature->Flags, signature->NumberOfCommands); + + for (i = 0; RTS_PDU_SIGNATURE_TABLE[i].SignatureId != 0; i++) + { + pSignature = RTS_PDU_SIGNATURE_TABLE[i].Signature; + + if (signature->Flags == pSignature->Flags) + { + if (signature->NumberOfCommands == pSignature->NumberOfCommands) + { + for (j = 0; j < signature->NumberOfCommands; j++) + { + if (signature->CommandTypes[j] != pSignature->CommandTypes[j]) + continue; + } + + printf("Identified %s RTS PDU\n", RTS_PDU_SIGNATURE_TABLE[i].PduName); + } + } + } + + return 0; +} + int rts_recv_pdu_commands(rdpRpc* rpc, rpcconn_rts_hdr_t* rts) { int i; @@ -1317,3 +1388,16 @@ int rts_recv_pdu(rdpRpc* rpc) return status; } + +int rts_recv_out_of_sequence_pdu(rdpRpc* rpc) +{ + rpcconn_rts_hdr_t* rts; + RtsPduSignature signature; + + rts = (rpcconn_rts_hdr_t*) rpc->buffer; + + rts_extract_pdu_signature(rpc, &signature, rts); + rts_print_pdu_signature(rpc, &signature); + + return 0; +} diff --git a/libfreerdp/core/rts.h b/libfreerdp/core/rts.h index 8a38819e0..2cf6feef8 100644 --- a/libfreerdp/core/rts.h +++ b/libfreerdp/core/rts.h @@ -222,6 +222,7 @@ int rts_send_flow_control_ack_pdu(rdpRpc* rpc); int rts_send_ping_pdu(rdpRpc* rpc); int rts_recv_pdu(rdpRpc* rpc); +int rts_recv_out_of_sequence_pdu(rdpRpc* rpc); #ifdef WITH_DEBUG_TSG #define WITH_DEBUG_RTS