Coverage Report

Created: 2026-05-11 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/core/client.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Client Channels
4
 *
5
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2015 Thincast Technologies GmbH
7
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
22
#include <freerdp/config.h>
23
24
#include "settings.h"
25
26
#include <winpr/assert.h>
27
28
#include <freerdp/log.h>
29
#include <freerdp/channels/drdynvc.h>
30
31
#include "rdp.h"
32
#include "client.h"
33
34
#define TAG FREERDP_TAG("core.client")
35
36
typedef struct
37
{
38
  freerdp_channel_handle_fkt_t fkt;
39
  void* userdata;
40
} ChannelEventEntry;
41
42
/* Use this instance to get access to channels in VirtualChannelInit. It is set during
43
 * freerdp_connect so channels that use VirtualChannelInit must be initialized from the same thread
44
 * as freerdp_connect was called */
45
static WINPR_TLS freerdp* g_Instance = nullptr;
46
47
/* use global counter to ensure uniqueness across channel manager instances */
48
static volatile LONG g_OpenHandleSeq = 1;
49
50
/* HashTable mapping channel handles to CHANNEL_OPEN_DATA */
51
static INIT_ONCE g_ChannelHandlesOnce = INIT_ONCE_STATIC_INIT;
52
static wHashTable* g_ChannelHandles = nullptr;
53
54
static BOOL freerdp_channels_process_message_free(wMessage* message, DWORD type);
55
56
static CHANNEL_OPEN_DATA* freerdp_channels_find_channel_open_data_by_name(rdpChannels* channels,
57
                                                                          const char* name)
58
0
{
59
0
  for (int index = 0; index < channels->openDataCount; index++)
60
0
  {
61
0
    CHANNEL_OPEN_DATA* pChannelOpenData = &channels->openDataList[index];
62
63
0
    if (strncmp(name, pChannelOpenData->name, CHANNEL_NAME_LEN + 1) == 0)
64
0
      return pChannelOpenData;
65
0
  }
66
67
0
  return nullptr;
68
0
}
69
70
/* returns rdpChannel for the channel name passed in */
71
static rdpMcsChannel* freerdp_channels_find_channel_by_name(rdpRdp* rdp, const char* name)
72
0
{
73
0
  rdpMcs* mcs = nullptr;
74
75
0
  if (!rdp)
76
0
    return nullptr;
77
78
0
  mcs = rdp->mcs;
79
80
0
  for (UINT32 index = 0; index < mcs->channelCount; index++)
81
0
  {
82
0
    rdpMcsChannel* channel = &mcs->channels[index];
83
84
0
    if (strncmp(name, channel->Name, CHANNEL_NAME_LEN + 1) == 0)
85
0
    {
86
0
      return channel;
87
0
    }
88
0
  }
89
90
0
  return nullptr;
91
0
}
92
93
static rdpMcsChannel* freerdp_channels_find_channel_by_id(rdpRdp* rdp, UINT16 channel_id)
94
0
{
95
0
  rdpMcsChannel* channel = nullptr;
96
0
  rdpMcs* mcs = nullptr;
97
98
0
  if (!rdp)
99
0
    return nullptr;
100
101
0
  mcs = rdp->mcs;
102
103
0
  for (UINT32 index = 0; index < mcs->channelCount; index++)
104
0
  {
105
0
    channel = &mcs->channels[index];
106
107
0
    if (channel->ChannelId == channel_id)
108
0
    {
109
0
      return channel;
110
0
    }
111
0
  }
112
113
0
  return nullptr;
114
0
}
115
116
static void channel_queue_message_free(wMessage* msg)
117
0
{
118
0
  CHANNEL_OPEN_EVENT* ev = nullptr;
119
120
0
  if (!msg || (msg->id != 0))
121
0
    return;
122
123
0
  ev = (CHANNEL_OPEN_EVENT*)msg->wParam;
124
0
  free(ev);
125
0
}
126
127
static void channel_queue_free(void* obj)
128
0
{
129
0
  wMessage* msg = (wMessage*)obj;
130
0
  freerdp_channels_process_message_free(msg, CHANNEL_EVENT_WRITE_CANCELLED);
131
0
  channel_queue_message_free(msg);
132
0
}
133
134
static BOOL CALLBACK init_channel_handles_table(WINPR_ATTR_UNUSED PINIT_ONCE once,
135
                                                WINPR_ATTR_UNUSED PVOID param,
136
                                                WINPR_ATTR_UNUSED PVOID* context)
137
1
{
138
1
  g_ChannelHandles = HashTable_New(TRUE);
139
1
  return TRUE;
140
1
}
141
142
static void* channel_event_entry_clone(const void* data)
143
0
{
144
0
  const ChannelEventEntry* entry = data;
145
0
  if (!entry)
146
0
    return nullptr;
147
148
0
  ChannelEventEntry* copy = calloc(1, sizeof(ChannelEventEntry));
149
0
  if (!copy)
150
0
    return nullptr;
151
0
  *copy = *entry;
152
0
  return copy;
153
0
}
154
155
rdpChannels* freerdp_channels_new(freerdp* instance)
156
9.36k
{
157
9.36k
  if (!InitOnceExecuteOnce(&g_ChannelHandlesOnce, init_channel_handles_table, nullptr, nullptr))
158
0
    return nullptr;
159
160
9.36k
  wObject* obj = nullptr;
161
9.36k
  rdpChannels* channels = nullptr;
162
9.36k
  channels = (rdpChannels*)calloc(1, sizeof(rdpChannels));
163
164
9.36k
  if (!channels)
165
0
    return nullptr;
166
167
9.36k
  if (!g_ChannelHandles)
168
0
    goto error;
169
9.36k
  if (!InitializeCriticalSectionAndSpinCount(&channels->channelsLock, 4000))
170
0
    goto error;
171
172
9.36k
  channels->instance = instance;
173
9.36k
  channels->queue = MessageQueue_New(nullptr);
174
175
9.36k
  if (!channels->queue)
176
0
    goto error;
177
178
9.36k
  obj = MessageQueue_Object(channels->queue);
179
9.36k
  obj->fnObjectFree = channel_queue_free;
180
181
9.36k
  channels->channelEvents = HashTable_New(FALSE);
182
9.36k
  if (!channels->channelEvents)
183
0
    goto error;
184
185
9.36k
  obj = HashTable_ValueObject(channels->channelEvents);
186
9.36k
  WINPR_ASSERT(obj);
187
9.36k
  obj->fnObjectFree = free;
188
9.36k
  obj->fnObjectNew = channel_event_entry_clone;
189
9.36k
  return channels;
190
0
error:
191
0
  WINPR_PRAGMA_DIAG_PUSH
192
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
193
0
  freerdp_channels_free(channels);
194
0
  WINPR_PRAGMA_DIAG_POP
195
0
  return nullptr;
196
9.36k
}
197
198
void freerdp_channels_free(rdpChannels* channels)
199
9.36k
{
200
9.36k
  if (!channels)
201
0
    return;
202
203
9.36k
  HashTable_Free(channels->channelEvents);
204
205
9.36k
  DeleteCriticalSection(&channels->channelsLock);
206
207
9.36k
  if (channels->queue)
208
9.36k
  {
209
9.36k
    MessageQueue_Free(channels->queue);
210
9.36k
    channels->queue = nullptr;
211
9.36k
  }
212
213
9.36k
  free(channels);
214
9.36k
}
215
216
/**
217
 * Function description
218
 *
219
 * @return 0 on success, otherwise a Win32 error code
220
 */
221
static UINT freerdp_drdynvc_on_channel_connected(DrdynvcClientContext* context, const char* name,
222
                                                 void* pInterface)
223
0
{
224
0
  UINT status = CHANNEL_RC_OK;
225
0
  ChannelConnectedEventArgs e = WINPR_C_ARRAY_INIT;
226
227
0
  WINPR_ASSERT(context);
228
229
0
  rdpChannels* channels = (rdpChannels*)context->custom;
230
0
  WINPR_ASSERT(channels);
231
232
0
  freerdp* instance = channels->instance;
233
0
  WINPR_ASSERT(instance);
234
0
  WINPR_ASSERT(instance->context);
235
236
0
  EventArgsInit(&e, "freerdp");
237
0
  e.name = name;
238
0
  e.pInterface = pInterface;
239
0
  if (PubSub_OnChannelConnected(instance->context->pubSub, instance->context, &e) < 0)
240
0
    return ERROR_INTERNAL_ERROR;
241
0
  return status;
242
0
}
243
244
/**
245
 * Function description
246
 *
247
 * @return 0 on success, otherwise a Win32 error code
248
 */
249
static UINT freerdp_drdynvc_on_channel_disconnected(DrdynvcClientContext* context, const char* name,
250
                                                    void* pInterface)
251
0
{
252
0
  UINT status = CHANNEL_RC_OK;
253
0
  ChannelDisconnectedEventArgs e = WINPR_C_ARRAY_INIT;
254
255
0
  WINPR_ASSERT(context);
256
0
  rdpChannels* channels = (rdpChannels*)context->custom;
257
0
  WINPR_ASSERT(channels);
258
259
0
  freerdp* instance = channels->instance;
260
0
  WINPR_ASSERT(instance);
261
0
  WINPR_ASSERT(instance->context);
262
263
0
  EventArgsInit(&e, "freerdp");
264
0
  e.name = name;
265
0
  e.pInterface = pInterface;
266
0
  if (PubSub_OnChannelDisconnected(instance->context->pubSub, instance->context, &e) < 0)
267
0
    return ERROR_INTERNAL_ERROR;
268
0
  return status;
269
0
}
270
271
static UINT freerdp_drdynvc_on_channel_attached(DrdynvcClientContext* context, const char* name,
272
                                                void* pInterface)
273
0
{
274
0
  UINT status = CHANNEL_RC_OK;
275
0
  ChannelAttachedEventArgs e = WINPR_C_ARRAY_INIT;
276
277
0
  WINPR_ASSERT(context);
278
0
  rdpChannels* channels = (rdpChannels*)context->custom;
279
0
  WINPR_ASSERT(channels);
280
281
0
  freerdp* instance = channels->instance;
282
0
  WINPR_ASSERT(instance);
283
0
  WINPR_ASSERT(instance->context);
284
285
0
  EventArgsInit(&e, "freerdp");
286
0
  e.name = name;
287
0
  e.pInterface = pInterface;
288
0
  if (PubSub_OnChannelAttached(instance->context->pubSub, instance->context, &e) < 0)
289
0
    return ERROR_INTERNAL_ERROR;
290
0
  return status;
291
0
}
292
293
static UINT freerdp_drdynvc_on_channel_detached(DrdynvcClientContext* context, const char* name,
294
                                                void* pInterface)
295
0
{
296
0
  UINT status = CHANNEL_RC_OK;
297
0
  ChannelDetachedEventArgs e = WINPR_C_ARRAY_INIT;
298
299
0
  WINPR_ASSERT(context);
300
0
  rdpChannels* channels = (rdpChannels*)context->custom;
301
0
  WINPR_ASSERT(channels);
302
303
0
  freerdp* instance = channels->instance;
304
0
  WINPR_ASSERT(instance);
305
0
  WINPR_ASSERT(instance->context);
306
307
0
  EventArgsInit(&e, "freerdp");
308
0
  e.name = name;
309
0
  e.pInterface = pInterface;
310
0
  if (PubSub_OnChannelDetached(instance->context->pubSub, instance->context, &e) < 0)
311
0
    return ERROR_INTERNAL_ERROR;
312
0
  return status;
313
0
}
314
315
void freerdp_channels_register_instance(WINPR_ATTR_UNUSED rdpChannels* channels, freerdp* instance)
316
0
{
317
  /* store instance in TLS so future VirtualChannelInit calls can use it */
318
0
  g_Instance = instance;
319
0
}
320
321
/**
322
 * go through and inform all the libraries that we are initialized
323
 * called only from main thread
324
 */
325
UINT freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance)
326
0
{
327
0
  UINT error = CHANNEL_RC_OK;
328
329
0
  MessageQueue_Clear(channels->queue);
330
331
0
  for (int index = 0; index < channels->clientDataCount; index++)
332
0
  {
333
0
    CHANNEL_CLIENT_DATA* pChannelClientData = &channels->clientDataList[index];
334
335
0
    if (pChannelClientData->pChannelInitEventProc)
336
0
    {
337
0
      pChannelClientData->pChannelInitEventProc(pChannelClientData->pInitHandle,
338
0
                                                CHANNEL_EVENT_INITIALIZED, nullptr, 0);
339
0
    }
340
0
    else if (pChannelClientData->pChannelInitEventProcEx)
341
0
    {
342
0
      pChannelClientData->pChannelInitEventProcEx(pChannelClientData->lpUserParam,
343
0
                                                  pChannelClientData->pInitHandle,
344
0
                                                  CHANNEL_EVENT_INITIALIZED, nullptr, 0);
345
0
    }
346
347
0
    error = getChannelError(instance->context);
348
0
    if (CHANNEL_RC_OK != error)
349
0
      break;
350
351
0
    CHANNEL_OPEN_DATA* pChannelOpenData = &channels->openDataList[index];
352
0
    ChannelInitializedEventArgs e = WINPR_C_ARRAY_INIT;
353
0
    EventArgsInit(&e, "freerdp");
354
0
    e.name = pChannelOpenData->name;
355
0
    e.pInterface = pChannelOpenData->pInterface;
356
0
    if (PubSub_OnChannelInitialized(instance->context->pubSub, instance->context, &e) < 0)
357
0
    {
358
0
      error = ERROR_INTERNAL_ERROR;
359
0
      break;
360
0
    }
361
0
  }
362
363
0
  return error;
364
0
}
365
366
UINT freerdp_channels_attach(freerdp* instance)
367
0
{
368
0
  UINT error = CHANNEL_RC_OK;
369
0
  const char* hostname = nullptr;
370
0
  size_t hostnameLength = 0;
371
0
  rdpChannels* channels = nullptr;
372
0
  CHANNEL_CLIENT_DATA* pChannelClientData = nullptr;
373
374
0
  WINPR_ASSERT(instance);
375
0
  WINPR_ASSERT(instance->context);
376
0
  WINPR_ASSERT(instance->context->settings);
377
378
0
  channels = instance->context->channels;
379
0
  hostname = freerdp_settings_get_string(instance->context->settings, FreeRDP_ServerHostname);
380
0
  WINPR_ASSERT(hostname);
381
0
  hostnameLength = strnlen(hostname, MAX_PATH);
382
383
0
  for (int index = 0; index < channels->clientDataCount; index++)
384
0
  {
385
0
    union
386
0
    {
387
0
      const void* cpv;
388
0
      void* pv;
389
0
    } cnv;
390
0
    ChannelAttachedEventArgs e = WINPR_C_ARRAY_INIT;
391
392
0
    cnv.cpv = hostname;
393
0
    pChannelClientData = &channels->clientDataList[index];
394
395
0
    if (pChannelClientData->pChannelInitEventProc)
396
0
    {
397
398
0
      pChannelClientData->pChannelInitEventProc(pChannelClientData->pInitHandle,
399
0
                                                CHANNEL_EVENT_ATTACHED, cnv.pv,
400
0
                                                (UINT)hostnameLength);
401
0
    }
402
0
    else if (pChannelClientData->pChannelInitEventProcEx)
403
0
    {
404
0
      pChannelClientData->pChannelInitEventProcEx(
405
0
          pChannelClientData->lpUserParam, pChannelClientData->pInitHandle,
406
0
          CHANNEL_EVENT_ATTACHED, cnv.pv, (UINT)hostnameLength);
407
0
    }
408
409
0
    error = getChannelError(instance->context);
410
0
    if (error != CHANNEL_RC_OK)
411
0
      goto fail;
412
413
0
    CHANNEL_OPEN_DATA* pChannelOpenData = &channels->openDataList[index];
414
0
    EventArgsInit(&e, "freerdp");
415
0
    e.name = pChannelOpenData->name;
416
0
    e.pInterface = pChannelOpenData->pInterface;
417
0
    if (PubSub_OnChannelAttached(instance->context->pubSub, instance->context, &e) < 0)
418
0
    {
419
0
      error = ERROR_INTERNAL_ERROR;
420
0
      goto fail;
421
0
    }
422
0
  }
423
424
0
fail:
425
0
  return error;
426
0
}
427
428
UINT freerdp_channels_detach(freerdp* instance)
429
0
{
430
0
  UINT error = CHANNEL_RC_OK;
431
0
  const char* hostname = nullptr;
432
0
  size_t hostnameLength = 0;
433
0
  rdpChannels* channels = nullptr;
434
0
  rdpContext* context = nullptr;
435
0
  CHANNEL_CLIENT_DATA* pChannelClientData = nullptr;
436
437
0
  WINPR_ASSERT(instance);
438
439
0
  context = instance->context;
440
0
  WINPR_ASSERT(context);
441
442
0
  channels = context->channels;
443
0
  WINPR_ASSERT(channels);
444
445
0
  WINPR_ASSERT(context->settings);
446
0
  hostname = freerdp_settings_get_string(context->settings, FreeRDP_ServerHostname);
447
0
  WINPR_ASSERT(hostname);
448
0
  hostnameLength = strnlen(hostname, MAX_PATH);
449
450
0
  for (int index = 0; index < channels->clientDataCount; index++)
451
0
  {
452
0
    union
453
0
    {
454
0
      const void* cpv;
455
0
      void* pv;
456
0
    } cnv;
457
458
0
    ChannelDetachedEventArgs e = WINPR_C_ARRAY_INIT;
459
0
    CHANNEL_OPEN_DATA* pChannelOpenData = nullptr;
460
461
0
    cnv.cpv = hostname;
462
0
    pChannelClientData = &channels->clientDataList[index];
463
464
0
    if (pChannelClientData->pChannelInitEventProc)
465
0
    {
466
0
      pChannelClientData->pChannelInitEventProc(pChannelClientData->pInitHandle,
467
0
                                                CHANNEL_EVENT_DETACHED, cnv.pv,
468
0
                                                (UINT)hostnameLength);
469
0
    }
470
0
    else if (pChannelClientData->pChannelInitEventProcEx)
471
0
    {
472
0
      pChannelClientData->pChannelInitEventProcEx(
473
0
          pChannelClientData->lpUserParam, pChannelClientData->pInitHandle,
474
0
          CHANNEL_EVENT_DETACHED, cnv.pv, (UINT)hostnameLength);
475
0
    }
476
477
0
    error = getChannelError(context);
478
0
    if (error != CHANNEL_RC_OK)
479
0
      goto fail;
480
481
0
    pChannelOpenData = &channels->openDataList[index];
482
0
    EventArgsInit(&e, "freerdp");
483
0
    e.name = pChannelOpenData->name;
484
0
    e.pInterface = pChannelOpenData->pInterface;
485
0
    if (PubSub_OnChannelDetached(context->pubSub, context, &e) < 0)
486
0
    {
487
0
      error = ERROR_INTERNAL_ERROR;
488
0
      goto fail;
489
0
    }
490
0
  }
491
492
0
fail:
493
0
  return error;
494
0
}
495
496
/**
497
 * go through and inform all the libraries that we are connected
498
 * this will tell the libraries that its ok to call MyVirtualChannelOpen
499
 * called only from main thread
500
 */
501
UINT freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance)
502
0
{
503
0
  UINT error = CHANNEL_RC_OK;
504
505
0
  WINPR_ASSERT(channels);
506
0
  WINPR_ASSERT(instance);
507
0
  WINPR_ASSERT(instance->context);
508
0
  WINPR_ASSERT(instance->context->settings);
509
510
0
  channels->connected = TRUE;
511
0
  const char* hostname =
512
0
      freerdp_settings_get_string(instance->context->settings, FreeRDP_ServerHostname);
513
0
  WINPR_ASSERT(hostname);
514
0
  const size_t hostnameLength = strnlen(hostname, MAX_PATH);
515
516
0
  for (int index = 0; index < channels->clientDataCount; index++)
517
0
  {
518
0
    union
519
0
    {
520
0
      const void* pcb;
521
0
      void* pb;
522
0
    } cnv;
523
524
0
    CHANNEL_CLIENT_DATA* pChannelClientData = &channels->clientDataList[index];
525
0
    CHANNEL_OPEN_DATA* pChannelOpenData = &channels->openDataList[index];
526
527
0
    cnv.pcb = hostname;
528
0
    if (pChannelClientData->pChannelInitEventProc)
529
0
    {
530
0
      pChannelClientData->pChannelInitEventProc(pChannelClientData->pInitHandle,
531
0
                                                CHANNEL_EVENT_CONNECTED, cnv.pb,
532
0
                                                (UINT)hostnameLength);
533
0
    }
534
0
    else if (pChannelClientData->pChannelInitEventProcEx)
535
0
    {
536
0
      pChannelClientData->pChannelInitEventProcEx(
537
0
          pChannelClientData->lpUserParam, pChannelClientData->pInitHandle,
538
0
          CHANNEL_EVENT_CONNECTED, cnv.pb, (UINT)hostnameLength);
539
0
    }
540
541
0
    error = getChannelError(instance->context);
542
0
    if (error != CHANNEL_RC_OK)
543
0
      goto fail;
544
545
0
    ChannelConnectedEventArgs e = WINPR_C_ARRAY_INIT;
546
0
    EventArgsInit(&e, "freerdp");
547
0
    e.name = pChannelOpenData->name;
548
0
    e.pInterface = pChannelOpenData->pInterface;
549
0
    if (PubSub_OnChannelConnected(instance->context->pubSub, instance->context, &e) < 0)
550
0
    {
551
0
      error = ERROR_INTERNAL_ERROR;
552
0
      goto fail;
553
0
    }
554
0
  }
555
556
0
  channels->drdynvc = (DrdynvcClientContext*)freerdp_channels_get_static_channel_interface(
557
0
      channels, DRDYNVC_SVC_CHANNEL_NAME);
558
559
0
  if (channels->drdynvc)
560
0
  {
561
0
    channels->drdynvc->custom = (void*)channels;
562
0
    channels->drdynvc->OnChannelConnected = freerdp_drdynvc_on_channel_connected;
563
0
    channels->drdynvc->OnChannelDisconnected = freerdp_drdynvc_on_channel_disconnected;
564
0
    channels->drdynvc->OnChannelAttached = freerdp_drdynvc_on_channel_attached;
565
0
    channels->drdynvc->OnChannelDetached = freerdp_drdynvc_on_channel_detached;
566
0
  }
567
568
0
fail:
569
0
  return error;
570
0
}
571
572
BOOL freerdp_channels_data(freerdp* instance, UINT16 channelId, const BYTE* cdata, size_t dataSize,
573
                           UINT32 flags, size_t totalSize)
574
0
{
575
0
  rdpMcs* mcs = nullptr;
576
0
  rdpChannels* channels = nullptr;
577
0
  rdpMcsChannel* channel = nullptr;
578
0
  CHANNEL_OPEN_DATA* pChannelOpenData = nullptr;
579
0
  union
580
0
  {
581
0
    const BYTE* pcb;
582
0
    BYTE* pb;
583
0
  } data;
584
585
0
  data.pcb = cdata;
586
0
  if (!instance || !data.pcb)
587
0
  {
588
0
    WLog_ERR(TAG, "(%p, %" PRIu16 ", %p, 0x%08x): Invalid arguments",
589
0
             WINPR_CXX_COMPAT_CAST(const void*, instance), channelId,
590
0
             WINPR_CXX_COMPAT_CAST(const void*, data.pcb), flags);
591
0
    return FALSE;
592
0
  }
593
594
0
  mcs = instance->context->rdp->mcs;
595
0
  channels = instance->context->channels;
596
597
0
  if (!channels || !mcs)
598
0
  {
599
0
    return FALSE;
600
0
  }
601
602
0
  for (UINT32 index = 0; index < mcs->channelCount; index++)
603
0
  {
604
0
    rdpMcsChannel* cur = &mcs->channels[index];
605
606
0
    if (cur->ChannelId == channelId)
607
0
    {
608
0
      channel = cur;
609
0
      break;
610
0
    }
611
0
  }
612
613
0
  if (!channel)
614
0
  {
615
0
    return FALSE;
616
0
  }
617
618
0
  pChannelOpenData = freerdp_channels_find_channel_open_data_by_name(channels, channel->Name);
619
620
0
  if (!pChannelOpenData)
621
0
  {
622
0
    return FALSE;
623
0
  }
624
625
0
  if (pChannelOpenData->pChannelOpenEventProc)
626
0
  {
627
0
    pChannelOpenData->pChannelOpenEventProc(pChannelOpenData->OpenHandle,
628
0
                                            CHANNEL_EVENT_DATA_RECEIVED, data.pb,
629
0
                                            (UINT32)dataSize, (UINT32)totalSize, flags);
630
0
  }
631
0
  else if (pChannelOpenData->pChannelOpenEventProcEx)
632
0
  {
633
0
    pChannelOpenData->pChannelOpenEventProcEx(
634
0
        pChannelOpenData->lpUserParam, pChannelOpenData->OpenHandle,
635
0
        CHANNEL_EVENT_DATA_RECEIVED, data.pb, (UINT32)dataSize, (UINT32)totalSize, flags);
636
0
  }
637
638
0
  return TRUE;
639
0
}
640
641
UINT16 freerdp_channels_get_id_by_name(freerdp* instance, const char* channel_name)
642
0
{
643
0
  if (!instance || !channel_name)
644
0
    return 0;
645
646
0
  rdpMcsChannel* mcsChannel =
647
0
      freerdp_channels_find_channel_by_name(instance->context->rdp, channel_name);
648
0
  if (!mcsChannel)
649
0
    return 0;
650
651
0
  return mcsChannel->ChannelId;
652
0
}
653
654
const char* freerdp_channels_get_name_by_id(freerdp* instance, UINT16 channelId)
655
0
{
656
0
  rdpMcsChannel* mcsChannel = nullptr;
657
0
  if (!instance)
658
0
    return nullptr;
659
660
0
  mcsChannel = freerdp_channels_find_channel_by_id(instance->context->rdp, channelId);
661
0
  if (!mcsChannel)
662
0
    return nullptr;
663
664
0
  return mcsChannel->Name;
665
0
}
666
667
BOOL freerdp_channels_process_message_free(wMessage* message, DWORD type)
668
0
{
669
0
  if (message->id == WMQ_QUIT)
670
0
  {
671
0
    return FALSE;
672
0
  }
673
674
0
  if (message->id == 0)
675
0
  {
676
0
    CHANNEL_OPEN_DATA* pChannelOpenData = nullptr;
677
0
    CHANNEL_OPEN_EVENT* item = (CHANNEL_OPEN_EVENT*)message->wParam;
678
679
0
    if (!item)
680
0
      return FALSE;
681
682
0
    pChannelOpenData = item->pChannelOpenData;
683
684
0
    if (pChannelOpenData->pChannelOpenEventProc)
685
0
    {
686
0
      pChannelOpenData->pChannelOpenEventProc(pChannelOpenData->OpenHandle, type,
687
0
                                              item->UserData, item->DataLength,
688
0
                                              item->DataLength, 0);
689
0
    }
690
0
    else if (pChannelOpenData->pChannelOpenEventProcEx)
691
0
    {
692
0
      pChannelOpenData->pChannelOpenEventProcEx(
693
0
          pChannelOpenData->lpUserParam, pChannelOpenData->OpenHandle, type, item->UserData,
694
0
          item->DataLength, item->DataLength, 0);
695
0
    }
696
0
  }
697
698
0
  return TRUE;
699
0
}
700
701
static BOOL freerdp_channels_process_message(freerdp* instance, wMessage* message)
702
0
{
703
0
  BOOL ret = TRUE;
704
0
  BOOL rc = FALSE;
705
706
0
  WINPR_ASSERT(instance);
707
0
  WINPR_ASSERT(message);
708
709
0
  if (message->id == WMQ_QUIT)
710
0
    goto fail;
711
0
  else if (message->id == 0)
712
0
  {
713
0
    rdpMcsChannel* channel = nullptr;
714
0
    CHANNEL_OPEN_DATA* pChannelOpenData = nullptr;
715
0
    CHANNEL_OPEN_EVENT* item = (CHANNEL_OPEN_EVENT*)message->wParam;
716
717
0
    if (!item)
718
0
      goto fail;
719
720
0
    pChannelOpenData = item->pChannelOpenData;
721
0
    if (pChannelOpenData->flags != 2)
722
0
    {
723
0
      freerdp_channels_process_message_free(message, CHANNEL_EVENT_WRITE_CANCELLED);
724
0
      goto fail;
725
0
    }
726
0
    channel =
727
0
        freerdp_channels_find_channel_by_name(instance->context->rdp, pChannelOpenData->name);
728
729
0
    if (channel)
730
0
      ret = instance->SendChannelData(instance, channel->ChannelId, item->Data,
731
0
                                      item->DataLength);
732
0
  }
733
734
0
  if (!freerdp_channels_process_message_free(message, CHANNEL_EVENT_WRITE_COMPLETE))
735
0
    goto fail;
736
737
0
  rc = ret;
738
739
0
fail:
740
0
  IFCALL(message->Free, message);
741
0
  return rc;
742
0
}
743
744
/**
745
 * called only from main thread
746
 */
747
static BOOL freerdp_channels_process_sync(rdpChannels* channels, freerdp* instance)
748
0
{
749
0
  BOOL status = TRUE;
750
0
  wMessage message = WINPR_C_ARRAY_INIT;
751
752
0
  WINPR_ASSERT(channels);
753
754
0
  while (MessageQueue_Peek(channels->queue, &message, TRUE))
755
0
  {
756
0
    if (!freerdp_channels_process_message(instance, &message))
757
0
      status = FALSE;
758
0
  }
759
760
0
  return status;
761
0
}
762
763
/**
764
 * called only from main thread
765
 */
766
#if defined(WITH_FREERDP_DEPRECATED)
767
BOOL freerdp_channels_get_fds(rdpChannels* channels, WINPR_ATTR_UNUSED freerdp* instance,
768
                              void** read_fds, int* read_count, WINPR_ATTR_UNUSED void** write_fds,
769
                              WINPR_ATTR_UNUSED int* write_count)
770
{
771
  void* pfd = nullptr;
772
  pfd = GetEventWaitObject(MessageQueue_Event(channels->queue));
773
774
  if (pfd)
775
  {
776
    read_fds[*read_count] = pfd;
777
    (*read_count)++;
778
  }
779
780
  return TRUE;
781
}
782
#endif
783
784
void* freerdp_channels_get_static_channel_interface(rdpChannels* channels, const char* name)
785
0
{
786
0
  void* pInterface = nullptr;
787
0
  CHANNEL_OPEN_DATA* pChannelOpenData =
788
0
      freerdp_channels_find_channel_open_data_by_name(channels, name);
789
790
0
  if (pChannelOpenData)
791
0
    pInterface = pChannelOpenData->pInterface;
792
793
0
  return pInterface;
794
0
}
795
796
HANDLE freerdp_channels_get_event_handle(freerdp* instance)
797
0
{
798
0
  if (!instance)
799
0
    return INVALID_HANDLE_VALUE;
800
801
0
  WINPR_ASSERT(instance->context);
802
803
0
  rdpChannels* channels = instance->context->channels;
804
0
  WINPR_ASSERT(channels);
805
806
0
  return MessageQueue_Event(channels->queue);
807
0
}
808
809
static BOOL channels_process(const void* key, void* value, void* arg)
810
0
{
811
0
  ChannelEventEntry* entry = value;
812
0
  rdpContext* context = arg;
813
814
0
  WINPR_UNUSED(key);
815
816
0
  if (!entry->fkt)
817
0
    return FALSE;
818
0
  return entry->fkt(context, entry->userdata);
819
0
}
820
821
int freerdp_channels_process_pending_messages(freerdp* instance)
822
0
{
823
0
  if (!instance)
824
0
    return -1;
825
826
0
  WINPR_ASSERT(instance->context);
827
828
0
  rdpChannels* channels = instance->context->channels;
829
0
  WINPR_ASSERT(channels);
830
831
0
  const DWORD status = WaitForSingleObject(MessageQueue_Event(channels->queue), 0);
832
0
  if (status == WAIT_OBJECT_0)
833
0
  {
834
0
    if (!freerdp_channels_process_sync(channels, instance))
835
0
      return -1;
836
0
  }
837
838
0
  if (!HashTable_Foreach(channels->channelEvents, channels_process, instance->context))
839
0
    return -1;
840
841
0
  return 1;
842
0
}
843
844
/**
845
 * called only from main thread
846
 */
847
BOOL freerdp_channels_check_fds(rdpChannels* channels, freerdp* instance)
848
0
{
849
0
  WINPR_ASSERT(channels);
850
0
  WINPR_UNUSED(channels);
851
852
0
  const int rc = freerdp_channels_process_pending_messages(instance);
853
0
  return rc == 1;
854
0
}
855
856
BOOL freerdp_client_channel_register(rdpChannels* channels, HANDLE handle,
857
                                     freerdp_channel_handle_fkt_t fkt, void* userdata)
858
0
{
859
0
  if (!channels || (handle == INVALID_HANDLE_VALUE) || !fkt)
860
0
  {
861
0
    WLog_ERR(TAG, "Invalid function arguments (channels=%p, handle=%p, fkt=%p, userdata=%p",
862
0
             WINPR_FUNC_PTR_CAST(channels, const void*), handle,
863
0
             WINPR_FUNC_PTR_CAST(fkt, const void*), userdata);
864
0
    return FALSE;
865
0
  }
866
867
0
  ChannelEventEntry entry = { .fkt = fkt, .userdata = userdata };
868
0
  return HashTable_Insert(channels->channelEvents, handle, &entry);
869
0
}
870
871
BOOL freerdp_client_channel_unregister(rdpChannels* channels, HANDLE handle)
872
0
{
873
0
  if (!channels || (handle == INVALID_HANDLE_VALUE))
874
0
  {
875
0
    WLog_ERR(TAG, "Invalid function arguments (channels=%p, handle=%p",
876
0
             WINPR_CXX_COMPAT_CAST(const void*, channels), handle);
877
0
    return FALSE;
878
0
  }
879
880
0
  return HashTable_Remove(channels->channelEvents, handle);
881
0
}
882
883
SSIZE_T freerdp_client_channel_get_registered_event_handles(rdpChannels* channels, HANDLE* events,
884
                                                            DWORD count)
885
0
{
886
0
  SSIZE_T rc = -1;
887
888
0
  WINPR_ASSERT(channels);
889
0
  WINPR_ASSERT(events || (count == 0));
890
891
0
  HashTable_Lock(channels->channelEvents);
892
0
  size_t len = HashTable_Count(channels->channelEvents);
893
0
  if (len <= count)
894
0
  {
895
0
    ULONG_PTR* keys = nullptr;
896
0
    const size_t nrKeys = HashTable_GetKeys(channels->channelEvents, &keys);
897
0
    if ((nrKeys <= SSIZE_MAX) && (nrKeys == len))
898
0
    {
899
0
      for (size_t x = 0; x < nrKeys; x++)
900
0
      {
901
0
        HANDLE cur = (HANDLE)keys[x];
902
0
        events[x] = cur;
903
0
      }
904
0
      rc = (SSIZE_T)nrKeys;
905
0
    }
906
0
    free(keys);
907
0
  }
908
0
  HashTable_Unlock(channels->channelEvents);
909
0
  return rc;
910
0
}
911
912
UINT freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance)
913
0
{
914
0
  UINT error = CHANNEL_RC_OK;
915
0
  CHANNEL_OPEN_DATA* pChannelOpenData = nullptr;
916
0
  CHANNEL_CLIENT_DATA* pChannelClientData = nullptr;
917
918
0
  WINPR_ASSERT(channels);
919
920
0
  if (!channels->connected)
921
0
    return 0;
922
923
0
  freerdp_channels_check_fds(channels, instance);
924
925
  /* tell all libraries we are shutting down */
926
0
  for (int index = 0; index < channels->clientDataCount; index++)
927
0
  {
928
0
    ChannelDisconnectedEventArgs e = WINPR_C_ARRAY_INIT;
929
0
    pChannelClientData = &channels->clientDataList[index];
930
931
0
    if (pChannelClientData->pChannelInitEventProc)
932
0
    {
933
0
      pChannelClientData->pChannelInitEventProc(pChannelClientData->pInitHandle,
934
0
                                                CHANNEL_EVENT_DISCONNECTED, nullptr, 0);
935
0
    }
936
0
    else if (pChannelClientData->pChannelInitEventProcEx)
937
0
    {
938
0
      pChannelClientData->pChannelInitEventProcEx(pChannelClientData->lpUserParam,
939
0
                                                  pChannelClientData->pInitHandle,
940
0
                                                  CHANNEL_EVENT_DISCONNECTED, nullptr, 0);
941
0
    }
942
943
0
    pChannelOpenData = &channels->openDataList[index];
944
0
    EventArgsInit(&e, "freerdp");
945
0
    e.name = pChannelOpenData->name;
946
0
    e.pInterface = pChannelOpenData->pInterface;
947
0
    if (PubSub_OnChannelDisconnected(instance->context->pubSub, instance->context, &e) < 0)
948
0
      error = ERROR_INTERNAL_ERROR;
949
0
  }
950
951
0
  channels->connected = FALSE;
952
953
  /* Flush pending messages */
954
0
  freerdp_channels_check_fds(channels, instance);
955
0
  return error;
956
0
}
957
958
void freerdp_channels_close(rdpChannels* channels, freerdp* instance)
959
0
{
960
0
  WINPR_ASSERT(channels);
961
0
  WINPR_ASSERT(instance);
962
963
0
  MessageQueue_PostQuit(channels->queue, 0);
964
0
  freerdp_channels_check_fds(channels, instance);
965
966
  /* tell all libraries we are shutting down */
967
0
  for (int index = 0; index < channels->clientDataCount; index++)
968
0
  {
969
0
    CHANNEL_CLIENT_DATA* pChannelClientData = &channels->clientDataList[index];
970
971
0
    if (pChannelClientData->pChannelInitEventProc)
972
0
    {
973
0
      pChannelClientData->pChannelInitEventProc(pChannelClientData->pInitHandle,
974
0
                                                CHANNEL_EVENT_TERMINATED, nullptr, 0);
975
0
    }
976
0
    else if (pChannelClientData->pChannelInitEventProcEx)
977
0
    {
978
0
      pChannelClientData->pChannelInitEventProcEx(pChannelClientData->lpUserParam,
979
0
                                                  pChannelClientData->pInitHandle,
980
0
                                                  CHANNEL_EVENT_TERMINATED, nullptr, 0);
981
0
    }
982
983
0
    CHANNEL_OPEN_DATA* pChannelOpenData = &channels->openDataList[index];
984
0
    ChannelTerminatedEventArgs e = WINPR_C_ARRAY_INIT;
985
0
    EventArgsInit(&e, "freerdp");
986
0
    e.name = pChannelOpenData->name;
987
0
    e.pInterface = pChannelOpenData->pInterface;
988
0
    if (PubSub_OnChannelTerminated(instance->context->pubSub, instance->context, &e) < 0)
989
0
    {
990
0
      WLog_WARN(TAG, "PubSub_OnChannelTerminated(%s) failed", pChannelOpenData->name);
991
0
    }
992
0
  }
993
994
0
  for (int index = 0; index < channels->openDataCount; index++)
995
0
  {
996
0
    CHANNEL_OPEN_DATA* pChannelOpenData = &channels->openDataList[index];
997
0
    HashTable_Remove(g_ChannelHandles, (void*)(UINT_PTR)pChannelOpenData->OpenHandle);
998
0
  }
999
1000
0
  channels->openDataCount = 0;
1001
0
  channels->initDataCount = 0;
1002
0
  channels->clientDataCount = 0;
1003
1004
0
  WINPR_ASSERT(instance->context);
1005
0
  WINPR_ASSERT(instance->context->settings);
1006
0
  instance->context->settings->ChannelCount = 0;
1007
0
  g_Instance = nullptr;
1008
0
}
1009
1010
static UINT VCAPITYPE FreeRDP_VirtualChannelInitEx(
1011
    LPVOID lpUserParam, LPVOID clientContext, LPVOID pInitHandle, PCHANNEL_DEF pChannel,
1012
    INT channelCount, ULONG versionRequested, PCHANNEL_INIT_EVENT_EX_FN pChannelInitEventProcEx)
1013
0
{
1014
0
  rdpSettings* settings = nullptr;
1015
0
  CHANNEL_INIT_DATA* pChannelInitData = nullptr;
1016
0
  CHANNEL_CLIENT_DATA* pChannelClientData = nullptr;
1017
0
  rdpChannels* channels = nullptr;
1018
1019
0
  if (!pInitHandle)
1020
0
    return CHANNEL_RC_BAD_INIT_HANDLE;
1021
1022
0
  if (!pChannel)
1023
0
    return CHANNEL_RC_BAD_CHANNEL;
1024
1025
0
  if ((channelCount <= 0) || !pChannelInitEventProcEx)
1026
0
    return CHANNEL_RC_INITIALIZATION_ERROR;
1027
1028
0
  pChannelInitData = (CHANNEL_INIT_DATA*)pInitHandle;
1029
0
  WINPR_ASSERT(pChannelInitData);
1030
1031
0
  channels = pChannelInitData->channels;
1032
0
  WINPR_ASSERT(channels);
1033
1034
0
  if (!channels->can_call_init)
1035
0
    return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY;
1036
1037
0
  if ((channels->openDataCount + channelCount) > CHANNEL_MAX_COUNT)
1038
0
    return CHANNEL_RC_TOO_MANY_CHANNELS;
1039
1040
0
  if (channels->connected)
1041
0
    return CHANNEL_RC_ALREADY_CONNECTED;
1042
1043
0
  if (versionRequested != VIRTUAL_CHANNEL_VERSION_WIN2000)
1044
0
  {
1045
0
  }
1046
1047
0
  for (int index = 0; index < channelCount; index++)
1048
0
  {
1049
0
    const PCHANNEL_DEF pChannelDef = &pChannel[index];
1050
1051
0
    if (freerdp_channels_find_channel_open_data_by_name(channels, pChannelDef->name) != nullptr)
1052
0
    {
1053
0
      return CHANNEL_RC_BAD_CHANNEL;
1054
0
    }
1055
0
  }
1056
1057
0
  pChannelInitData->pInterface = clientContext;
1058
0
  pChannelClientData = &channels->clientDataList[channels->clientDataCount];
1059
0
  pChannelClientData->pChannelInitEventProcEx = pChannelInitEventProcEx;
1060
0
  pChannelClientData->pInitHandle = pInitHandle;
1061
0
  pChannelClientData->lpUserParam = lpUserParam;
1062
0
  channels->clientDataCount++;
1063
1064
0
  WINPR_ASSERT(channels->instance);
1065
0
  WINPR_ASSERT(channels->instance->context);
1066
0
  settings = channels->instance->context->settings;
1067
0
  WINPR_ASSERT(settings);
1068
1069
0
  for (int index = 0; index < channelCount; index++)
1070
0
  {
1071
0
    const PCHANNEL_DEF pChannelDef = &pChannel[index];
1072
0
    CHANNEL_OPEN_DATA* pChannelOpenData = &channels->openDataList[channels->openDataCount];
1073
1074
0
    WINPR_ASSERT(pChannelOpenData);
1075
1076
0
    const LONG hdl = InterlockedIncrement(&g_OpenHandleSeq);
1077
0
    pChannelOpenData->OpenHandle = WINPR_ASSERTING_INT_CAST(uint32_t, hdl);
1078
0
    pChannelOpenData->channels = channels;
1079
0
    pChannelOpenData->lpUserParam = lpUserParam;
1080
0
    if (!HashTable_Insert(g_ChannelHandles, (void*)(UINT_PTR)pChannelOpenData->OpenHandle,
1081
0
                          (void*)pChannelOpenData))
1082
0
    {
1083
0
      pChannelInitData->pInterface = nullptr;
1084
0
      return CHANNEL_RC_INITIALIZATION_ERROR;
1085
0
    }
1086
0
    pChannelOpenData->flags = 1; /* init */
1087
0
    strncpy(pChannelOpenData->name, pChannelDef->name, CHANNEL_NAME_LEN);
1088
0
    pChannelOpenData->options = pChannelDef->options;
1089
1090
0
    const UINT32 max = freerdp_settings_get_uint32(settings, FreeRDP_ChannelDefArraySize);
1091
0
    WINPR_ASSERT(max >= CHANNEL_MAX_COUNT);
1092
0
    if (settings->ChannelCount < max)
1093
0
    {
1094
0
      CHANNEL_DEF* channel = freerdp_settings_get_pointer_array_writable(
1095
0
          settings, FreeRDP_ChannelDefArray, settings->ChannelCount);
1096
0
      if (!channel)
1097
0
        continue;
1098
0
      strncpy(channel->name, pChannelDef->name, CHANNEL_NAME_LEN);
1099
0
      channel->options = pChannelDef->options;
1100
0
      settings->ChannelCount++;
1101
0
    }
1102
1103
0
    channels->openDataCount++;
1104
0
  }
1105
1106
0
  return CHANNEL_RC_OK;
1107
0
}
1108
1109
static UINT VCAPITYPE FreeRDP_VirtualChannelInit(LPVOID* ppInitHandle, PCHANNEL_DEF pChannel,
1110
                                                 INT channelCount, ULONG versionRequested,
1111
                                                 PCHANNEL_INIT_EVENT_FN pChannelInitEventProc)
1112
0
{
1113
0
  CHANNEL_DEF* channel = nullptr;
1114
0
  rdpSettings* settings = nullptr;
1115
0
  PCHANNEL_DEF pChannelDef = nullptr;
1116
0
  CHANNEL_INIT_DATA* pChannelInitData = nullptr;
1117
0
  CHANNEL_OPEN_DATA* pChannelOpenData = nullptr;
1118
0
  CHANNEL_CLIENT_DATA* pChannelClientData = nullptr;
1119
0
  rdpChannels* channels = nullptr;
1120
1121
  /* g_Instance should have been set during freerdp_connect - otherwise VirtualChannelInit was
1122
   * called from a different thread */
1123
0
  if (!g_Instance || !g_Instance->context)
1124
0
    return CHANNEL_RC_NOT_INITIALIZED;
1125
1126
0
  channels = g_Instance->context->channels;
1127
1128
0
  if (!ppInitHandle || !channels)
1129
0
    return CHANNEL_RC_BAD_INIT_HANDLE;
1130
1131
0
  if (!pChannel)
1132
0
    return CHANNEL_RC_BAD_CHANNEL;
1133
1134
0
  if ((channelCount <= 0) || !pChannelInitEventProc)
1135
0
    return CHANNEL_RC_INITIALIZATION_ERROR;
1136
1137
0
  pChannelInitData = &(channels->initDataList[channels->initDataCount]);
1138
0
  *ppInitHandle = pChannelInitData;
1139
0
  channels->initDataCount++;
1140
0
  pChannelInitData->channels = channels;
1141
0
  pChannelInitData->pInterface = nullptr;
1142
1143
0
  if (!channels->can_call_init)
1144
0
    return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY;
1145
1146
0
  if (channels->openDataCount + channelCount > CHANNEL_MAX_COUNT)
1147
0
    return CHANNEL_RC_TOO_MANY_CHANNELS;
1148
1149
0
  if (channels->connected)
1150
0
    return CHANNEL_RC_ALREADY_CONNECTED;
1151
1152
0
  if (versionRequested != VIRTUAL_CHANNEL_VERSION_WIN2000)
1153
0
  {
1154
0
  }
1155
1156
0
  for (int index = 0; index < channelCount; index++)
1157
0
  {
1158
0
    pChannelDef = &pChannel[index];
1159
1160
0
    if (freerdp_channels_find_channel_open_data_by_name(channels, pChannelDef->name) != nullptr)
1161
0
    {
1162
0
      return CHANNEL_RC_BAD_CHANNEL;
1163
0
    }
1164
0
  }
1165
1166
0
  pChannelClientData = &channels->clientDataList[channels->clientDataCount];
1167
0
  pChannelClientData->pChannelInitEventProc = pChannelInitEventProc;
1168
0
  pChannelClientData->pInitHandle = *ppInitHandle;
1169
0
  channels->clientDataCount++;
1170
0
  settings = channels->instance->context->settings;
1171
1172
0
  for (int index = 0; index < channelCount; index++)
1173
0
  {
1174
0
    UINT32 ChannelCount = freerdp_settings_get_uint32(settings, FreeRDP_ChannelCount);
1175
1176
0
    pChannelDef = &pChannel[index];
1177
1178
0
    pChannelOpenData = &channels->openDataList[channels->openDataCount];
1179
1180
0
    const LONG hdl = InterlockedIncrement(&g_OpenHandleSeq);
1181
0
    pChannelOpenData->OpenHandle = WINPR_ASSERTING_INT_CAST(uint32_t, hdl);
1182
0
    pChannelOpenData->channels = channels;
1183
0
    if (!HashTable_Insert(g_ChannelHandles, (void*)(UINT_PTR)pChannelOpenData->OpenHandle,
1184
0
                          (void*)pChannelOpenData))
1185
0
      return CHANNEL_RC_INITIALIZATION_ERROR;
1186
0
    pChannelOpenData->flags = 1; /* init */
1187
0
    strncpy(pChannelOpenData->name, pChannelDef->name, CHANNEL_NAME_LEN);
1188
0
    pChannelOpenData->options = pChannelDef->options;
1189
1190
0
    if (ChannelCount < CHANNEL_MAX_COUNT)
1191
0
    {
1192
0
      channel = freerdp_settings_get_pointer_array_writable(settings, FreeRDP_ChannelDefArray,
1193
0
                                                            ChannelCount++);
1194
0
      strncpy(channel->name, pChannelDef->name, CHANNEL_NAME_LEN);
1195
0
      channel->options = pChannelDef->options;
1196
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_ChannelCount, ChannelCount))
1197
0
        return ERROR_INTERNAL_ERROR;
1198
0
    }
1199
1200
0
    channels->openDataCount++;
1201
0
  }
1202
1203
0
  return CHANNEL_RC_OK;
1204
0
}
1205
1206
static UINT VCAPITYPE
1207
FreeRDP_VirtualChannelOpenEx(LPVOID pInitHandle, LPDWORD pOpenHandle, PCHAR pChannelName,
1208
                             PCHANNEL_OPEN_EVENT_EX_FN pChannelOpenEventProcEx)
1209
0
{
1210
0
  void* pInterface = nullptr;
1211
0
  rdpChannels* channels = nullptr;
1212
0
  CHANNEL_INIT_DATA* pChannelInitData = nullptr;
1213
0
  CHANNEL_OPEN_DATA* pChannelOpenData = nullptr;
1214
0
  pChannelInitData = (CHANNEL_INIT_DATA*)pInitHandle;
1215
0
  channels = pChannelInitData->channels;
1216
0
  pInterface = pChannelInitData->pInterface;
1217
1218
0
  if (!pOpenHandle)
1219
0
    return CHANNEL_RC_BAD_CHANNEL_HANDLE;
1220
1221
0
  if (!pChannelOpenEventProcEx)
1222
0
    return CHANNEL_RC_BAD_PROC;
1223
1224
0
  if (!channels->connected)
1225
0
    return CHANNEL_RC_NOT_CONNECTED;
1226
1227
0
  pChannelOpenData = freerdp_channels_find_channel_open_data_by_name(channels, pChannelName);
1228
1229
0
  if (!pChannelOpenData)
1230
0
    return CHANNEL_RC_UNKNOWN_CHANNEL_NAME;
1231
1232
0
  if (pChannelOpenData->flags == 2)
1233
0
    return CHANNEL_RC_ALREADY_OPEN;
1234
1235
0
  pChannelOpenData->flags = 2; /* open */
1236
0
  pChannelOpenData->pInterface = pInterface;
1237
0
  pChannelOpenData->pChannelOpenEventProcEx = pChannelOpenEventProcEx;
1238
0
  *pOpenHandle = pChannelOpenData->OpenHandle;
1239
0
  return CHANNEL_RC_OK;
1240
0
}
1241
1242
static UINT VCAPITYPE FreeRDP_VirtualChannelOpen(LPVOID pInitHandle, LPDWORD pOpenHandle,
1243
                                                 PCHAR pChannelName,
1244
                                                 PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc)
1245
0
{
1246
0
  void* pInterface = nullptr;
1247
0
  rdpChannels* channels = nullptr;
1248
0
  CHANNEL_INIT_DATA* pChannelInitData = nullptr;
1249
0
  CHANNEL_OPEN_DATA* pChannelOpenData = nullptr;
1250
0
  pChannelInitData = (CHANNEL_INIT_DATA*)pInitHandle;
1251
0
  channels = pChannelInitData->channels;
1252
0
  pInterface = pChannelInitData->pInterface;
1253
1254
0
  if (!pOpenHandle)
1255
0
    return CHANNEL_RC_BAD_CHANNEL_HANDLE;
1256
1257
0
  if (!pChannelOpenEventProc)
1258
0
    return CHANNEL_RC_BAD_PROC;
1259
1260
0
  if (!channels->connected)
1261
0
    return CHANNEL_RC_NOT_CONNECTED;
1262
1263
0
  pChannelOpenData = freerdp_channels_find_channel_open_data_by_name(channels, pChannelName);
1264
1265
0
  if (!pChannelOpenData)
1266
0
    return CHANNEL_RC_UNKNOWN_CHANNEL_NAME;
1267
1268
0
  if (pChannelOpenData->flags == 2)
1269
0
    return CHANNEL_RC_ALREADY_OPEN;
1270
1271
0
  pChannelOpenData->flags = 2; /* open */
1272
0
  pChannelOpenData->pInterface = pInterface;
1273
0
  pChannelOpenData->pChannelOpenEventProc = pChannelOpenEventProc;
1274
0
  *pOpenHandle = pChannelOpenData->OpenHandle;
1275
0
  return CHANNEL_RC_OK;
1276
0
}
1277
1278
static UINT VCAPITYPE FreeRDP_VirtualChannelCloseEx(LPVOID pInitHandle, DWORD openHandle)
1279
0
{
1280
0
  CHANNEL_OPEN_DATA* pChannelOpenData = nullptr;
1281
1282
0
  if (!pInitHandle)
1283
0
    return CHANNEL_RC_BAD_INIT_HANDLE;
1284
1285
0
  pChannelOpenData = HashTable_GetItemValue(g_ChannelHandles, (void*)(UINT_PTR)openHandle);
1286
1287
0
  if (!pChannelOpenData)
1288
0
    return CHANNEL_RC_BAD_CHANNEL_HANDLE;
1289
1290
0
  if (pChannelOpenData->flags != 2)
1291
0
    return CHANNEL_RC_NOT_OPEN;
1292
1293
0
  pChannelOpenData->flags = 0;
1294
0
  return CHANNEL_RC_OK;
1295
0
}
1296
1297
static UINT VCAPITYPE FreeRDP_VirtualChannelClose(DWORD openHandle)
1298
0
{
1299
0
  CHANNEL_OPEN_DATA* pChannelOpenData = nullptr;
1300
1301
0
  pChannelOpenData = HashTable_GetItemValue(g_ChannelHandles, (void*)(UINT_PTR)openHandle);
1302
1303
0
  if (!pChannelOpenData)
1304
0
    return CHANNEL_RC_BAD_CHANNEL_HANDLE;
1305
1306
0
  if (pChannelOpenData->flags != 2)
1307
0
    return CHANNEL_RC_NOT_OPEN;
1308
1309
0
  pChannelOpenData->flags = 0;
1310
0
  return CHANNEL_RC_OK;
1311
0
}
1312
1313
static UINT VCAPITYPE FreeRDP_VirtualChannelWriteEx(LPVOID pInitHandle, DWORD openHandle,
1314
                                                    LPVOID pData, ULONG dataLength,
1315
                                                    LPVOID pUserData)
1316
0
{
1317
0
  rdpChannels* channels = nullptr;
1318
0
  CHANNEL_INIT_DATA* pChannelInitData = nullptr;
1319
0
  CHANNEL_OPEN_DATA* pChannelOpenData = nullptr;
1320
0
  CHANNEL_OPEN_EVENT* pChannelOpenEvent = nullptr;
1321
0
  wMessage message = WINPR_C_ARRAY_INIT;
1322
1323
0
  if (!pInitHandle)
1324
0
    return CHANNEL_RC_BAD_INIT_HANDLE;
1325
1326
0
  pChannelInitData = (CHANNEL_INIT_DATA*)pInitHandle;
1327
0
  channels = pChannelInitData->channels;
1328
1329
0
  if (!channels)
1330
0
    return CHANNEL_RC_BAD_CHANNEL_HANDLE;
1331
1332
0
  pChannelOpenData = HashTable_GetItemValue(g_ChannelHandles, (void*)(UINT_PTR)openHandle);
1333
1334
0
  if (!pChannelOpenData)
1335
0
    return CHANNEL_RC_BAD_CHANNEL_HANDLE;
1336
1337
0
  if (!channels->connected)
1338
0
    return CHANNEL_RC_NOT_CONNECTED;
1339
1340
0
  if (!pData)
1341
0
    return CHANNEL_RC_NULL_DATA;
1342
1343
0
  if (!dataLength)
1344
0
    return CHANNEL_RC_ZERO_LENGTH;
1345
1346
0
  if (pChannelOpenData->flags != 2)
1347
0
    return CHANNEL_RC_NOT_OPEN;
1348
1349
0
  pChannelOpenEvent = (CHANNEL_OPEN_EVENT*)malloc(sizeof(CHANNEL_OPEN_EVENT));
1350
1351
0
  if (!pChannelOpenEvent)
1352
0
    return CHANNEL_RC_NO_MEMORY;
1353
1354
0
  pChannelOpenEvent->Data = pData;
1355
0
  pChannelOpenEvent->DataLength = dataLength;
1356
0
  pChannelOpenEvent->UserData = pUserData;
1357
0
  pChannelOpenEvent->pChannelOpenData = pChannelOpenData;
1358
0
  message.context = channels;
1359
0
  message.id = 0;
1360
0
  message.wParam = pChannelOpenEvent;
1361
0
  message.lParam = nullptr;
1362
0
  message.Free = channel_queue_message_free;
1363
1364
0
  if (!MessageQueue_Dispatch(channels->queue, &message))
1365
0
  {
1366
0
    free(pChannelOpenEvent);
1367
0
    return CHANNEL_RC_NO_MEMORY;
1368
0
  }
1369
1370
0
  return CHANNEL_RC_OK;
1371
0
}
1372
1373
static UINT VCAPITYPE FreeRDP_VirtualChannelWrite(DWORD openHandle, LPVOID pData, ULONG dataLength,
1374
                                                  LPVOID pUserData)
1375
0
{
1376
0
  wMessage message = WINPR_C_ARRAY_INIT;
1377
0
  CHANNEL_OPEN_DATA* pChannelOpenData = nullptr;
1378
0
  CHANNEL_OPEN_EVENT* pChannelOpenEvent = nullptr;
1379
0
  rdpChannels* channels = nullptr;
1380
1381
0
  pChannelOpenData = HashTable_GetItemValue(g_ChannelHandles, (void*)(UINT_PTR)openHandle);
1382
1383
0
  if (!pChannelOpenData)
1384
0
    return CHANNEL_RC_BAD_CHANNEL_HANDLE;
1385
1386
0
  channels = pChannelOpenData->channels;
1387
0
  if (!channels)
1388
0
    return CHANNEL_RC_BAD_CHANNEL_HANDLE;
1389
1390
0
  if (!channels->connected)
1391
0
    return CHANNEL_RC_NOT_CONNECTED;
1392
1393
0
  if (!pData)
1394
0
    return CHANNEL_RC_NULL_DATA;
1395
1396
0
  if (!dataLength)
1397
0
    return CHANNEL_RC_ZERO_LENGTH;
1398
1399
0
  if (pChannelOpenData->flags != 2)
1400
0
    return CHANNEL_RC_NOT_OPEN;
1401
1402
0
  pChannelOpenEvent = (CHANNEL_OPEN_EVENT*)malloc(sizeof(CHANNEL_OPEN_EVENT));
1403
1404
0
  if (!pChannelOpenEvent)
1405
0
    return CHANNEL_RC_NO_MEMORY;
1406
1407
0
  pChannelOpenEvent->Data = pData;
1408
0
  pChannelOpenEvent->DataLength = dataLength;
1409
0
  pChannelOpenEvent->UserData = pUserData;
1410
0
  pChannelOpenEvent->pChannelOpenData = pChannelOpenData;
1411
0
  message.context = channels;
1412
0
  message.id = 0;
1413
0
  message.wParam = pChannelOpenEvent;
1414
0
  message.lParam = nullptr;
1415
0
  message.Free = channel_queue_message_free;
1416
1417
0
  if (!MessageQueue_Dispatch(channels->queue, &message))
1418
0
  {
1419
0
    free(pChannelOpenEvent);
1420
0
    return CHANNEL_RC_NO_MEMORY;
1421
0
  }
1422
1423
0
  return CHANNEL_RC_OK;
1424
0
}
1425
1426
static BOOL freerdp_channels_is_loaded(rdpChannels* channels, PVIRTUALCHANNELENTRY entry)
1427
0
{
1428
0
  for (int i = 0; i < channels->clientDataCount; i++)
1429
0
  {
1430
0
    CHANNEL_CLIENT_DATA* pChannelClientData = &channels->clientDataList[i];
1431
1432
0
    if (pChannelClientData->entry == entry)
1433
0
      return TRUE;
1434
0
  }
1435
1436
0
  return FALSE;
1437
0
}
1438
1439
static BOOL freerdp_channels_is_loaded_ex(rdpChannels* channels, PVIRTUALCHANNELENTRYEX entryEx)
1440
0
{
1441
0
  for (int i = 0; i < channels->clientDataCount; i++)
1442
0
  {
1443
0
    CHANNEL_CLIENT_DATA* pChannelClientData = &channels->clientDataList[i];
1444
1445
0
    if (pChannelClientData->entryEx == entryEx)
1446
0
      return TRUE;
1447
0
  }
1448
1449
0
  return FALSE;
1450
0
}
1451
1452
int freerdp_channels_client_load(rdpChannels* channels, WINPR_ATTR_UNUSED rdpSettings* settings,
1453
                                 PVIRTUALCHANNELENTRY entry, void* data)
1454
0
{
1455
0
  CHANNEL_CLIENT_DATA* pChannelClientData = nullptr;
1456
1457
0
  WINPR_ASSERT(channels);
1458
0
  WINPR_ASSERT(channels->instance);
1459
0
  WINPR_ASSERT(channels->instance->context);
1460
0
  WINPR_ASSERT(entry);
1461
1462
0
  if (channels->clientDataCount + 1 > CHANNEL_MAX_COUNT)
1463
0
  {
1464
0
    WLog_ERR(TAG, "error: too many channels");
1465
0
    return 1;
1466
0
  }
1467
1468
0
  if (freerdp_channels_is_loaded(channels, entry))
1469
0
  {
1470
0
    WLog_WARN(TAG, "Skipping, channel already loaded");
1471
0
    return 0;
1472
0
  }
1473
1474
0
  pChannelClientData = &channels->clientDataList[channels->clientDataCount];
1475
0
  pChannelClientData->entry = entry;
1476
1477
0
  CHANNEL_ENTRY_POINTS_FREERDP EntryPoints = { .cbSize = sizeof(EntryPoints),
1478
0
                                             .protocolVersion = VIRTUAL_CHANNEL_VERSION_WIN2000,
1479
0
                                             .pVirtualChannelInit = FreeRDP_VirtualChannelInit,
1480
0
                                             .pVirtualChannelOpen = FreeRDP_VirtualChannelOpen,
1481
0
                                             .pVirtualChannelClose =
1482
0
                                                 FreeRDP_VirtualChannelClose,
1483
0
                                             .pVirtualChannelWrite =
1484
0
                                                 FreeRDP_VirtualChannelWrite,
1485
0
                                             .MagicNumber = FREERDP_CHANNEL_MAGIC_NUMBER,
1486
0
                                             .pExtendedData = data,
1487
0
                                             .context = channels->instance->context };
1488
  /* enable VirtualChannelInit */
1489
0
  union
1490
0
  {
1491
0
    PCHANNEL_ENTRY_POINTS_FREERDP pfx;
1492
0
    PCHANNEL_ENTRY_POINTS px;
1493
0
  } ptr;
1494
1495
0
  ptr.pfx = &EntryPoints;
1496
1497
0
  channels->can_call_init = TRUE;
1498
0
  EnterCriticalSection(&channels->channelsLock);
1499
0
  const BOOL status = pChannelClientData->entry(ptr.px);
1500
0
  LeaveCriticalSection(&channels->channelsLock);
1501
  /* disable MyVirtualChannelInit */
1502
0
  channels->can_call_init = FALSE;
1503
1504
0
  if (!status)
1505
0
  {
1506
0
    WLog_ERR(TAG, "error: channel export function call failed");
1507
0
    return 1;
1508
0
  }
1509
1510
0
  return 0;
1511
0
}
1512
1513
int freerdp_channels_client_load_ex(rdpChannels* channels, WINPR_ATTR_UNUSED rdpSettings* settings,
1514
                                    PVIRTUALCHANNELENTRYEX entryEx, void* data)
1515
0
{
1516
0
  WINPR_ASSERT(channels);
1517
0
  WINPR_ASSERT(channels->instance);
1518
0
  WINPR_ASSERT(channels->instance->context);
1519
0
  WINPR_ASSERT(entryEx);
1520
1521
0
  if (channels->clientDataCount + 1 > CHANNEL_MAX_COUNT)
1522
0
  {
1523
0
    WLog_ERR(TAG, "error: too many channels");
1524
0
    return 1;
1525
0
  }
1526
1527
0
  if (freerdp_channels_is_loaded_ex(channels, entryEx))
1528
0
  {
1529
0
    WLog_WARN(TAG, "Skipping, channel already loaded");
1530
0
    return 0;
1531
0
  }
1532
1533
0
  CHANNEL_CLIENT_DATA* pChannelClientData = &channels->clientDataList[channels->clientDataCount];
1534
0
  pChannelClientData->entryEx = entryEx;
1535
1536
0
  CHANNEL_INIT_DATA* pChannelInitData = &(channels->initDataList[channels->initDataCount++]);
1537
0
  void* pInitHandle = pChannelInitData;
1538
0
  pChannelInitData->channels = channels;
1539
1540
0
  CHANNEL_ENTRY_POINTS_FREERDP_EX EntryPointsEx = {
1541
0
    .cbSize = sizeof(EntryPointsEx),
1542
0
    .protocolVersion = VIRTUAL_CHANNEL_VERSION_WIN2000,
1543
0
    .pVirtualChannelInitEx = FreeRDP_VirtualChannelInitEx,
1544
0
    .pVirtualChannelOpenEx = FreeRDP_VirtualChannelOpenEx,
1545
0
    .pVirtualChannelCloseEx = FreeRDP_VirtualChannelCloseEx,
1546
0
    .pVirtualChannelWriteEx = FreeRDP_VirtualChannelWriteEx,
1547
0
    .MagicNumber = FREERDP_CHANNEL_MAGIC_NUMBER,
1548
0
    .pExtendedData = data,
1549
0
    .context = channels->instance->context
1550
0
  };
1551
1552
0
  union
1553
0
  {
1554
0
    PCHANNEL_ENTRY_POINTS_FREERDP_EX pfx;
1555
0
    PCHANNEL_ENTRY_POINTS_EX px;
1556
0
  } ptr;
1557
1558
0
  ptr.pfx = &EntryPointsEx;
1559
1560
  /* enable VirtualChannelInit */
1561
0
  channels->can_call_init = TRUE;
1562
0
  EnterCriticalSection(&channels->channelsLock);
1563
0
  const BOOL status = pChannelClientData->entryEx(ptr.px, pInitHandle);
1564
0
  LeaveCriticalSection(&channels->channelsLock);
1565
  /* disable MyVirtualChannelInit */
1566
0
  channels->can_call_init = FALSE;
1567
1568
0
  if (!status)
1569
0
  {
1570
0
    WLog_ERR(TAG, "error: channel export function call failed");
1571
0
    return 1;
1572
0
  }
1573
1574
0
  return 0;
1575
0
}
1576
1577
/**
1578
 * this is called when processing the command line parameters
1579
 * called only from main thread
1580
 */
1581
int freerdp_channels_load_plugin(rdpChannels* channels, rdpSettings* settings, const char* name,
1582
                                 void* data)
1583
0
{
1584
0
  PVIRTUALCHANNELENTRY entry =
1585
0
      freerdp_load_channel_addin_entry(name, nullptr, nullptr, FREERDP_ADDIN_CHANNEL_STATIC);
1586
1587
0
  if (!entry)
1588
0
    return 1;
1589
1590
0
  return freerdp_channels_client_load(channels, settings, entry, data);
1591
0
}