Coverage Report

Created: 2026-07-16 07:14

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