FreeRDP
Loading...
Searching...
No Matches
server/encomsp_main.c
1
22#include <freerdp/config.h>
23
24#include <winpr/crt.h>
25#include <winpr/print.h>
26#include <winpr/stream.h>
27
28#include <freerdp/freerdp.h>
29#include <freerdp/channels/log.h>
30
31#include "encomsp_main.h"
32
33#define TAG CHANNELS_TAG("encomsp.server")
34
40static UINT encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header)
41{
42 if (!Stream_CheckAndLogRequiredLength(TAG, s, ENCOMSP_ORDER_HEADER_SIZE))
43 return ERROR_INVALID_DATA;
44
45 Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */
46 Stream_Read_UINT16(s, header->Length); /* Length (2 bytes) */
47 return CHANNEL_RC_OK;
48}
49
55static UINT encomsp_recv_change_participant_control_level_pdu(EncomspServerContext* context,
56 wStream* s,
57 const ENCOMSP_ORDER_HEADER* header)
58{
60 UINT error = CHANNEL_RC_OK;
61
62 const size_t pos = Stream_GetPosition(s);
63 if (pos < ENCOMSP_ORDER_HEADER_SIZE)
64 return ERROR_INVALID_PARAMETER;
65
66 const size_t beg = pos - ENCOMSP_ORDER_HEADER_SIZE;
67 CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
68
69 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
70 return ERROR_INVALID_DATA;
71
72 Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
73 Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
74 const size_t end = Stream_GetPosition(s);
75
76 if ((beg + header->Length) < end)
77 {
78 WLog_ERR(TAG, "Not enough data!");
79 return ERROR_INVALID_DATA;
80 }
81
82 if ((beg + header->Length) > end)
83 {
84 if (!Stream_CheckAndLogRequiredLength(TAG, s, (size_t)((beg + header->Length) - end)))
85 return ERROR_INVALID_DATA;
86
87 Stream_SetPosition(s, (beg + header->Length));
88 }
89
90 IFCALLRET(context->ChangeParticipantControlLevel, error, context, &pdu);
91
92 if (error)
93 WLog_ERR(TAG, "context->ChangeParticipantControlLevel failed with error %" PRIu32 "",
94 error);
95
96 return error;
97}
98
104static UINT encomsp_server_receive_pdu(EncomspServerContext* context, wStream* s)
105{
106 UINT error = CHANNEL_RC_OK;
107
108 while (Stream_GetRemainingLength(s) > 0)
109 {
110 ENCOMSP_ORDER_HEADER header = { 0 };
111 if ((error = encomsp_read_header(s, &header)))
112 {
113 WLog_ERR(TAG, "encomsp_read_header failed with error %" PRIu32 "!", error);
114 return error;
115 }
116
117 WLog_INFO(TAG, "EncomspReceive: Type: %" PRIu16 " Length: %" PRIu16 "", header.Type,
118 header.Length);
119
120 switch (header.Type)
121 {
122 case ODTYPE_PARTICIPANT_CTRL_CHANGED:
123 if ((error =
124 encomsp_recv_change_participant_control_level_pdu(context, s, &header)))
125 {
126 WLog_ERR(TAG,
127 "encomsp_recv_change_participant_control_level_pdu failed with error "
128 "%" PRIu32 "!",
129 error);
130 return error;
131 }
132
133 break;
134
135 default:
136 WLog_ERR(TAG, "header.Type unknown %" PRIu16 "!", header.Type);
137 return ERROR_INVALID_DATA;
138 }
139 }
140
141 return error;
142}
143
144static DWORD WINAPI encomsp_server_thread(LPVOID arg)
145{
146 wStream* s = NULL;
147 DWORD nCount = 0;
148 void* buffer = NULL;
149 HANDLE events[8];
150 HANDLE ChannelEvent = NULL;
151 DWORD BytesReturned = 0;
152 ENCOMSP_ORDER_HEADER* header = NULL;
153 EncomspServerContext* context = NULL;
154 UINT error = CHANNEL_RC_OK;
155 DWORD status = 0;
156 context = (EncomspServerContext*)arg;
157
158 buffer = NULL;
159 BytesReturned = 0;
160 ChannelEvent = NULL;
161 s = Stream_New(NULL, 4096);
162
163 if (!s)
164 {
165 WLog_ERR(TAG, "Stream_New failed!");
166 error = CHANNEL_RC_NO_MEMORY;
167 goto out;
168 }
169
170 if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
171 &BytesReturned) == TRUE)
172 {
173 if (BytesReturned == sizeof(HANDLE))
174 ChannelEvent = *(HANDLE*)buffer;
175
176 WTSFreeMemory(buffer);
177 }
178
179 nCount = 0;
180 events[nCount++] = ChannelEvent;
181 events[nCount++] = context->priv->StopEvent;
182
183 while (1)
184 {
185 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
186
187 if (status == WAIT_FAILED)
188 {
189 error = GetLastError();
190 WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
191 break;
192 }
193
194 status = WaitForSingleObject(context->priv->StopEvent, 0);
195
196 if (status == WAIT_FAILED)
197 {
198 error = GetLastError();
199 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
200 break;
201 }
202
203 if (status == WAIT_OBJECT_0)
204 {
205 break;
206 }
207
208 if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned))
209 {
210 WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
211 error = ERROR_INTERNAL_ERROR;
212 break;
213 }
214
215 if (BytesReturned < 1)
216 continue;
217
218 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
219 {
220 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
221 error = CHANNEL_RC_NO_MEMORY;
222 break;
223 }
224
225 const size_t cap = Stream_Capacity(s);
226 if ((cap > UINT32_MAX) ||
227 !WTSVirtualChannelRead(context->priv->ChannelHandle, 0, Stream_BufferAs(s, char),
228 (ULONG)cap, &BytesReturned))
229 {
230 WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
231 error = ERROR_INTERNAL_ERROR;
232 break;
233 }
234
235 if (Stream_GetPosition(s) >= ENCOMSP_ORDER_HEADER_SIZE)
236 {
237 header = Stream_BufferAs(s, ENCOMSP_ORDER_HEADER);
238
239 if (header->Length >= Stream_GetPosition(s))
240 {
241 Stream_SealLength(s);
242 Stream_SetPosition(s, 0);
243
244 if ((error = encomsp_server_receive_pdu(context, s)))
245 {
246 WLog_ERR(TAG, "encomsp_server_receive_pdu failed with error %" PRIu32 "!",
247 error);
248 break;
249 }
250
251 Stream_SetPosition(s, 0);
252 }
253 }
254 }
255
256 Stream_Free(s, TRUE);
257out:
258
259 if (error && context->rdpcontext)
260 setChannelError(context->rdpcontext, error, "encomsp_server_thread reported an error");
261
262 ExitThread(error);
263 return error;
264}
265
271static UINT encomsp_server_start(EncomspServerContext* context)
272{
273 context->priv->ChannelHandle =
274 WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, ENCOMSP_SVC_CHANNEL_NAME);
275
276 if (!context->priv->ChannelHandle)
277 return CHANNEL_RC_BAD_CHANNEL;
278
279 if (!(context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
280 {
281 WLog_ERR(TAG, "CreateEvent failed!");
282 return ERROR_INTERNAL_ERROR;
283 }
284
285 if (!(context->priv->Thread =
286 CreateThread(NULL, 0, encomsp_server_thread, (void*)context, 0, NULL)))
287 {
288 WLog_ERR(TAG, "CreateThread failed!");
289 (void)CloseHandle(context->priv->StopEvent);
290 context->priv->StopEvent = NULL;
291 return ERROR_INTERNAL_ERROR;
292 }
293
294 return CHANNEL_RC_OK;
295}
296
302static UINT encomsp_server_stop(EncomspServerContext* context)
303{
304 UINT error = CHANNEL_RC_OK;
305 (void)SetEvent(context->priv->StopEvent);
306
307 if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
308 {
309 error = GetLastError();
310 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
311 return error;
312 }
313
314 (void)CloseHandle(context->priv->Thread);
315 (void)CloseHandle(context->priv->StopEvent);
316 return error;
317}
318
319EncomspServerContext* encomsp_server_context_new(HANDLE vcm)
320{
321 EncomspServerContext* context = NULL;
322 context = (EncomspServerContext*)calloc(1, sizeof(EncomspServerContext));
323
324 if (context)
325 {
326 context->vcm = vcm;
327 context->Start = encomsp_server_start;
328 context->Stop = encomsp_server_stop;
329 context->priv = (EncomspServerPrivate*)calloc(1, sizeof(EncomspServerPrivate));
330
331 if (!context->priv)
332 {
333 WLog_ERR(TAG, "calloc failed!");
334 free(context);
335 return NULL;
336 }
337 }
338
339 return context;
340}
341
342void encomsp_server_context_free(EncomspServerContext* context)
343{
344 if (context)
345 {
346 if (context->priv->ChannelHandle != INVALID_HANDLE_VALUE)
347 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
348
349 free(context->priv);
350 free(context);
351 }
352}