int rpc_recv_pdu_fragment(rdpRpc* rpc) { int status; int headerLength; int bytesRead = 0; rpcconn_hdr_t* header; WaitForSingleObject(rpc->VirtualConnection->DefaultInChannel->Mutex, INFINITE); status = rpc_recv_pdu_header(rpc, rpc->FragBuffer); if (status < 1) { printf("rpc_recv_pdu_header: error reading header\n"); return status; } headerLength = status; header = (rpcconn_hdr_t*) rpc->FragBuffer; bytesRead += status; if (header->common.frag_length > rpc->FragBufferSize) { rpc->FragBufferSize = header->common.frag_length; rpc->FragBuffer = (BYTE*) realloc(rpc->FragBuffer, rpc->FragBufferSize); header = (rpcconn_hdr_t*) rpc->FragBuffer; } while (bytesRead < header->common.frag_length) { status = rpc_out_read(rpc, &rpc->FragBuffer[bytesRead], header->common.frag_length - bytesRead); if (status < 0) { printf("rpc_recv_pdu: error reading fragment\n"); return status; } bytesRead += status; } ReleaseMutex(rpc->VirtualConnection->DefaultInChannel->Mutex); if (header->common.ptype == PTYPE_RTS) /* RTS PDU */ { 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, rpc->FragBuffer, header->common.frag_length); return rpc_recv_pdu_fragment(rpc); } else if (header->common.ptype == PTYPE_FAULT) { rpc_recv_fault_pdu(header); return -1; } rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header->common.frag_length; rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -= header->common.frag_length; #if 0 printf("BytesReceived: %d ReceiverAvailableWindow: %d ReceiveWindow: %d\n", rpc->VirtualConnection->DefaultOutChannel->BytesReceived, rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow, rpc->ReceiveWindow); #endif if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow < (rpc->ReceiveWindow / 2)) { printf("Sending Flow Control Ack PDU\n"); rts_send_flow_control_ack_pdu(rpc); } #ifdef WITH_DEBUG_RPC rpc_pdu_header_print((rpcconn_hdr_t*) header); printf("rpc_recv_pdu_fragment: length: %d\n", header->common.frag_length); freerdp_hexdump(rpc->FragBuffer, header->common.frag_length); printf("\n"); #endif return header->common.frag_length; }
int rpc_client_on_fragment_received_event(rdpRpc* rpc) { BYTE* buffer; UINT32 StubOffset; UINT32 StubLength; wStream* fragment; rpcconn_hdr_t* header; freerdp* instance; instance = (freerdp*) rpc->transport->settings->instance; if (!rpc->client->pdu) rpc->client->pdu = rpc_client_receive_pool_take(rpc); fragment = Queue_Dequeue(rpc->client->FragmentQueue); buffer = (BYTE*) Stream_Buffer(fragment); header = (rpcconn_hdr_t*) Stream_Buffer(fragment); if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED) { rpc->client->pdu->Flags = 0; rpc->client->pdu->CallId = header->common.call_id; Stream_EnsureCapacity(rpc->client->pdu->s, Stream_Length(fragment)); Stream_Write(rpc->client->pdu->s, buffer, Stream_Length(fragment)); Stream_Length(rpc->client->pdu->s) = Stream_GetPosition(rpc->client->pdu->s); rpc_client_fragment_pool_return(rpc, fragment); Queue_Enqueue(rpc->client->ReceiveQueue, rpc->client->pdu); SetEvent(rpc->transport->ReceiveEvent); rpc->client->pdu = NULL; return 0; } if (header->common.ptype == PTYPE_RTS) { if (rpc->VirtualConnection->State >= VIRTUAL_CONNECTION_STATE_OPENED) { //fprintf(stderr, "Receiving Out-of-Sequence RTS PDU\n"); rts_recv_out_of_sequence_pdu(rpc, buffer, header->common.frag_length); rpc_client_fragment_pool_return(rpc, fragment); } else { fprintf(stderr, "warning: unhandled RTS PDU\n"); } return 0; } else if (header->common.ptype == PTYPE_FAULT) { rpc_recv_fault_pdu(header); return -1; } if (header->common.ptype != PTYPE_RESPONSE) { fprintf(stderr, "Unexpected RPC PDU type: %d\n", header->common.ptype); return -1; } rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header->common.frag_length; rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -= header->common.frag_length; if (!rpc_get_stub_data_info(rpc, buffer, &StubOffset, &StubLength)) { fprintf(stderr, "rpc_recv_pdu_fragment: expected stub\n"); return -1; } if (StubLength == 4) { //fprintf(stderr, "Ignoring TsProxySendToServer Response\n"); printf("Got stub length 4 with flags %d and callid %d\n", header->common.pfc_flags, header->common.call_id); /* received a disconnect request from the server? */ if ((header->common.call_id == rpc->PipeCallId) && (header->common.pfc_flags & PFC_LAST_FRAG)) { TerminateEventArgs e; instance->context->rdp->disconnect = TRUE; rpc->transport->tsg->state = TSG_STATE_TUNNEL_CLOSE_PENDING; EventArgsInit(&e, "freerdp"); e.code = 0; PubSub_OnTerminate(instance->context->pubSub, instance->context, &e); } rpc_client_fragment_pool_return(rpc, fragment); return 0; } Stream_EnsureCapacity(rpc->client->pdu->s, header->response.alloc_hint); buffer = (BYTE*) Stream_Buffer(fragment); header = (rpcconn_hdr_t*) Stream_Buffer(fragment); if (rpc->StubFragCount == 0) rpc->StubCallId = header->common.call_id; if (rpc->StubCallId != header->common.call_id) { fprintf(stderr, "invalid call_id: actual: %d, expected: %d, frag_count: %d\n", rpc->StubCallId, header->common.call_id, rpc->StubFragCount); } Stream_Write(rpc->client->pdu->s, &buffer[StubOffset], StubLength); rpc->StubFragCount++; rpc_client_fragment_pool_return(rpc, fragment); if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow < (rpc->ReceiveWindow / 2)) { //fprintf(stderr, "Sending Flow Control Ack PDU\n"); rts_send_flow_control_ack_pdu(rpc); } /** * If alloc_hint is set to a nonzero value and a request or a response is fragmented into multiple * PDUs, implementations of these extensions SHOULD set the alloc_hint field in every PDU to be the * combined stub data length of all remaining fragment PDUs. */ if (header->response.alloc_hint == StubLength) { rpc->client->pdu->Flags = RPC_PDU_FLAG_STUB; rpc->client->pdu->CallId = rpc->StubCallId; Stream_Length(rpc->client->pdu->s) = Stream_GetPosition(rpc->client->pdu->s); rpc->StubFragCount = 0; rpc->StubCallId = 0; Queue_Enqueue(rpc->client->ReceiveQueue, rpc->client->pdu); rpc->client->pdu = NULL; return 0; } return 0; }
int rpc_client_on_fragment_received_event(rdpRpc* rpc) { BYTE* buffer; UINT32 StubOffset; UINT32 StubLength; wStream* fragment; rpcconn_hdr_t* header; if (!rpc->client->pdu) rpc->client->pdu = rpc_client_receive_pool_take(rpc); fragment = Queue_Dequeue(rpc->client->FragmentQueue); buffer = (BYTE*) Stream_Buffer(fragment); header = (rpcconn_hdr_t*) Stream_Buffer(fragment); if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED) { rpc->client->pdu->Flags = 0; rpc->client->pdu->CallId = header->common.call_id; Stream_EnsureCapacity(rpc->client->pdu->s, Stream_Length(fragment)); Stream_Write(rpc->client->pdu->s, buffer, Stream_Length(fragment)); Stream_Length(rpc->client->pdu->s) = Stream_Position(rpc->client->pdu->s); rpc_client_fragment_pool_return(rpc, fragment); Queue_Enqueue(rpc->client->ReceiveQueue, rpc->client->pdu); SetEvent(rpc->transport->ReceiveEvent); rpc->client->pdu = NULL; return 0; } if (header->common.ptype == PTYPE_RTS) { if (rpc->VirtualConnection->State >= VIRTUAL_CONNECTION_STATE_OPENED) { //printf("Receiving Out-of-Sequence RTS PDU\n"); rts_recv_out_of_sequence_pdu(rpc, buffer, header->common.frag_length); rpc_client_fragment_pool_return(rpc, fragment); } else { printf("warning: unhandled RTS PDU\n"); } return 0; } else if (header->common.ptype == PTYPE_FAULT) { rpc_recv_fault_pdu(header); return -1; } if (header->common.ptype != PTYPE_RESPONSE) { printf("Unexpected RPC PDU type: %d\n", header->common.ptype); return -1; } rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header->common.frag_length; rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -= header->common.frag_length; if (!rpc_get_stub_data_info(rpc, buffer, &StubOffset, &StubLength)) { printf("rpc_recv_pdu_fragment: expected stub\n"); return -1; } if (StubLength == 4) { //printf("Ignoring TsProxySendToServer Response\n"); rpc_client_fragment_pool_return(rpc, fragment); return 0; } Stream_EnsureCapacity(rpc->client->pdu->s, header->response.alloc_hint); buffer = (BYTE*) Stream_Buffer(fragment); header = (rpcconn_hdr_t*) Stream_Buffer(fragment); if (rpc->StubFragCount == 0) rpc->StubCallId = header->common.call_id; if (rpc->StubCallId != header->common.call_id) { printf("invalid call_id: actual: %d, expected: %d, frag_count: %d\n", rpc->StubCallId, header->common.call_id, rpc->StubFragCount); } Stream_Write(rpc->client->pdu->s, &buffer[StubOffset], StubLength); rpc->StubFragCount++; rpc_client_fragment_pool_return(rpc, fragment); if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow < (rpc->ReceiveWindow / 2)) { //printf("Sending Flow Control Ack PDU\n"); rts_send_flow_control_ack_pdu(rpc); } /** * If alloc_hint is set to a nonzero value and a request or a response is fragmented into multiple * PDUs, implementations of these extensions SHOULD set the alloc_hint field in every PDU to be the * combined stub data length of all remaining fragment PDUs. */ if (header->response.alloc_hint == StubLength) { rpc->client->pdu->Flags = RPC_PDU_FLAG_STUB; rpc->client->pdu->CallId = rpc->StubCallId; Stream_Length(rpc->client->pdu->s) = Stream_Position(rpc->client->pdu->s); rpc->StubFragCount = 0; rpc->StubCallId = 0; Queue_Enqueue(rpc->client->ReceiveQueue, rpc->client->pdu); rpc->client->pdu = NULL; return 0; } return 0; }