Coverage Report

Created: 2026-03-04 06:17

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