Coverage Report

Created: 2026-10-28 06:54

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