int rpc_client_on_read_event(rdpRpc* rpc) { int position; int status = -1; rpcconn_common_hdr_t* header; if (!rpc->client->RecvFrag) rpc->client->RecvFrag = rpc_client_fragment_pool_take(rpc); position = Stream_Position(rpc->client->RecvFrag); if (Stream_Position(rpc->client->RecvFrag) < RPC_COMMON_FIELDS_LENGTH) { status = rpc_out_read(rpc, Stream_Pointer(rpc->client->RecvFrag), RPC_COMMON_FIELDS_LENGTH - Stream_Position(rpc->client->RecvFrag)); if (status < 0) { printf("rpc_client_frag_read: error reading header\n"); return -1; } Stream_Seek(rpc->client->RecvFrag, status); } if (Stream_Position(rpc->client->RecvFrag) >= RPC_COMMON_FIELDS_LENGTH) { header = (rpcconn_common_hdr_t*) Stream_Buffer(rpc->client->RecvFrag); if (header->frag_length > rpc->max_recv_frag) { printf("rpc_client_frag_read: invalid fragment size: %d (max: %d)\n", header->frag_length, rpc->max_recv_frag); winpr_HexDump(Stream_Buffer(rpc->client->RecvFrag), Stream_Position(rpc->client->RecvFrag)); return -1; } if (Stream_Position(rpc->client->RecvFrag) < header->frag_length) { status = rpc_out_read(rpc, Stream_Pointer(rpc->client->RecvFrag), header->frag_length - Stream_Position(rpc->client->RecvFrag)); if (status < 0) { printf("rpc_client_frag_read: error reading fragment body\n"); return -1; } Stream_Seek(rpc->client->RecvFrag, status); } } else { return status; } if (status < 0) return -1; status = Stream_Position(rpc->client->RecvFrag) - position; if (Stream_Position(rpc->client->RecvFrag) >= header->frag_length) { /* complete fragment received */ Stream_Length(rpc->client->RecvFrag) = Stream_Position(rpc->client->RecvFrag); Stream_SetPosition(rpc->client->RecvFrag, 0); Queue_Enqueue(rpc->client->FragmentQueue, rpc->client->RecvFrag); rpc->client->RecvFrag = NULL; rpc_client_on_fragment_received_event(rpc); } return status; }
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; }
DWORD TsProxySendToServer(handle_t IDL_handle, byte pRpcMessage[], UINT32 count, UINT32* lengths) { wStream* s; int status; rdpTsg* tsg; BYTE* buffer; UINT32 length; byte* buffer1 = NULL; byte* buffer2 = NULL; byte* buffer3 = NULL; UINT32 buffer1Length; UINT32 buffer2Length; UINT32 buffer3Length; UINT32 numBuffers = 0; UINT32 totalDataBytes = 0; tsg = (rdpTsg*) IDL_handle; buffer1Length = buffer2Length = buffer3Length = 0; if (count > 0) { numBuffers++; buffer1 = &pRpcMessage[0]; buffer1Length = lengths[0]; totalDataBytes += lengths[0] + 4; } if (count > 1) { numBuffers++; buffer2 = &pRpcMessage[1]; buffer2Length = lengths[1]; totalDataBytes += lengths[1] + 4; } if (count > 2) { numBuffers++; buffer3 = &pRpcMessage[2]; buffer3Length = lengths[2]; totalDataBytes += lengths[2] + 4; } length = 28 + totalDataBytes; buffer = (BYTE*) malloc(length); s = Stream_New(buffer, length); /* PCHANNEL_CONTEXT_HANDLE_NOSERIALIZE_NR (20 bytes) */ Stream_Write(s, &tsg->ChannelContext.ContextType, 4); /* ContextType (4 bytes) */ Stream_Write(s, tsg->ChannelContext.ContextUuid, 16); /* ContextUuid (16 bytes) */ Stream_Write_UINT32_BE(s, totalDataBytes); /* totalDataBytes (4 bytes) */ Stream_Write_UINT32_BE(s, numBuffers); /* numBuffers (4 bytes) */ if (buffer1Length > 0) Stream_Write_UINT32_BE(s, buffer1Length); /* buffer1Length (4 bytes) */ if (buffer2Length > 0) Stream_Write_UINT32_BE(s, buffer2Length); /* buffer2Length (4 bytes) */ if (buffer3Length > 0) Stream_Write_UINT32_BE(s, buffer3Length); /* buffer3Length (4 bytes) */ if (buffer1Length > 0) Stream_Write(s, buffer1, buffer1Length); /* buffer1 (variable) */ if (buffer2Length > 0) Stream_Write(s, buffer2, buffer2Length); /* buffer2 (variable) */ if (buffer3Length > 0) Stream_Write(s, buffer3, buffer3Length); /* buffer3 (variable) */ Stream_Length(s) = Stream_Position(s); status = rpc_write(tsg->rpc, Stream_Buffer(s), Stream_Length(s), TsProxySendToServerOpnum); Stream_Free(s, TRUE); if (status <= 0) { printf("rpc_write failed!\n"); return -1; } return length; }