22#include <freerdp/config.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);
55static UINT encomsp_recv_change_participant_control_level_pdu(EncomspServerContext* context,
60 UINT error = CHANNEL_RC_OK;
62 const size_t pos = Stream_GetPosition(s);
63 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
64 return ERROR_INVALID_PARAMETER;
66 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
69 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
70 return ERROR_INVALID_DATA;
72 Stream_Read_UINT16(s, pdu.Flags);
73 Stream_Read_UINT32(s, pdu.ParticipantId);
74 const size_t end = Stream_GetPosition(s);
76 if ((beg + header->Length) < end)
78 WLog_ERR(TAG,
"Not enough data!");
79 return ERROR_INVALID_DATA;
82 if ((beg + header->Length) > end)
84 if (!Stream_CheckAndLogRequiredLength(TAG, s, (
size_t)((beg + header->Length) - end)))
85 return ERROR_INVALID_DATA;
87 if (!Stream_SetPosition(s, (beg + header->Length)))
88 return ERROR_INVALID_DATA;
91 IFCALLRET(context->ChangeParticipantControlLevel, error, context, &pdu);
94 WLog_ERR(TAG,
"context->ChangeParticipantControlLevel failed with error %" PRIu32
"",
105static UINT encomsp_server_receive_pdu(EncomspServerContext* context,
wStream* s)
107 UINT error = CHANNEL_RC_OK;
109 while (Stream_GetRemainingLength(s) > 0)
112 if ((error = encomsp_read_header(s, &header)))
114 WLog_ERR(TAG,
"encomsp_read_header failed with error %" PRIu32
"!", error);
118 WLog_INFO(TAG,
"EncomspReceive: Type: %" PRIu16
" Length: %" PRIu16
"", header.Type,
123 case ODTYPE_PARTICIPANT_CTRL_CHANGED:
125 encomsp_recv_change_participant_control_level_pdu(context, s, &header)))
128 "encomsp_recv_change_participant_control_level_pdu failed with error "
137 WLog_ERR(TAG,
"header.Type unknown %" PRIu16
"!", header.Type);
138 return ERROR_INVALID_DATA;
145static DWORD WINAPI encomsp_server_thread(LPVOID arg)
149 void* buffer =
nullptr;
151 HANDLE ChannelEvent =
nullptr;
152 DWORD BytesReturned = 0;
154 EncomspServerContext* context =
nullptr;
155 UINT error = CHANNEL_RC_OK;
157 context = (EncomspServerContext*)arg;
161 ChannelEvent =
nullptr;
162 s = Stream_New(
nullptr, 4096);
166 WLog_ERR(TAG,
"Stream_New failed!");
167 error = CHANNEL_RC_NO_MEMORY;
171 if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
172 &BytesReturned) == TRUE)
174 if (BytesReturned ==
sizeof(HANDLE))
175 ChannelEvent = *(HANDLE*)buffer;
177 WTSFreeMemory(buffer);
181 events[nCount++] = ChannelEvent;
182 events[nCount++] = context->priv->StopEvent;
186 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
188 if (status == WAIT_FAILED)
190 error = GetLastError();
191 WLog_ERR(TAG,
"WaitForMultipleObjects failed with error %" PRIu32
"", error);
195 status = WaitForSingleObject(context->priv->StopEvent, 0);
197 if (status == WAIT_FAILED)
199 error = GetLastError();
200 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", error);
204 if (status == WAIT_OBJECT_0)
209 if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
nullptr, 0, &BytesReturned))
211 WLog_ERR(TAG,
"WTSVirtualChannelRead failed!");
212 error = ERROR_INTERNAL_ERROR;
216 if (BytesReturned < 1)
219 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
221 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
222 error = CHANNEL_RC_NO_MEMORY;
226 const size_t cap = Stream_Capacity(s);
227 if ((cap > UINT32_MAX) ||
228 !WTSVirtualChannelRead(context->priv->ChannelHandle, 0, Stream_BufferAs(s,
char),
229 (ULONG)cap, &BytesReturned))
231 WLog_ERR(TAG,
"WTSVirtualChannelRead failed!");
232 error = ERROR_INTERNAL_ERROR;
236 if (Stream_GetPosition(s) >= ENCOMSP_ORDER_HEADER_SIZE)
240 if (header->Length >= Stream_GetPosition(s))
242 Stream_SealLength(s);
243 Stream_ResetPosition(s);
245 if ((error = encomsp_server_receive_pdu(context, s)))
247 WLog_ERR(TAG,
"encomsp_server_receive_pdu failed with error %" PRIu32
"!",
252 Stream_ResetPosition(s);
257 Stream_Free(s, TRUE);
260 if (error && context->rdpcontext)
261 setChannelError(context->rdpcontext, error,
"encomsp_server_thread reported an error");
272static UINT encomsp_server_start(EncomspServerContext* context)
274 context->priv->ChannelHandle =
275 WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, ENCOMSP_SVC_CHANNEL_NAME);
277 if (!context->priv->ChannelHandle)
278 return CHANNEL_RC_BAD_CHANNEL;
280 if (!(context->priv->StopEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr)))
282 WLog_ERR(TAG,
"CreateEvent failed!");
283 return ERROR_INTERNAL_ERROR;
286 if (!(context->priv->Thread =
287 CreateThread(
nullptr, 0, encomsp_server_thread, (
void*)context, 0,
nullptr)))
289 WLog_ERR(TAG,
"CreateThread failed!");
290 (void)CloseHandle(context->priv->StopEvent);
291 context->priv->StopEvent =
nullptr;
292 return ERROR_INTERNAL_ERROR;
295 return CHANNEL_RC_OK;
303static UINT encomsp_server_stop(EncomspServerContext* context)
305 UINT error = CHANNEL_RC_OK;
306 (void)SetEvent(context->priv->StopEvent);
308 if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
310 error = GetLastError();
311 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", error);
315 (void)CloseHandle(context->priv->Thread);
316 (void)CloseHandle(context->priv->StopEvent);
320EncomspServerContext* encomsp_server_context_new(HANDLE vcm)
322 EncomspServerContext* context =
nullptr;
323 context = (EncomspServerContext*)calloc(1,
sizeof(EncomspServerContext));
328 context->Start = encomsp_server_start;
329 context->Stop = encomsp_server_stop;
330 context->priv = (EncomspServerPrivate*)calloc(1,
sizeof(EncomspServerPrivate));
334 WLog_ERR(TAG,
"calloc failed!");
343void encomsp_server_context_free(EncomspServerContext* context)
347 if (context->priv->ChannelHandle != INVALID_HANDLE_VALUE)
348 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);