22 #include <freerdp/config.h>
24 #include <winpr/crt.h>
25 #include <winpr/print.h>
26 #include <winpr/stream.h>
28 #include <freerdp/freerdp.h>
29 #include <freerdp/channels/log.h>
31 #include "encomsp_main.h"
33 #define TAG CHANNELS_TAG("encomsp.server")
42 if (!Stream_CheckAndLogRequiredLength(TAG, s, ENCOMSP_ORDER_HEADER_SIZE))
43 return ERROR_INVALID_DATA;
45 Stream_Read_UINT16(s, header->Type);
46 Stream_Read_UINT16(s, header->Length);
54 Stream_Write_UINT16(s, header->Type);
55 Stream_Write_UINT16(s, header->Length);
63 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
66 Stream_Read_UINT16(s, str->cchString);
68 if (str->cchString > 1024)
71 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, str->cchString,
sizeof(WCHAR)))
74 Stream_Read(s, &(str->wString), (str->cchString * 2));
85 static UINT encomsp_recv_change_participant_control_level_pdu(EncomspServerContext* context,
90 UINT error = CHANNEL_RC_OK;
92 const size_t pos = Stream_GetPosition(s);
93 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
94 return ERROR_INVALID_PARAMETER;
96 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
99 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
100 return ERROR_INVALID_DATA;
102 Stream_Read_UINT16(s, pdu.Flags);
103 Stream_Read_UINT32(s, pdu.ParticipantId);
104 const size_t end = Stream_GetPosition(s);
106 if ((beg + header->Length) < end)
108 WLog_ERR(TAG,
"Not enough data!");
109 return ERROR_INVALID_DATA;
112 if ((beg + header->Length) > end)
114 if (!Stream_CheckAndLogRequiredLength(TAG, s, (
size_t)((beg + header->Length) - end)))
115 return ERROR_INVALID_DATA;
117 Stream_SetPosition(s, (beg + header->Length));
120 IFCALLRET(context->ChangeParticipantControlLevel, error, context, &pdu);
123 WLog_ERR(TAG,
"context->ChangeParticipantControlLevel failed with error %" PRIu32
"",
134 static UINT encomsp_server_receive_pdu(EncomspServerContext* context,
wStream* s)
136 UINT error = CHANNEL_RC_OK;
139 while (Stream_GetRemainingLength(s) > 0)
141 if ((error = encomsp_read_header(s, &header)))
143 WLog_ERR(TAG,
"encomsp_read_header failed with error %" PRIu32
"!", error);
147 WLog_INFO(TAG,
"EncomspReceive: Type: %" PRIu16
" Length: %" PRIu16
"", header.Type,
152 case ODTYPE_PARTICIPANT_CTRL_CHANGED:
154 encomsp_recv_change_participant_control_level_pdu(context, s, &header)))
157 "encomsp_recv_change_participant_control_level_pdu failed with error "
166 WLog_ERR(TAG,
"header.Type unknown %" PRIu16
"!", header.Type);
167 return ERROR_INVALID_DATA;
174 static DWORD WINAPI encomsp_server_thread(LPVOID arg)
180 HANDLE ChannelEvent = NULL;
181 DWORD BytesReturned = 0;
183 EncomspServerContext* context = NULL;
184 UINT error = CHANNEL_RC_OK;
186 context = (EncomspServerContext*)arg;
191 s = Stream_New(NULL, 4096);
195 WLog_ERR(TAG,
"Stream_New failed!");
196 error = CHANNEL_RC_NO_MEMORY;
200 if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
201 &BytesReturned) == TRUE)
203 if (BytesReturned ==
sizeof(HANDLE))
204 ChannelEvent = *(HANDLE*)buffer;
206 WTSFreeMemory(buffer);
210 events[nCount++] = ChannelEvent;
211 events[nCount++] = context->priv->StopEvent;
215 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
217 if (status == WAIT_FAILED)
219 error = GetLastError();
220 WLog_ERR(TAG,
"WaitForMultipleObjects failed with error %" PRIu32
"", error);
224 status = WaitForSingleObject(context->priv->StopEvent, 0);
226 if (status == WAIT_FAILED)
228 error = GetLastError();
229 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", error);
233 if (status == WAIT_OBJECT_0)
238 if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned))
240 WLog_ERR(TAG,
"WTSVirtualChannelRead failed!");
241 error = ERROR_INTERNAL_ERROR;
245 if (BytesReturned < 1)
248 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
250 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
251 error = CHANNEL_RC_NO_MEMORY;
255 const size_t cap = Stream_Capacity(s);
256 if ((cap > UINT32_MAX) ||
257 !WTSVirtualChannelRead(context->priv->ChannelHandle, 0, Stream_BufferAs(s,
char),
258 (ULONG)cap, &BytesReturned))
260 WLog_ERR(TAG,
"WTSVirtualChannelRead failed!");
261 error = ERROR_INTERNAL_ERROR;
265 if (Stream_GetPosition(s) >= ENCOMSP_ORDER_HEADER_SIZE)
269 if (header->Length >= Stream_GetPosition(s))
271 Stream_SealLength(s);
272 Stream_SetPosition(s, 0);
274 if ((error = encomsp_server_receive_pdu(context, s)))
276 WLog_ERR(TAG,
"encomsp_server_receive_pdu failed with error %" PRIu32
"!",
281 Stream_SetPosition(s, 0);
286 Stream_Free(s, TRUE);
289 if (error && context->rdpcontext)
290 setChannelError(context->rdpcontext, error,
"encomsp_server_thread reported an error");
301 static UINT encomsp_server_start(EncomspServerContext* context)
303 context->priv->ChannelHandle =
304 WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, ENCOMSP_SVC_CHANNEL_NAME);
306 if (!context->priv->ChannelHandle)
307 return CHANNEL_RC_BAD_CHANNEL;
309 if (!(context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
311 WLog_ERR(TAG,
"CreateEvent failed!");
312 return ERROR_INTERNAL_ERROR;
315 if (!(context->priv->Thread =
316 CreateThread(NULL, 0, encomsp_server_thread, (
void*)context, 0, NULL)))
318 WLog_ERR(TAG,
"CreateThread failed!");
319 (void)CloseHandle(context->priv->StopEvent);
320 context->priv->StopEvent = NULL;
321 return ERROR_INTERNAL_ERROR;
324 return CHANNEL_RC_OK;
332 static UINT encomsp_server_stop(EncomspServerContext* context)
334 UINT error = CHANNEL_RC_OK;
335 (void)SetEvent(context->priv->StopEvent);
337 if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
339 error = GetLastError();
340 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", error);
344 (void)CloseHandle(context->priv->Thread);
345 (void)CloseHandle(context->priv->StopEvent);
349 EncomspServerContext* encomsp_server_context_new(HANDLE vcm)
351 EncomspServerContext* context = NULL;
352 context = (EncomspServerContext*)calloc(1,
sizeof(EncomspServerContext));
357 context->Start = encomsp_server_start;
358 context->Stop = encomsp_server_stop;
359 context->priv = (EncomspServerPrivate*)calloc(1,
sizeof(EncomspServerPrivate));
363 WLog_ERR(TAG,
"calloc failed!");
372 void encomsp_server_context_free(EncomspServerContext* context)
376 if (context->priv->ChannelHandle != INVALID_HANDLE_VALUE)
377 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);