FreeRDP
Loading...
Searching...
No Matches
channels/client/addin.c
1
22#include <freerdp/config.h>
23
24#include <winpr/crt.h>
25#include <winpr/assert.h>
26#include <winpr/path.h>
27#include <winpr/string.h>
28#include <winpr/file.h>
29#include <winpr/synch.h>
30#include <winpr/library.h>
31#include <winpr/collections.h>
32
33#include <freerdp/freerdp.h>
34#include <freerdp/addin.h>
35#include <freerdp/build-config.h>
36#include <freerdp/client/channels.h>
37
38#include "tables.h"
39
40#include "addin.h"
41
42#include <freerdp/channels/log.h>
43#define TAG CHANNELS_TAG("addin")
44
45extern const STATIC_ENTRY_TABLE CLIENT_STATIC_ENTRY_TABLES[];
46
47static void* freerdp_channels_find_static_entry_in_table(const STATIC_ENTRY_TABLE* table,
48 const char* identifier)
49{
50 size_t index = 0;
51 const STATIC_ENTRY* pEntry = &table->table.cse[index++];
52
53 while (pEntry->entry != nullptr)
54 {
55 static_entry_fn_t fkt = pEntry->entry;
56 if (strcmp(pEntry->name, identifier) == 0)
57 return WINPR_FUNC_PTR_CAST(fkt, void*);
58
59 pEntry = &table->table.cse[index++];
60 }
61
62 return nullptr;
63}
64
65void* freerdp_channels_client_find_static_entry(const char* name, const char* identifier)
66{
67 size_t index = 0;
68 const STATIC_ENTRY_TABLE* pEntry = &CLIENT_STATIC_ENTRY_TABLES[index++];
69
70 while (pEntry->table.cse != nullptr)
71 {
72 if (strcmp(pEntry->name, name) == 0)
73 {
74 return freerdp_channels_find_static_entry_in_table(pEntry, identifier);
75 }
76
77 pEntry = &CLIENT_STATIC_ENTRY_TABLES[index++];
78 }
79
80 return nullptr;
81}
82
83extern const STATIC_ADDIN_TABLE CLIENT_STATIC_ADDIN_TABLE[];
84
85static FREERDP_ADDIN** freerdp_channels_list_client_static_addins(
86 WINPR_ATTR_UNUSED LPCSTR pszName, WINPR_ATTR_UNUSED LPCSTR pszSubsystem,
87 WINPR_ATTR_UNUSED LPCSTR pszType, WINPR_ATTR_UNUSED DWORD dwFlags)
88{
89 DWORD nAddins = 0;
90 FREERDP_ADDIN** ppAddins = nullptr;
91 const STATIC_SUBSYSTEM_ENTRY* subsystems = nullptr;
92 nAddins = 0;
93 ppAddins = (FREERDP_ADDIN**)calloc(128, sizeof(FREERDP_ADDIN*));
94
95 if (!ppAddins)
96 {
97 WLog_ERR(TAG, "calloc failed!");
98 return nullptr;
99 }
100
101 ppAddins[nAddins] = nullptr;
102
103 for (size_t i = 0; CLIENT_STATIC_ADDIN_TABLE[i].name != nullptr; i++)
104 {
105 FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN));
106 const STATIC_ADDIN_TABLE* table = &CLIENT_STATIC_ADDIN_TABLE[i];
107 if (!pAddin)
108 {
109 WLog_ERR(TAG, "calloc failed!");
110 goto error_out;
111 }
112
113 (void)sprintf_s(pAddin->cName, ARRAYSIZE(pAddin->cName), "%s", table->name);
114 pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
115 pAddin->dwFlags |= FREERDP_ADDIN_STATIC;
116 pAddin->dwFlags |= FREERDP_ADDIN_NAME;
117 ppAddins[nAddins++] = pAddin;
118 subsystems = table->table;
119
120 for (size_t j = 0; subsystems[j].name != nullptr; j++)
121 {
122 pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN));
123
124 if (!pAddin)
125 {
126 WLog_ERR(TAG, "calloc failed!");
127 goto error_out;
128 }
129
130 (void)sprintf_s(pAddin->cName, ARRAYSIZE(pAddin->cName), "%s", table->name);
131 (void)sprintf_s(pAddin->cSubsystem, ARRAYSIZE(pAddin->cSubsystem), "%s",
132 subsystems[j].name);
133 pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
134 pAddin->dwFlags |= FREERDP_ADDIN_STATIC;
135 pAddin->dwFlags |= FREERDP_ADDIN_NAME;
136 pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
137 ppAddins[nAddins++] = pAddin;
138 }
139 }
140
141 return ppAddins;
142error_out:
143 freerdp_channels_addin_list_free(ppAddins);
144 return nullptr;
145}
146
147static HANDLE FindFirstFileUTF8(LPCSTR pszSearchPath, WIN32_FIND_DATAW* FindData)
148{
149 HANDLE hdl = INVALID_HANDLE_VALUE;
150 if (!pszSearchPath)
151 return hdl;
152 WCHAR* wpath = ConvertUtf8ToWCharAlloc(pszSearchPath, nullptr);
153 if (!wpath)
154 return hdl;
155
156 hdl = FindFirstFileW(wpath, FindData);
157 free(wpath);
158
159 return hdl;
160}
161
162static FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPCSTR pszName, LPCSTR pszSubsystem,
163 LPCSTR pszType,
164 WINPR_ATTR_UNUSED DWORD dwFlags)
165{
166 int nDashes = 0;
167 LPCSTR pszAddinPath = FREERDP_ADDIN_PATH;
168 LPCSTR pszInstallPrefix = FREERDP_INSTALL_PREFIX;
169 const size_t cchAddinPath = strnlen(pszAddinPath, sizeof(FREERDP_ADDIN_PATH));
170 const size_t cchInstallPrefix = strnlen(pszInstallPrefix, sizeof(FREERDP_INSTALL_PREFIX));
171 const char* pszExtension = PathGetSharedLibraryExtensionA(0);
172 const size_t cchPattern = 128 + strnlen(pszExtension, MAX_PATH) + 2;
173 char* pszPattern = calloc(cchPattern + 1, sizeof(char));
174
175 if (!pszPattern)
176 {
177 WLog_ERR(TAG, "malloc failed!");
178 return nullptr;
179 }
180
181 if (pszName && pszSubsystem && pszType)
182 {
183 (void)sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "%s-client-%s-%s.%s",
184 pszName, pszSubsystem, pszType, pszExtension);
185 }
186 else if (pszName && pszType)
187 {
188 (void)sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "%s-client-?-%s.%s",
189 pszName, pszType, pszExtension);
190 }
191 else if (pszName)
192 {
193 (void)sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "%s-client*.%s",
194 pszName, pszExtension);
195 }
196 else
197 {
198 (void)sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "?-client*.%s",
199 pszExtension);
200 }
201
202 const size_t cchPattern2 = strnlen(pszPattern, cchPattern);
203 const size_t cchSearchPath = cchInstallPrefix + cchAddinPath + cchPattern2 + 3;
204 char* pszSearchPath = calloc(cchSearchPath + 1, sizeof(char));
205
206 if (!pszSearchPath)
207 {
208 WLog_ERR(TAG, "malloc failed!");
209 free(pszPattern);
210 return nullptr;
211 }
212
213 CopyMemory(pszSearchPath, pszInstallPrefix, cchInstallPrefix);
214 pszSearchPath[cchInstallPrefix] = '\0';
215
216 char* result = GetCombinedPathV(pszSearchPath, "%s%c%s", pszAddinPath,
217 PathGetSeparatorA(PATH_STYLE_NATIVE), pszPattern);
218 free(pszPattern);
219 free(pszSearchPath);
220
221 if (!result)
222 return nullptr;
223
224 WIN32_FIND_DATAW FindData = WINPR_C_ARRAY_INIT;
225 HANDLE hFind = FindFirstFileUTF8(result, &FindData);
226 free(result);
227
228 DWORD nAddins = 0;
229 FREERDP_ADDIN** ppAddins = (FREERDP_ADDIN**)calloc(128, sizeof(FREERDP_ADDIN*));
230
231 if (!ppAddins)
232 {
233 FindClose(hFind);
234 WLog_ERR(TAG, "calloc failed!");
235 return nullptr;
236 }
237
238 if (hFind == INVALID_HANDLE_VALUE)
239 return ppAddins;
240
241 do
242 {
243 char* cFileName = nullptr;
244 BOOL used = FALSE;
245 FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN));
246
247 if (!pAddin)
248 {
249 WLog_ERR(TAG, "calloc failed!");
250 goto error_out;
251 }
252
253 cFileName =
254 ConvertWCharNToUtf8Alloc(FindData.cFileName, ARRAYSIZE(FindData.cFileName), nullptr);
255 if (!cFileName)
256 goto skip;
257
258 nDashes = 0;
259 for (size_t index = 0; cFileName[index]; index++)
260 nDashes += (cFileName[index] == '-') ? 1 : 0;
261
262 if (nDashes == 1)
263 {
264 size_t len = 0;
265 char* p[2] = WINPR_C_ARRAY_INIT;
266 /* <name>-client.<extension> */
267 p[0] = cFileName;
268 p[1] = strchr(p[0], '-');
269 if (!p[1])
270 goto skip;
271 p[1] += 1;
272
273 len = (size_t)(p[1] - p[0]);
274 if (len < 1)
275 {
276 WLog_WARN(TAG, "Skipping file '%s', invalid format", cFileName);
277 goto skip;
278 }
279 strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1));
280
281 pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
282 pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
283 pAddin->dwFlags |= FREERDP_ADDIN_NAME;
284 ppAddins[nAddins++] = pAddin;
285
286 used = TRUE;
287 }
288 else if (nDashes == 2)
289 {
290 size_t len = 0;
291 char* p[4] = WINPR_C_ARRAY_INIT;
292 /* <name>-client-<subsystem>.<extension> */
293 p[0] = cFileName;
294 p[1] = strchr(p[0], '-');
295 if (!p[1])
296 goto skip;
297 p[1] += 1;
298 p[2] = strchr(p[1], '-');
299 if (!p[2])
300 goto skip;
301 p[2] += 1;
302 p[3] = strchr(p[2], '.');
303 if (!p[3])
304 goto skip;
305 p[3] += 1;
306
307 len = (size_t)(p[1] - p[0]);
308 if (len < 1)
309 {
310 WLog_WARN(TAG, "Skipping file '%s', invalid format", cFileName);
311 goto skip;
312 }
313 strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1));
314
315 len = (size_t)(p[3] - p[2]);
316 if (len < 1)
317 {
318 WLog_WARN(TAG, "Skipping file '%s', invalid format", cFileName);
319 goto skip;
320 }
321 strncpy(pAddin->cSubsystem, p[2], MIN(ARRAYSIZE(pAddin->cSubsystem), len - 1));
322
323 pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
324 pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
325 pAddin->dwFlags |= FREERDP_ADDIN_NAME;
326 pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
327 ppAddins[nAddins++] = pAddin;
328
329 used = TRUE;
330 }
331 else if (nDashes == 3)
332 {
333 size_t len = 0;
334 char* p[5] = WINPR_C_ARRAY_INIT;
335 /* <name>-client-<subsystem>-<type>.<extension> */
336 p[0] = cFileName;
337 p[1] = strchr(p[0], '-');
338 if (!p[1])
339 goto skip;
340 p[1] += 1;
341 p[2] = strchr(p[1], '-');
342 if (!p[2])
343 goto skip;
344 p[2] += 1;
345 p[3] = strchr(p[2], '-');
346 if (!p[3])
347 goto skip;
348 p[3] += 1;
349 p[4] = strchr(p[3], '.');
350 if (!p[4])
351 goto skip;
352 p[4] += 1;
353
354 len = (size_t)(p[1] - p[0]);
355 if (len < 1)
356 {
357 WLog_WARN(TAG, "Skipping file '%s', invalid format", cFileName);
358 goto skip;
359 }
360 strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1));
361
362 len = (size_t)(p[3] - p[2]);
363 if (len < 1)
364 {
365 WLog_WARN(TAG, "Skipping file '%s', invalid format", cFileName);
366 goto skip;
367 }
368 strncpy(pAddin->cSubsystem, p[2], MIN(ARRAYSIZE(pAddin->cSubsystem), len - 1));
369
370 len = (size_t)(p[4] - p[3]);
371 if (len < 1)
372 {
373 WLog_WARN(TAG, "Skipping file '%s', invalid format", cFileName);
374 goto skip;
375 }
376 strncpy(pAddin->cType, p[3], MIN(ARRAYSIZE(pAddin->cType), len - 1));
377
378 pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
379 pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
380 pAddin->dwFlags |= FREERDP_ADDIN_NAME;
381 pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
382 pAddin->dwFlags |= FREERDP_ADDIN_TYPE;
383 ppAddins[nAddins++] = pAddin;
384
385 used = TRUE;
386 }
387
388 skip:
389 free(cFileName);
390 if (!used)
391 free(pAddin);
392
393 } while (FindNextFileW(hFind, &FindData));
394
395 FindClose(hFind);
396 ppAddins[nAddins] = nullptr;
397 return ppAddins;
398error_out:
399 FindClose(hFind);
400 freerdp_channels_addin_list_free(ppAddins);
401 return nullptr;
402}
403
404FREERDP_ADDIN** freerdp_channels_list_addins(LPCSTR pszName, LPCSTR pszSubsystem, LPCSTR pszType,
405 DWORD dwFlags)
406{
407 if (dwFlags & FREERDP_ADDIN_STATIC)
408 return freerdp_channels_list_client_static_addins(pszName, pszSubsystem, pszType, dwFlags);
409 else if (dwFlags & FREERDP_ADDIN_DYNAMIC)
410 return freerdp_channels_list_dynamic_addins(pszName, pszSubsystem, pszType, dwFlags);
411
412 return nullptr;
413}
414
415void freerdp_channels_addin_list_free(FREERDP_ADDIN** ppAddins)
416{
417 if (!ppAddins)
418 return;
419
420 for (size_t index = 0; ppAddins[index] != nullptr; index++)
421 free(ppAddins[index]);
422
423 free((void*)ppAddins);
424}
425
426extern const STATIC_ENTRY CLIENT_VirtualChannelEntryEx_TABLE[];
427
428static BOOL freerdp_channels_is_virtual_channel_entry_ex(LPCSTR pszName)
429{
430 for (size_t i = 0; CLIENT_VirtualChannelEntryEx_TABLE[i].name != nullptr; i++)
431 {
432 const STATIC_ENTRY* entry = &CLIENT_VirtualChannelEntryEx_TABLE[i];
433
434 if (!strncmp(entry->name, pszName, MAX_PATH))
435 return TRUE;
436 }
437
438 return FALSE;
439}
440
441PVIRTUALCHANNELENTRY freerdp_channels_load_static_addin_entry(LPCSTR pszName, LPCSTR pszSubsystem,
442 LPCSTR pszType, DWORD dwFlags)
443{
444 const STATIC_ADDIN_TABLE* table = CLIENT_STATIC_ADDIN_TABLE;
445 const char* type = nullptr;
446
447 if (!pszName)
448 return nullptr;
449
450 if (dwFlags & FREERDP_ADDIN_CHANNEL_DYNAMIC)
451 type = "DVCPluginEntry";
452 else if (dwFlags & FREERDP_ADDIN_CHANNEL_DEVICE)
453 type = "DeviceServiceEntry";
454 else if (dwFlags & FREERDP_ADDIN_CHANNEL_STATIC)
455 {
456 if (dwFlags & FREERDP_ADDIN_CHANNEL_ENTRYEX)
457 type = "VirtualChannelEntryEx";
458 else
459 type = "VirtualChannelEntry";
460 }
461
462 for (; table->name != nullptr; table++)
463 {
464 if (strncmp(table->name, pszName, MAX_PATH) == 0)
465 {
466 if (type && (strncmp(table->type, type, MAX_PATH) != 0))
467 continue;
468
469 if (pszSubsystem != nullptr)
470 {
471 const STATIC_SUBSYSTEM_ENTRY* subsystems = table->table;
472
473 for (; subsystems->name != nullptr; subsystems++)
474 {
475 /* If the pszSubsystem is an empty string use the default backend. */
476 if ((strnlen(pszSubsystem, 1) ==
477 0) || /* we only want to know if strnlen is > 0 */
478 (strncmp(subsystems->name, pszSubsystem, MAX_PATH) == 0))
479 {
480 static_subsystem_entry_fn_t fkt = subsystems->entry;
481
482 if (pszType)
483 {
484 if (strncmp(subsystems->type, pszType, MAX_PATH) == 0)
485 return WINPR_FUNC_PTR_CAST(fkt, PVIRTUALCHANNELENTRY);
486 }
487 else
488 return WINPR_FUNC_PTR_CAST(fkt, PVIRTUALCHANNELENTRY);
489 }
490 }
491 }
492 else
493 {
494 if (dwFlags & FREERDP_ADDIN_CHANNEL_ENTRYEX)
495 {
496 if (!freerdp_channels_is_virtual_channel_entry_ex(pszName))
497 return nullptr;
498 }
499
500 return table->entry.csevc;
501 }
502 }
503 }
504
505 return nullptr;
506}
507
508typedef struct
509{
510 wMessageQueue* queue;
511 wStream* data_in;
512 HANDLE thread;
513 char* channel_name;
514 rdpContext* ctx;
515 LPVOID userdata;
516 MsgHandler msg_handler;
517 BOOL firstFlagReceived;
518 UINT32 totalLength;
519} msg_proc_internals;
520
521static DWORD WINAPI channel_client_thread_proc(LPVOID userdata)
522{
523 UINT error = CHANNEL_RC_OK;
524 wStream* data = nullptr;
525 wMessage message = WINPR_C_ARRAY_INIT;
526 msg_proc_internals* internals = userdata;
527
528 WINPR_ASSERT(internals);
529
530 while (1)
531 {
532 if (!MessageQueue_Wait(internals->queue))
533 {
534 WLog_ERR(TAG, "MessageQueue_Wait failed!");
535 error = ERROR_INTERNAL_ERROR;
536 break;
537 }
538 if (!MessageQueue_Peek(internals->queue, &message, TRUE))
539 {
540 WLog_ERR(TAG, "MessageQueue_Peek failed!");
541 error = ERROR_INTERNAL_ERROR;
542 break;
543 }
544
545 if (message.id == WMQ_QUIT)
546 break;
547
548 if (message.id == 0)
549 {
550 data = (wStream*)message.wParam;
551
552 if ((error = internals->msg_handler(internals->userdata, data)))
553 {
554 WLog_ERR(TAG, "msg_handler failed with error %" PRIu32 "!", error);
555 break;
556 }
557 }
558 }
559 if (error && internals->ctx)
560 {
561 char msg[128];
562 (void)_snprintf(msg, 127,
563 "%s_virtual_channel_client_thread reported an"
564 " error",
565 internals->channel_name);
566 setChannelError(internals->ctx, error, msg);
567 }
568 ExitThread(error);
569 return error;
570}
571
572static void free_msg(void* obj)
573{
574 wMessage* msg = (wMessage*)obj;
575
576 if (msg && (msg->id == 0))
577 {
578 wStream* s = (wStream*)msg->wParam;
579 Stream_Free(s, TRUE);
580 }
581}
582
583static void channel_client_handler_free(msg_proc_internals* internals)
584{
585 if (!internals)
586 return;
587
588 if (internals->thread)
589 (void)CloseHandle(internals->thread);
590 MessageQueue_Free(internals->queue);
591 Stream_Free(internals->data_in, TRUE);
592 free(internals->channel_name);
593 free(internals);
594}
595
596/* Create message queue and thread or not, depending on settings */
597void* channel_client_create_handler(rdpContext* ctx, LPVOID userdata, MsgHandler msg_handler,
598 const char* channel_name)
599{
600 msg_proc_internals* internals = calloc(1, sizeof(msg_proc_internals));
601 if (!internals)
602 {
603 WLog_ERR(TAG, "calloc failed!");
604 return nullptr;
605 }
606 internals->msg_handler = msg_handler;
607 internals->userdata = userdata;
608 if (channel_name)
609 {
610 internals->channel_name = _strdup(channel_name);
611 if (!internals->channel_name)
612 goto fail;
613 }
614 WINPR_ASSERT(ctx);
615 WINPR_ASSERT(ctx->settings);
616 internals->ctx = ctx;
617 if ((freerdp_settings_get_uint32(ctx->settings, FreeRDP_ThreadingFlags) &
618 THREADING_FLAGS_DISABLE_THREADS) == 0)
619 {
620 wObject obj = WINPR_C_ARRAY_INIT;
621 obj.fnObjectFree = free_msg;
622 internals->queue = MessageQueue_New(&obj);
623 if (!internals->queue)
624 {
625 WLog_ERR(TAG, "MessageQueue_New failed!");
626 goto fail;
627 }
628
629 if (!(internals->thread = CreateThread(nullptr, 0, channel_client_thread_proc,
630 (void*)internals, 0, nullptr)))
631 {
632 WLog_ERR(TAG, "CreateThread failed!");
633 goto fail;
634 }
635 }
636 return internals;
637
638fail:
639 channel_client_handler_free(internals);
640 return nullptr;
641}
642/* post a message in the queue or directly call the processing handler */
643UINT channel_client_post_message(void* MsgsHandle, LPVOID pData, UINT32 dataLength,
644 UINT32 totalLength, UINT32 dataFlags)
645{
646 msg_proc_internals* internals = MsgsHandle;
647 wStream* data_in = nullptr;
648
649 if (!internals)
650 {
651 /* TODO: return some error here */
652 return CHANNEL_RC_OK;
653 }
654
655 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
656 {
657 return CHANNEL_RC_OK;
658 }
659
660 if (dataFlags & CHANNEL_FLAG_FIRST)
661 {
662 if (internals->firstFlagReceived)
663 return ERROR_INVALID_DATA;
664 internals->firstFlagReceived = TRUE;
665
666 if (internals->data_in)
667 {
668 if (!Stream_EnsureCapacity(internals->data_in, dataLength))
669 return CHANNEL_RC_NO_MEMORY;
670 }
671 else
672 internals->data_in = Stream_New(nullptr, dataLength);
673 internals->totalLength = totalLength;
674 }
675
676 if (!(data_in = internals->data_in))
677 {
678 WLog_ERR(TAG, "Stream_New failed!");
679 return CHANNEL_RC_NO_MEMORY;
680 }
681
682 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
683 {
684 Stream_Free(internals->data_in, TRUE);
685 internals->data_in = nullptr;
686 return CHANNEL_RC_NO_MEMORY;
687 }
688
689 Stream_Write(data_in, pData, dataLength);
690
691 if ((Stream_GetPosition(data_in) > totalLength) || (internals->totalLength != totalLength))
692 {
693 Stream_Free(internals->data_in, TRUE);
694 internals->data_in = nullptr;
695 return ERROR_INVALID_DATA;
696 }
697
698 if (dataFlags & CHANNEL_FLAG_LAST)
699 {
700 if (!internals->firstFlagReceived)
701 return ERROR_INVALID_DATA;
702 internals->firstFlagReceived = FALSE;
703
704 if (!data_in)
705 return ERROR_INVALID_DATA;
706
707 if (internals->totalLength != Stream_GetPosition(data_in))
708 {
709 WLog_ERR(TAG, "%s_plugin_process_received: read error", internals->channel_name);
710 return ERROR_INTERNAL_ERROR;
711 }
712
713 internals->totalLength = 0;
714 internals->data_in = nullptr;
715 Stream_SealLength(data_in);
716 Stream_ResetPosition(data_in);
717
718 if ((freerdp_settings_get_uint32(internals->ctx->settings, FreeRDP_ThreadingFlags) &
719 THREADING_FLAGS_DISABLE_THREADS) != 0)
720 {
721 UINT error = CHANNEL_RC_OK;
722 if ((error = internals->msg_handler(internals->userdata, data_in)))
723 {
724 WLog_ERR(TAG,
725 "msg_handler failed with error"
726 " %" PRIu32 "!",
727 error);
728 return ERROR_INTERNAL_ERROR;
729 }
730 }
731 else if (!MessageQueue_Post(internals->queue, nullptr, 0, (void*)data_in, nullptr))
732 {
733 WLog_ERR(TAG, "MessageQueue_Post failed!");
734 return ERROR_INTERNAL_ERROR;
735 }
736 }
737 return CHANNEL_RC_OK;
738}
739/* Tear down queue and thread */
740UINT channel_client_quit_handler(void* MsgsHandle)
741{
742 msg_proc_internals* internals = MsgsHandle;
743 UINT rc = 0;
744 if (!internals)
745 {
746 /* TODO: return some error here */
747 return CHANNEL_RC_OK;
748 }
749
750 WINPR_ASSERT(internals->ctx);
751 WINPR_ASSERT(internals->ctx->settings);
752
753 if ((freerdp_settings_get_uint32(internals->ctx->settings, FreeRDP_ThreadingFlags) &
754 THREADING_FLAGS_DISABLE_THREADS) == 0)
755 {
756 if (internals->queue && internals->thread)
757 {
758 if (MessageQueue_PostQuit(internals->queue, 0) &&
759 (WaitForSingleObject(internals->thread, INFINITE) == WAIT_FAILED))
760 {
761 rc = GetLastError();
762 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
763 return rc;
764 }
765 }
766 }
767
768 channel_client_handler_free(internals);
769 return CHANNEL_RC_OK;
770}
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
Definition tables.h:86
Definition tables.h:34
Definition tables.h:93
This struct contains function pointer to initialize/free objects.
Definition collections.h:52
OBJECT_FREE_FN fnObjectFree
Definition collections.h:59