2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * Remote Assistance Virtual Channel
5 * Copyright 2014 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.
24 #include <winpr/crt.h>
25 #include <winpr/print.h>
27 #include <freerdp/client/remdesk.h>
29 #include "remdesk_main.h"
31 RemdeskClientContext* remdesk_get_client_interface(remdeskPlugin* remdesk)
33 RemdeskClientContext* pInterface;
34 pInterface = (RemdeskClientContext*) remdesk->channelEntryPoints.pInterface;
38 static int remdesk_process_receive(remdeskPlugin* remdesk, wStream* s)
42 printf("RemdeskReceive: %d\n", Stream_GetRemainingLength(s));
43 winpr_HexDump(Stream_Pointer(s), Stream_GetRemainingLength(s));
48 static void remdesk_process_connect(remdeskPlugin* remdesk)
50 printf("RemdeskProcessConnect\n");
53 /****************************************************************************************/
55 static wListDictionary* g_InitHandles;
56 static wListDictionary* g_OpenHandles;
58 void remdesk_add_init_handle_data(void* pInitHandle, void* pUserData)
61 g_InitHandles = ListDictionary_New(TRUE);
63 ListDictionary_Add(g_InitHandles, pInitHandle, pUserData);
66 void* remdesk_get_init_handle_data(void* pInitHandle)
68 void* pUserData = NULL;
69 pUserData = ListDictionary_GetItemValue(g_InitHandles, pInitHandle);
73 void remdesk_remove_init_handle_data(void* pInitHandle)
75 ListDictionary_Remove(g_InitHandles, pInitHandle);
78 void remdesk_add_open_handle_data(DWORD openHandle, void* pUserData)
80 void* pOpenHandle = (void*) (size_t) openHandle;
83 g_OpenHandles = ListDictionary_New(TRUE);
85 ListDictionary_Add(g_OpenHandles, pOpenHandle, pUserData);
88 void* remdesk_get_open_handle_data(DWORD openHandle)
90 void* pUserData = NULL;
91 void* pOpenHandle = (void*) (size_t) openHandle;
92 pUserData = ListDictionary_GetItemValue(g_OpenHandles, pOpenHandle);
96 void remdesk_remove_open_handle_data(DWORD openHandle)
98 void* pOpenHandle = (void*) (size_t) openHandle;
99 ListDictionary_Remove(g_OpenHandles, pOpenHandle);
102 int remdesk_send(remdeskPlugin* remdesk, wStream* s)
105 remdeskPlugin* plugin = (remdeskPlugin*) remdesk;
109 status = CHANNEL_RC_BAD_INIT_HANDLE;
113 status = plugin->channelEntryPoints.pVirtualChannelWrite(plugin->OpenHandle,
114 Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s);
117 if (status != CHANNEL_RC_OK)
119 Stream_Free(s, TRUE);
120 fprintf(stderr, "remdesk_send: VirtualChannelWrite failed %d\n", status);
126 static void remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk,
127 void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
131 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
136 if (dataFlags & CHANNEL_FLAG_FIRST)
138 if (remdesk->data_in)
139 Stream_Free(remdesk->data_in, TRUE);
141 remdesk->data_in = Stream_New(NULL, totalLength);
144 data_in = remdesk->data_in;
145 Stream_EnsureRemainingCapacity(data_in, (int) dataLength);
146 Stream_Write(data_in, pData, dataLength);
148 if (dataFlags & CHANNEL_FLAG_LAST)
150 if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
152 fprintf(stderr, "remdesk_plugin_process_received: read error\n");
155 remdesk->data_in = NULL;
156 Stream_SealLength(data_in);
157 Stream_SetPosition(data_in, 0);
159 MessageQueue_Post(remdesk->MsgPipe->In, NULL, 0, (void*) data_in, NULL);
163 static VOID VCAPITYPE remdesk_virtual_channel_open_event(DWORD openHandle, UINT event,
164 LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
166 remdeskPlugin* remdesk;
168 remdesk = (remdeskPlugin*) remdesk_get_open_handle_data(openHandle);
172 fprintf(stderr, "remdesk_virtual_channel_open_event: error no match\n");
178 case CHANNEL_EVENT_DATA_RECEIVED:
179 remdesk_virtual_channel_event_data_received(remdesk, pData, dataLength, totalLength, dataFlags);
182 case CHANNEL_EVENT_WRITE_COMPLETE:
183 Stream_Free((wStream*) pData, TRUE);
186 case CHANNEL_EVENT_USER:
191 static void* remdesk_virtual_channel_client_thread(void* arg)
195 remdeskPlugin* remdesk = (remdeskPlugin*) arg;
197 remdesk_process_connect(remdesk);
201 if (!MessageQueue_Wait(remdesk->MsgPipe->In))
204 if (MessageQueue_Peek(remdesk->MsgPipe->In, &message, TRUE))
206 if (message.id == WMQ_QUIT)
211 data = (wStream*) message.wParam;
212 remdesk_process_receive(remdesk, data);
221 static void remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk, LPVOID pData, UINT32 dataLength)
225 status = remdesk->channelEntryPoints.pVirtualChannelOpen(remdesk->InitHandle,
226 &remdesk->OpenHandle, remdesk->channelDef.name, remdesk_virtual_channel_open_event);
228 remdesk_add_open_handle_data(remdesk->OpenHandle, remdesk);
230 if (status != CHANNEL_RC_OK)
232 fprintf(stderr, "remdesk_virtual_channel_event_connected: open failed: status: %d\n", status);
236 remdesk->MsgPipe = MessagePipe_New();
238 remdesk->thread = CreateThread(NULL, 0,
239 (LPTHREAD_START_ROUTINE) remdesk_virtual_channel_client_thread, (void*) remdesk, 0, NULL);
242 static void remdesk_virtual_channel_event_terminated(remdeskPlugin* remdesk)
244 MessagePipe_PostQuit(remdesk->MsgPipe, 0);
245 WaitForSingleObject(remdesk->thread, INFINITE);
247 MessagePipe_Free(remdesk->MsgPipe);
248 CloseHandle(remdesk->thread);
250 remdesk->channelEntryPoints.pVirtualChannelClose(remdesk->OpenHandle);
252 if (remdesk->data_in)
254 Stream_Free(remdesk->data_in, TRUE);
255 remdesk->data_in = NULL;
258 remdesk_remove_open_handle_data(remdesk->OpenHandle);
259 remdesk_remove_init_handle_data(remdesk->InitHandle);
262 static VOID VCAPITYPE remdesk_virtual_channel_init_event(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength)
264 remdeskPlugin* remdesk;
266 remdesk = (remdeskPlugin*) remdesk_get_init_handle_data(pInitHandle);
270 fprintf(stderr, "remdesk_virtual_channel_init_event: error no match\n");
276 case CHANNEL_EVENT_CONNECTED:
277 remdesk_virtual_channel_event_connected(remdesk, pData, dataLength);
280 case CHANNEL_EVENT_DISCONNECTED:
283 case CHANNEL_EVENT_TERMINATED:
284 remdesk_virtual_channel_event_terminated(remdesk);
289 /* remdesk is always built-in */
290 #define VirtualChannelEntry remdesk_VirtualChannelEntry
292 BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
294 remdeskPlugin* remdesk;
295 RemdeskClientContext* context;
296 CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx;
298 remdesk = (remdeskPlugin*) calloc(1, sizeof(remdeskPlugin));
300 remdesk->channelDef.options =
301 CHANNEL_OPTION_INITIALIZED |
302 CHANNEL_OPTION_ENCRYPT_RDP |
303 CHANNEL_OPTION_COMPRESS_RDP |
304 CHANNEL_OPTION_SHOW_PROTOCOL;
306 strcpy(remdesk->channelDef.name, "remdesk");
308 pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP*) pEntryPoints;
310 if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP)) &&
311 (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
313 context = (RemdeskClientContext*) calloc(1, sizeof(RemdeskClientContext));
315 context->handle = (void*) remdesk;
317 *(pEntryPointsEx->ppInterface) = (void*) context;
320 CopyMemory(&(remdesk->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP));
322 remdesk->channelEntryPoints.pVirtualChannelInit(&remdesk->InitHandle,
323 &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, remdesk_virtual_channel_init_event);
325 remdesk_add_init_handle_data(remdesk->InitHandle, (void*) remdesk);