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{
59 ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu = WINPR_C_ARRAY_INIT;
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 if (!Stream_SetPosition(s, (beg + header->Length)))
88 return ERROR_INVALID_DATA;
89 }
90
91 IFCALLRET(context->ChangeParticipantControlLevel, error, context, &pdu);
92
93 if (error)
94 WLog_ERR(TAG, "context->ChangeParticipantControlLevel failed with error %" PRIu32 "",
95 error);
96
97 return error;
98}
99
105static UINT encomsp_server_receive_pdu(EncomspServerContext* context, wStream* s)
106{
107 UINT error = CHANNEL_RC_OK;
108
109 while (Stream_GetRemainingLength(s) > 0)
110 {
111 ENCOMSP_ORDER_HEADER header = WINPR_C_ARRAY_INIT;
112 if ((error = encomsp_read_header(s, &header)))
113 {
114 WLog_ERR(TAG, "encomsp_read_header failed with error %" PRIu32 "!", error);
115 return error;
116 }
117
118 WLog_INFO(TAG, "EncomspReceive: Type: %" PRIu16 " Length: %" PRIu16 "", header.Type,
119 header.Length);
120
121 switch (header.Type)
122 {
123 case ODTYPE_PARTICIPANT_CTRL_CHANGED:
124 if ((error =
125 encomsp_recv_change_participant_control_level_pdu(context, s, &header)))
126 {
127 WLog_ERR(TAG,
128 "encomsp_recv_change_participant_control_level_pdu failed with error "
129 "%" PRIu32 "!",
130 error);
131 return error;
132 }
133
134 break;
135
136 default:
137 WLog_ERR(TAG, "header.Type unknown %" PRIu16 "!", header.Type);
138 return ERROR_INVALID_DATA;
139 }
140 }
141
142 return error;
143}
144
145static DWORD WINAPI encomsp_server_thread(LPVOID arg)
146{
147 wStream* s = nullptr;
148 DWORD nCount = 0;
149 void* buffer = nullptr;
150 HANDLE events[8];
151 HANDLE ChannelEvent = nullptr;
152 DWORD BytesReturned = 0;
153 ENCOMSP_ORDER_HEADER* header = nullptr;
154 EncomspServerContext* context = nullptr;
155 UINT error = CHANNEL_RC_OK;
156 DWORD status = 0;
157 context = (EncomspServerContext*)arg;
158
159 buffer = nullptr;
160 BytesReturned = 0;
161 ChannelEvent = nullptr;
162 s = Stream_New(nullptr, 4096);
163
164 if (!s)
165 {
166 WLog_ERR(TAG, "Stream_New failed!");
167 error = CHANNEL_RC_NO_MEMORY;
168 goto out;
169 }
170
171 if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
172 &BytesReturned) == TRUE)
173 {
174 if (BytesReturned == sizeof(HANDLE))
175 ChannelEvent = *(HANDLE*)buffer;
176
177 WTSFreeMemory(buffer);
178 }
179
180 nCount = 0;
181 events[nCount++] = ChannelEvent;
182 events[nCount++] = context->priv->StopEvent;
183
184 while (1)
185 {
186 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
187
188 if (status == WAIT_FAILED)
189 {
190 error = GetLastError();
191 WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
192 break;
193 }
194
195 status = WaitForSingleObject(context->priv->StopEvent, 0);
196
197 if (status == WAIT_FAILED)
198 {
199 error = GetLastError();
200 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
201 break;
202 }
203
204 if (status == WAIT_OBJECT_0)
205 {
206 break;
207 }
208
209 if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, nullptr, 0, &BytesReturned))
210 {
211 WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
212 error = ERROR_INTERNAL_ERROR;
213 break;
214 }
215
216 if (BytesReturned < 1)
217 continue;
218
219 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
220 {
221 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
222 error = CHANNEL_RC_NO_MEMORY;
223 break;
224 }
225
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))
230 {
231 WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
232 error = ERROR_INTERNAL_ERROR;
233 break;
234 }
235
236 if (Stream_GetPosition(s) >= ENCOMSP_ORDER_HEADER_SIZE)
237 {
238 header = Stream_BufferAs(s, ENCOMSP_ORDER_HEADER);
239
240 if (header->Length >= Stream_GetPosition(s))
241 {
242 Stream_SealLength(s);
243 Stream_ResetPosition(s);
244
245 if ((error = encomsp_server_receive_pdu(context, s)))
246 {
247 WLog_ERR(TAG, "encomsp_server_receive_pdu failed with error %" PRIu32 "!",
248 error);
249 break;
250 }
251
252 Stream_ResetPosition(s);
253 }
254 }
255 }
256
257 Stream_Free(s, TRUE);
258out:
259
260 if (error && context->rdpcontext)
261 setChannelError(context->rdpcontext, error, "encomsp_server_thread reported an error");
262
263 ExitThread(error);
264 return error;
265}
266
272static UINT encomsp_server_start(EncomspServerContext* context)
273{
274 context->priv->ChannelHandle =
275 WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, ENCOMSP_SVC_CHANNEL_NAME);
276
277 if (!context->priv->ChannelHandle)
278 return CHANNEL_RC_BAD_CHANNEL;
279
280 if (!(context->priv->StopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
281 {
282 WLog_ERR(TAG, "CreateEvent failed!");
283 return ERROR_INTERNAL_ERROR;
284 }
285
286 if (!(context->priv->Thread =
287 CreateThread(nullptr, 0, encomsp_server_thread, (void*)context, 0, nullptr)))
288 {
289 WLog_ERR(TAG, "CreateThread failed!");
290 (void)CloseHandle(context->priv->StopEvent);
291 context->priv->StopEvent = nullptr;
292 return ERROR_INTERNAL_ERROR;
293 }
294
295 return CHANNEL_RC_OK;
296}
297
303static UINT encomsp_server_stop(EncomspServerContext* context)
304{
305 UINT error = CHANNEL_RC_OK;
306 (void)SetEvent(context->priv->StopEvent);
307
308 if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
309 {
310 error = GetLastError();
311 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
312 return error;
313 }
314
315 (void)CloseHandle(context->priv->Thread);
316 (void)CloseHandle(context->priv->StopEvent);
317 return error;
318}
319
320EncomspServerContext* encomsp_server_context_new(HANDLE vcm)
321{
322 EncomspServerContext* context = nullptr;
323 context = (EncomspServerContext*)calloc(1, sizeof(EncomspServerContext));
324
325 if (context)
326 {
327 context->vcm = vcm;
328 context->Start = encomsp_server_start;
329 context->Stop = encomsp_server_stop;
330 context->priv = (EncomspServerPrivate*)calloc(1, sizeof(EncomspServerPrivate));
331
332 if (!context->priv)
333 {
334 WLog_ERR(TAG, "calloc failed!");
335 free(context);
336 return nullptr;
337 }
338 }
339
340 return context;
341}
342
343void encomsp_server_context_free(EncomspServerContext* context)
344{
345 if (context)
346 {
347 if (context->priv->ChannelHandle != INVALID_HANDLE_VALUE)
348 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
349
350 free(context->priv);
351 free(context);
352 }
353}