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} msg_proc_internals;
518
519static DWORD WINAPI channel_client_thread_proc(LPVOID userdata)
520{
521 UINT error = CHANNEL_RC_OK;
522 wStream* data = nullptr;
523 wMessage message = WINPR_C_ARRAY_INIT;
524 msg_proc_internals* internals = userdata;
525
526 WINPR_ASSERT(internals);
527
528 while (1)
529 {
530 if (!MessageQueue_Wait(internals->queue))
531 {
532 WLog_ERR(TAG, "MessageQueue_Wait failed!");
533 error = ERROR_INTERNAL_ERROR;
534 break;
535 }
536 if (!MessageQueue_Peek(internals->queue, &message, TRUE))
537 {
538 WLog_ERR(TAG, "MessageQueue_Peek failed!");
539 error = ERROR_INTERNAL_ERROR;
540 break;
541 }
542
543 if (message.id == WMQ_QUIT)
544 break;
545
546 if (message.id == 0)
547 {
548 data = (wStream*)message.wParam;
549
550 if ((error = internals->msg_handler(internals->userdata, data)))
551 {
552 WLog_ERR(TAG, "msg_handler failed with error %" PRIu32 "!", error);
553 break;
554 }
555 }
556 }
557 if (error && internals->ctx)
558 {
559 char msg[128];
560 (void)_snprintf(msg, 127,
561 "%s_virtual_channel_client_thread reported an"
562 " error",
563 internals->channel_name);
564 setChannelError(internals->ctx, error, msg);
565 }
566 ExitThread(error);
567 return error;
568}
569
570static void free_msg(void* obj)
571{
572 wMessage* msg = (wMessage*)obj;
573
574 if (msg && (msg->id == 0))
575 {
576 wStream* s = (wStream*)msg->wParam;
577 Stream_Free(s, TRUE);
578 }
579}
580
581static void channel_client_handler_free(msg_proc_internals* internals)
582{
583 if (!internals)
584 return;
585
586 if (internals->thread)
587 (void)CloseHandle(internals->thread);
588 MessageQueue_Free(internals->queue);
589 Stream_Free(internals->data_in, TRUE);
590 free(internals->channel_name);
591 free(internals);
592}
593
594/* Create message queue and thread or not, depending on settings */
595void* channel_client_create_handler(rdpContext* ctx, LPVOID userdata, MsgHandler msg_handler,
596 const char* channel_name)
597{
598 msg_proc_internals* internals = calloc(1, sizeof(msg_proc_internals));
599 if (!internals)
600 {
601 WLog_ERR(TAG, "calloc failed!");
602 return nullptr;
603 }
604 internals->msg_handler = msg_handler;
605 internals->userdata = userdata;
606 if (channel_name)
607 {
608 internals->channel_name = _strdup(channel_name);
609 if (!internals->channel_name)
610 goto fail;
611 }
612 WINPR_ASSERT(ctx);
613 WINPR_ASSERT(ctx->settings);
614 internals->ctx = ctx;
615 if ((freerdp_settings_get_uint32(ctx->settings, FreeRDP_ThreadingFlags) &
616 THREADING_FLAGS_DISABLE_THREADS) == 0)
617 {
618 wObject obj = WINPR_C_ARRAY_INIT;
619 obj.fnObjectFree = free_msg;
620 internals->queue = MessageQueue_New(&obj);
621 if (!internals->queue)
622 {
623 WLog_ERR(TAG, "MessageQueue_New failed!");
624 goto fail;
625 }
626
627 if (!(internals->thread = CreateThread(nullptr, 0, channel_client_thread_proc,
628 (void*)internals, 0, nullptr)))
629 {
630 WLog_ERR(TAG, "CreateThread failed!");
631 goto fail;
632 }
633 }
634 return internals;
635
636fail:
637 channel_client_handler_free(internals);
638 return nullptr;
639}
640/* post a message in the queue or directly call the processing handler */
641UINT channel_client_post_message(void* MsgsHandle, LPVOID pData, UINT32 dataLength,
642 UINT32 totalLength, UINT32 dataFlags)
643{
644 msg_proc_internals* internals = MsgsHandle;
645 wStream* data_in = nullptr;
646
647 if (!internals)
648 {
649 /* TODO: return some error here */
650 return CHANNEL_RC_OK;
651 }
652
653 if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
654 {
655 return CHANNEL_RC_OK;
656 }
657
658 if (dataFlags & CHANNEL_FLAG_FIRST)
659 {
660 if (internals->data_in)
661 {
662 if (!Stream_EnsureCapacity(internals->data_in, totalLength))
663 return CHANNEL_RC_NO_MEMORY;
664 }
665 else
666 internals->data_in = Stream_New(nullptr, totalLength);
667 }
668
669 if (!(data_in = internals->data_in))
670 {
671 WLog_ERR(TAG, "Stream_New failed!");
672 return CHANNEL_RC_NO_MEMORY;
673 }
674
675 if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
676 {
677 Stream_Free(internals->data_in, TRUE);
678 internals->data_in = nullptr;
679 return CHANNEL_RC_NO_MEMORY;
680 }
681
682 Stream_Write(data_in, pData, dataLength);
683
684 if (dataFlags & CHANNEL_FLAG_LAST)
685 {
686 if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
687 {
688 WLog_ERR(TAG, "%s_plugin_process_received: read error", internals->channel_name);
689 return ERROR_INTERNAL_ERROR;
690 }
691
692 internals->data_in = nullptr;
693 Stream_SealLength(data_in);
694 Stream_ResetPosition(data_in);
695
696 if ((freerdp_settings_get_uint32(internals->ctx->settings, FreeRDP_ThreadingFlags) &
697 THREADING_FLAGS_DISABLE_THREADS) != 0)
698 {
699 UINT error = CHANNEL_RC_OK;
700 if ((error = internals->msg_handler(internals->userdata, data_in)))
701 {
702 WLog_ERR(TAG,
703 "msg_handler failed with error"
704 " %" PRIu32 "!",
705 error);
706 return ERROR_INTERNAL_ERROR;
707 }
708 }
709 else if (!MessageQueue_Post(internals->queue, nullptr, 0, (void*)data_in, nullptr))
710 {
711 WLog_ERR(TAG, "MessageQueue_Post failed!");
712 return ERROR_INTERNAL_ERROR;
713 }
714 }
715 return CHANNEL_RC_OK;
716}
717/* Tear down queue and thread */
718UINT channel_client_quit_handler(void* MsgsHandle)
719{
720 msg_proc_internals* internals = MsgsHandle;
721 UINT rc = 0;
722 if (!internals)
723 {
724 /* TODO: return some error here */
725 return CHANNEL_RC_OK;
726 }
727
728 WINPR_ASSERT(internals->ctx);
729 WINPR_ASSERT(internals->ctx->settings);
730
731 if ((freerdp_settings_get_uint32(internals->ctx->settings, FreeRDP_ThreadingFlags) &
732 THREADING_FLAGS_DISABLE_THREADS) == 0)
733 {
734 if (internals->queue && internals->thread)
735 {
736 if (MessageQueue_PostQuit(internals->queue, 0) &&
737 (WaitForSingleObject(internals->thread, INFINITE) == WAIT_FAILED))
738 {
739 rc = GetLastError();
740 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
741 return rc;
742 }
743 }
744 }
745
746 channel_client_handler_free(internals);
747 return CHANNEL_RC_OK;
748}
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