示例#1
0
文件: rpc.c 项目: d0rian/FreeRDP
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;
}
示例#2
0
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;
}
示例#3
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;
}