2
* FreeRDP: A Remote Desktop Protocol Implementation
5
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7
* Licensed under the Apache License, Version 2.0 (the "License");
8
* you may not use this file except in compliance with the License.
9
* You may obtain a copy of the License at
11
* http://www.apache.org/licenses/LICENSE-2.0
13
* Unless required by applicable law or agreed to in writing, software
14
* distributed under the License is distributed on an "AS IS" BASIS,
15
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
* See the License for the specific language governing permissions and
17
* limitations under the License.
28
#include <winpr/crt.h>
29
#include <winpr/print.h>
30
#include <winpr/synch.h>
31
#include <winpr/thread.h>
32
#include <winpr/stream.h>
34
#include "rpc_fault.h"
36
#include "rpc_client.h"
40
wStream* rpc_client_fragment_pool_take(rdpRpc* rpc)
42
wStream* fragment = NULL;
44
if (WaitForSingleObject(Queue_Event(rpc->client->FragmentPool), 0) == WAIT_OBJECT_0)
45
fragment = Queue_Dequeue(rpc->client->FragmentPool);
48
fragment = Stream_New(NULL, rpc->max_recv_frag);
53
int rpc_client_fragment_pool_return(rdpRpc* rpc, wStream* fragment)
55
Queue_Enqueue(rpc->client->FragmentPool, fragment);
59
RPC_PDU* rpc_client_receive_pool_take(rdpRpc* rpc)
63
if (WaitForSingleObject(Queue_Event(rpc->client->ReceivePool), 0) == WAIT_OBJECT_0)
64
pdu = Queue_Dequeue(rpc->client->ReceivePool);
68
pdu = (RPC_PDU*) malloc(sizeof(RPC_PDU));
69
pdu->s = Stream_New(NULL, rpc->max_recv_frag);
75
Stream_Length(pdu->s) = 0;
76
Stream_SetPosition(pdu->s, 0);
81
int rpc_client_receive_pool_return(rdpRpc* rpc, RPC_PDU* pdu)
83
Queue_Enqueue(rpc->client->ReceivePool, pdu);
87
int rpc_client_on_fragment_received_event(rdpRpc* rpc)
93
rpcconn_hdr_t* header;
96
instance = (freerdp*) rpc->transport->settings->instance;
98
if (!rpc->client->pdu)
99
rpc->client->pdu = rpc_client_receive_pool_take(rpc);
101
fragment = Queue_Dequeue(rpc->client->FragmentQueue);
103
buffer = (BYTE*) Stream_Buffer(fragment);
104
header = (rpcconn_hdr_t*) Stream_Buffer(fragment);
106
if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
108
rpc->client->pdu->Flags = 0;
109
rpc->client->pdu->CallId = header->common.call_id;
111
Stream_EnsureCapacity(rpc->client->pdu->s, Stream_Length(fragment));
112
Stream_Write(rpc->client->pdu->s, buffer, Stream_Length(fragment));
113
Stream_Length(rpc->client->pdu->s) = Stream_GetPosition(rpc->client->pdu->s);
115
rpc_client_fragment_pool_return(rpc, fragment);
117
Queue_Enqueue(rpc->client->ReceiveQueue, rpc->client->pdu);
118
SetEvent(rpc->transport->ReceiveEvent);
119
rpc->client->pdu = NULL;
124
if (header->common.ptype == PTYPE_RTS)
126
if (rpc->VirtualConnection->State >= VIRTUAL_CONNECTION_STATE_OPENED)
128
//fprintf(stderr, "Receiving Out-of-Sequence RTS PDU\n");
129
rts_recv_out_of_sequence_pdu(rpc, buffer, header->common.frag_length);
131
rpc_client_fragment_pool_return(rpc, fragment);
135
fprintf(stderr, "warning: unhandled RTS PDU\n");
140
else if (header->common.ptype == PTYPE_FAULT)
142
rpc_recv_fault_pdu(header);
146
if (header->common.ptype != PTYPE_RESPONSE)
148
fprintf(stderr, "Unexpected RPC PDU type: %d\n", header->common.ptype);
152
rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header->common.frag_length;
153
rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -= header->common.frag_length;
155
if (!rpc_get_stub_data_info(rpc, buffer, &StubOffset, &StubLength))
157
fprintf(stderr, "rpc_recv_pdu_fragment: expected stub\n");
163
//fprintf(stderr, "Ignoring TsProxySendToServer Response\n");
164
printf("Got stub length 4 with flags %d and callid %d\n", header->common.pfc_flags, header->common.call_id);
166
/* received a disconnect request from the server? */
167
if ((header->common.call_id == rpc->PipeCallId) && (header->common.pfc_flags & PFC_LAST_FRAG))
169
TerminateEventArgs e;
171
instance->context->rdp->disconnect = TRUE;
172
rpc->transport->tsg->state = TSG_STATE_TUNNEL_CLOSE_PENDING;
174
EventArgsInit(&e, "freerdp");
176
PubSub_OnTerminate(instance->context->pubSub, instance->context, &e);
179
rpc_client_fragment_pool_return(rpc, fragment);
183
Stream_EnsureCapacity(rpc->client->pdu->s, header->response.alloc_hint);
184
buffer = (BYTE*) Stream_Buffer(fragment);
185
header = (rpcconn_hdr_t*) Stream_Buffer(fragment);
187
if (rpc->StubFragCount == 0)
188
rpc->StubCallId = header->common.call_id;
190
if (rpc->StubCallId != header->common.call_id)
192
fprintf(stderr, "invalid call_id: actual: %d, expected: %d, frag_count: %d\n",
193
rpc->StubCallId, header->common.call_id, rpc->StubFragCount);
196
Stream_Write(rpc->client->pdu->s, &buffer[StubOffset], StubLength);
197
rpc->StubFragCount++;
199
rpc_client_fragment_pool_return(rpc, fragment);
201
if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow < (rpc->ReceiveWindow / 2))
203
//fprintf(stderr, "Sending Flow Control Ack PDU\n");
204
rts_send_flow_control_ack_pdu(rpc);
208
* If alloc_hint is set to a nonzero value and a request or a response is fragmented into multiple
209
* PDUs, implementations of these extensions SHOULD set the alloc_hint field in every PDU to be the
210
* combined stub data length of all remaining fragment PDUs.
213
if (header->response.alloc_hint == StubLength)
215
rpc->client->pdu->Flags = RPC_PDU_FLAG_STUB;
216
rpc->client->pdu->CallId = rpc->StubCallId;
218
Stream_Length(rpc->client->pdu->s) = Stream_GetPosition(rpc->client->pdu->s);
220
rpc->StubFragCount = 0;
223
Queue_Enqueue(rpc->client->ReceiveQueue, rpc->client->pdu);
225
rpc->client->pdu = NULL;
233
int rpc_client_on_read_event(rdpRpc* rpc)
237
rpcconn_common_hdr_t* header;
239
if (!rpc->client->RecvFrag)
240
rpc->client->RecvFrag = rpc_client_fragment_pool_take(rpc);
242
position = Stream_GetPosition(rpc->client->RecvFrag);
244
if (Stream_GetPosition(rpc->client->RecvFrag) < RPC_COMMON_FIELDS_LENGTH)
246
status = rpc_out_read(rpc, Stream_Pointer(rpc->client->RecvFrag),
247
RPC_COMMON_FIELDS_LENGTH - Stream_GetPosition(rpc->client->RecvFrag));
251
fprintf(stderr, "rpc_client_frag_read: error reading header\n");
255
Stream_Seek(rpc->client->RecvFrag, status);
258
if (Stream_GetPosition(rpc->client->RecvFrag) >= RPC_COMMON_FIELDS_LENGTH)
260
header = (rpcconn_common_hdr_t*) Stream_Buffer(rpc->client->RecvFrag);
262
if (header->frag_length > rpc->max_recv_frag)
264
fprintf(stderr, "rpc_client_frag_read: invalid fragment size: %d (max: %d)\n",
265
header->frag_length, rpc->max_recv_frag);
266
winpr_HexDump(Stream_Buffer(rpc->client->RecvFrag), Stream_GetPosition(rpc->client->RecvFrag));
270
if (Stream_GetPosition(rpc->client->RecvFrag) < header->frag_length)
272
status = rpc_out_read(rpc, Stream_Pointer(rpc->client->RecvFrag),
273
header->frag_length - Stream_GetPosition(rpc->client->RecvFrag));
277
fprintf(stderr, "rpc_client_frag_read: error reading fragment body\n");
281
Stream_Seek(rpc->client->RecvFrag, status);
292
status = Stream_GetPosition(rpc->client->RecvFrag) - position;
294
if (Stream_GetPosition(rpc->client->RecvFrag) >= header->frag_length)
296
/* complete fragment received */
298
Stream_Length(rpc->client->RecvFrag) = Stream_GetPosition(rpc->client->RecvFrag);
299
Stream_SetPosition(rpc->client->RecvFrag, 0);
301
Queue_Enqueue(rpc->client->FragmentQueue, rpc->client->RecvFrag);
302
rpc->client->RecvFrag = NULL;
304
rpc_client_on_fragment_received_event(rpc);
311
* [MS-RPCE] Client Call:
312
* http://msdn.microsoft.com/en-us/library/gg593159/
315
RpcClientCall* rpc_client_call_find_by_id(rdpRpc* rpc, UINT32 CallId)
319
RpcClientCall* clientCall;
321
ArrayList_Lock(rpc->client->ClientCallList);
324
count = ArrayList_Count(rpc->client->ClientCallList);
326
for (index = 0; index < count; index++)
328
clientCall = (RpcClientCall*) ArrayList_GetItem(rpc->client->ClientCallList, index);
330
if (clientCall->CallId == CallId)
334
ArrayList_Unlock(rpc->client->ClientCallList);
339
RpcClientCall* rpc_client_call_new(UINT32 CallId, UINT32 OpNum)
341
RpcClientCall* clientCall;
343
clientCall = (RpcClientCall*) malloc(sizeof(RpcClientCall));
347
clientCall->CallId = CallId;
348
clientCall->OpNum = OpNum;
349
clientCall->State = RPC_CLIENT_CALL_STATE_SEND_PDUS;
355
void rpc_client_call_free(RpcClientCall* clientCall)
360
int rpc_send_enqueue_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
364
pdu = (RPC_PDU*) malloc(sizeof(RPC_PDU));
365
pdu->s = Stream_New(buffer, length);
367
Queue_Enqueue(rpc->client->SendQueue, pdu);
369
if (rpc->client->SynchronousSend)
371
WaitForSingleObject(rpc->client->PduSentEvent, INFINITE);
372
ResetEvent(rpc->client->PduSentEvent);
378
int rpc_send_dequeue_pdu(rdpRpc* rpc)
382
RpcClientCall* clientCall;
383
rpcconn_common_hdr_t* header;
385
pdu = (RPC_PDU*) Queue_Dequeue(rpc->client->SendQueue);
390
WaitForSingleObject(rpc->VirtualConnection->DefaultInChannel->Mutex, INFINITE);
392
status = rpc_in_write(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s));
394
header = (rpcconn_common_hdr_t*) Stream_Buffer(pdu->s);
395
clientCall = rpc_client_call_find_by_id(rpc, header->call_id);
396
clientCall->State = RPC_CLIENT_CALL_STATE_DISPATCHED;
398
ReleaseMutex(rpc->VirtualConnection->DefaultInChannel->Mutex);
401
* This protocol specifies that only RPC PDUs are subject to the flow control abstract
402
* data model. RTS PDUs and the HTTP request and response headers are not subject to flow control.
403
* Implementations of this protocol MUST NOT include them when computing any of the variables
404
* specified by this abstract data model.
407
if (header->ptype == PTYPE_REQUEST)
409
rpc->VirtualConnection->DefaultInChannel->BytesSent += status;
410
rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow -= status;
413
Stream_Free(pdu->s, TRUE);
416
if (rpc->client->SynchronousSend)
417
SetEvent(rpc->client->PduSentEvent);
422
RPC_PDU* rpc_recv_dequeue_pdu(rdpRpc* rpc)
425
DWORD dwMilliseconds;
428
dwMilliseconds = rpc->client->SynchronousReceive ? INFINITE : 0;
430
if (WaitForSingleObject(Queue_Event(rpc->client->ReceiveQueue), dwMilliseconds) == WAIT_OBJECT_0)
432
pdu = (RPC_PDU*) Queue_Dequeue(rpc->client->ReceiveQueue);
434
#ifdef WITH_DEBUG_TSG
437
fprintf(stderr, "Receiving PDU (length: %d, CallId: %d)\n", pdu->s->length, pdu->CallId);
438
winpr_HexDump(Stream_Buffer(pdu->s), Stream_Length(pdu->s));
439
fprintf(stderr, "\n");
449
RPC_PDU* rpc_recv_peek_pdu(rdpRpc* rpc)
452
DWORD dwMilliseconds;
455
dwMilliseconds = rpc->client->SynchronousReceive ? INFINITE : 0;
457
if (WaitForSingleObject(Queue_Event(rpc->client->ReceiveQueue), dwMilliseconds) == WAIT_OBJECT_0)
459
pdu = (RPC_PDU*) Queue_Peek(rpc->client->ReceiveQueue);
466
static void* rpc_client_thread(void* arg)
476
ReadEvent = CreateFileDescriptorEvent(NULL, TRUE, FALSE, rpc->TlsOut->sockfd);
479
events[nCount++] = rpc->client->StopEvent;
480
events[nCount++] = Queue_Event(rpc->client->SendQueue);
481
events[nCount++] = ReadEvent;
485
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
487
if (WaitForSingleObject(rpc->client->StopEvent, 0) == WAIT_OBJECT_0)
492
if (WaitForSingleObject(ReadEvent, 0) == WAIT_OBJECT_0)
494
if (rpc_client_on_read_event(rpc) < 0)
498
if (WaitForSingleObject(Queue_Event(rpc->client->SendQueue), 0) == WAIT_OBJECT_0)
500
rpc_send_dequeue_pdu(rpc);
504
CloseHandle(ReadEvent);
506
rpc_client_free(rpc);
511
static void rpc_pdu_free(RPC_PDU* pdu)
513
Stream_Free(pdu->s, TRUE);
517
static void rpc_fragment_free(wStream* fragment)
519
Stream_Free(fragment, TRUE);
522
int rpc_client_new(rdpRpc* rpc)
524
RpcClient* client = NULL;
526
client = (RpcClient*) malloc(sizeof(RpcClient));
530
client->Thread = CreateThread(NULL, 0,
531
(LPTHREAD_START_ROUTINE) rpc_client_thread,
532
rpc, CREATE_SUSPENDED, NULL);
534
client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
535
client->PduSentEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
537
client->SendQueue = Queue_New(TRUE, -1, -1);
538
Queue_Object(client->SendQueue)->fnObjectFree = (OBJECT_FREE_FN) rpc_pdu_free;
541
client->ReceivePool = Queue_New(TRUE, -1, -1);
542
client->ReceiveQueue = Queue_New(TRUE, -1, -1);
543
Queue_Object(client->ReceivePool)->fnObjectFree = (OBJECT_FREE_FN) rpc_pdu_free;
544
Queue_Object(client->ReceiveQueue)->fnObjectFree = (OBJECT_FREE_FN) rpc_pdu_free;
546
client->RecvFrag = NULL;
547
client->FragmentPool = Queue_New(TRUE, -1, -1);
548
client->FragmentQueue = Queue_New(TRUE, -1, -1);
550
Queue_Object(client->FragmentPool)->fnObjectFree = (OBJECT_FREE_FN) rpc_fragment_free;
551
Queue_Object(client->FragmentQueue)->fnObjectFree = (OBJECT_FREE_FN) rpc_fragment_free;
553
client->ClientCallList = ArrayList_New(TRUE);
554
ArrayList_Object(client->ClientCallList)->fnObjectFree = (OBJECT_FREE_FN) rpc_client_call_free;
557
rpc->client = client;
562
int rpc_client_start(rdpRpc* rpc)
564
ResumeThread(rpc->client->Thread);
569
int rpc_client_stop(rdpRpc* rpc)
571
SetEvent(rpc->client->StopEvent);
573
WaitForSingleObject(rpc->client->Thread, INFINITE);
578
int rpc_client_free(rdpRpc* rpc)
582
client = rpc->client;
586
Queue_Free(client->SendQueue);
588
if (client->RecvFrag)
589
rpc_fragment_free(client->RecvFrag);
591
Queue_Free(client->FragmentPool);
592
Queue_Free(client->FragmentQueue);
595
rpc_pdu_free(client->pdu);
597
Queue_Free(client->ReceivePool);
598
Queue_Free(client->ReceiveQueue);
600
ArrayList_Free(client->ClientCallList);
602
CloseHandle(client->StopEvent);
603
CloseHandle(client->PduSentEvent);
605
CloseHandle(client->Thread);