libfreerdp-core: started handling flow control, can get further with TSG
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Sat, 17 Nov 2012 02:17:04 +0000 (21:17 -0500)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Sat, 17 Nov 2012 02:17:04 +0000 (21:17 -0500)
libfreerdp/core/rpc.c
libfreerdp/core/rts.c
libfreerdp/core/rts.h

index 5df1923..1eabf71 100644 (file)
@@ -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)
index 41aa33f..154a0c1 100644 (file)
@@ -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;
+}
index 8a38819..2cf6fee 100644 (file)
@@ -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