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