Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/libfreerdp/core/freerdp.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * FreeRDP Core
4
 *
5
 * Copyright 2011 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 <string.h>
27
#include <stdarg.h>
28
#include <time.h>
29
30
#include "rdp.h"
31
#include "input.h"
32
#include "update.h"
33
#include "surface.h"
34
#include "transport.h"
35
#include "connection.h"
36
#include "message.h"
37
#include <freerdp/buildflags.h>
38
#include "gateway/rpc_fault.h"
39
40
#include <winpr/assert.h>
41
42
#include <winpr/crt.h>
43
#include <winpr/string.h>
44
#include <winpr/stream.h>
45
#include <winpr/wtsapi.h>
46
#include <winpr/ssl.h>
47
#include <winpr/debug.h>
48
49
#include <freerdp/freerdp.h>
50
#include <freerdp/streamdump.h>
51
#include <freerdp/error.h>
52
#include <freerdp/event.h>
53
#include <freerdp/locale/keyboard.h>
54
#include <freerdp/channels/channels.h>
55
#include <freerdp/version.h>
56
#include <freerdp/log.h>
57
#include <freerdp/utils/signal.h>
58
59
#include "../cache/pointer.h"
60
#include "utils.h"
61
62
7.99k
#define TAG FREERDP_TAG("core")
63
64
static void sig_abort_connect(int signum, const char* signame, void* ctx)
65
0
{
66
0
  rdpContext* context = (rdpContext*)ctx;
67
68
0
  WLog_INFO(TAG, "Signal %s [%d], terminating session %p", signame, signum, context);
69
0
  if (context)
70
0
    freerdp_abort_connect_context(context);
71
0
}
72
73
/** Creates a new connection based on the settings found in the "instance" parameter
74
 *  It will use the callbacks registered on the structure to process the pre/post connect operations
75
 *  that the caller requires.
76
 *  @see struct rdp_freerdp in freerdp.h
77
 *
78
 *  @param instance - pointer to a rdp_freerdp structure that contains base information to establish
79
 * the connection. On return, this function will be initialized with the new connection's settings.
80
 *
81
 *  @return TRUE if successful. FALSE otherwise.
82
 *
83
 */
84
static int freerdp_connect_begin(freerdp* instance)
85
0
{
86
0
  BOOL rc = 0;
87
0
  rdpRdp* rdp = NULL;
88
0
  BOOL status = TRUE;
89
0
  rdpSettings* settings = NULL;
90
0
  UINT32 KeyboardLayout = 0;
91
92
0
  if (!instance)
93
0
    return -1;
94
95
0
  WINPR_ASSERT(instance->context);
96
97
  /* We always set the return code to 0 before we start the connect sequence*/
98
0
  instance->ConnectionCallbackState = CLIENT_STATE_INITIAL;
99
0
  freerdp_set_last_error_log(instance->context, FREERDP_ERROR_SUCCESS);
100
0
  clearChannelError(instance->context);
101
0
  if (!utils_reset_abort(instance->context->rdp))
102
0
    return -1;
103
104
0
  rdp = instance->context->rdp;
105
0
  WINPR_ASSERT(rdp);
106
107
0
  settings = instance->context->settings;
108
0
  WINPR_ASSERT(settings);
109
110
0
  freerdp_channels_register_instance(instance->context->channels, instance);
111
112
0
  if (!freerdp_settings_set_default_order_support(settings))
113
0
    return -1;
114
115
0
  freerdp_add_signal_cleanup_handler(instance->context, sig_abort_connect);
116
117
0
  IFCALLRET(instance->PreConnect, status, instance);
118
0
  instance->ConnectionCallbackState = CLIENT_STATE_PRECONNECT_PASSED;
119
120
0
  freerdp_settings_print_warnings(settings);
121
122
0
  if (status)
123
0
    status = rdp_set_backup_settings(rdp);
124
0
  if (status)
125
0
    status = utils_reload_channels(instance->context);
126
127
0
  KeyboardLayout = freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout);
128
0
  switch (KeyboardLayout)
129
0
  {
130
0
    case KBD_JAPANESE:
131
0
    case KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002:
132
0
    {
133
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardType,
134
0
                                       WINPR_KBD_TYPE_JAPANESE))
135
0
        return -1;
136
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardSubType, 2))
137
0
        return -1;
138
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardFunctionKey, 12))
139
0
        return -1;
140
0
    }
141
0
    break;
142
0
    default:
143
0
      break;
144
0
  }
145
146
0
  if (!status)
147
0
  {
148
0
    rdpContext* context = instance->context;
149
0
    WINPR_ASSERT(context);
150
0
    freerdp_set_last_error_if_not(context, FREERDP_ERROR_PRE_CONNECT_FAILED);
151
152
0
    WLog_Print(context->log, WLOG_ERROR, "freerdp_pre_connect failed");
153
0
    return 0;
154
0
  }
155
156
0
  rc = rdp_client_connect(rdp);
157
158
  /* --authonly tests the connection without a UI */
159
0
  if (freerdp_settings_get_bool(rdp->settings, FreeRDP_AuthenticationOnly))
160
0
  {
161
0
    rdpContext* context = rdp->context;
162
0
    WINPR_ASSERT(context);
163
0
    WLog_Print(context->log, WLOG_ERROR, "Authentication only, exit status %" PRId32 "", rc);
164
0
    return 0;
165
0
  }
166
167
0
  return rc ? 1 : 0;
168
0
}
169
170
BOOL freerdp_connect(freerdp* instance)
171
0
{
172
0
  BOOL status = FALSE;
173
0
  ConnectionResultEventArgs e = { 0 };
174
0
  const int rc = freerdp_connect_begin(instance);
175
0
  rdpRdp* rdp = NULL;
176
0
  UINT status2 = ERROR_INTERNAL_ERROR;
177
178
0
  WINPR_ASSERT(instance);
179
0
  WINPR_ASSERT(instance->context);
180
181
0
  rdp = instance->context->rdp;
182
0
  WINPR_ASSERT(rdp);
183
0
  WINPR_ASSERT(rdp->settings);
184
185
0
  if (rc < 0)
186
0
    return FALSE;
187
188
0
  if (rc == 0)
189
0
    goto freerdp_connect_finally;
190
191
  /* Pointers might have changed inbetween */
192
0
  {
193
0
    rdp_update_internal* up = update_cast(rdp->update);
194
195
0
    if (freerdp_settings_get_bool(rdp->settings, FreeRDP_DumpRemoteFx))
196
0
    {
197
0
      up->pcap_rfx = pcap_open(
198
0
          freerdp_settings_get_string(rdp->settings, FreeRDP_DumpRemoteFxFile), TRUE);
199
200
0
      if (up->pcap_rfx)
201
0
        up->dump_rfx = TRUE;
202
0
    }
203
0
  }
204
205
0
  if (rc > 0)
206
0
  {
207
0
    pointer_cache_register_callbacks(instance->context->update);
208
0
    status = IFCALLRESULT(TRUE, instance->PostConnect, instance);
209
0
    instance->ConnectionCallbackState = CLIENT_STATE_POSTCONNECT_PASSED;
210
211
0
    if (status)
212
0
      status2 = freerdp_channels_post_connect(instance->context->channels, instance);
213
0
  }
214
0
  else
215
0
  {
216
0
    status2 = CHANNEL_RC_OK;
217
0
    if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_TRANSPORT_FAILED)
218
0
      status = freerdp_reconnect(instance);
219
0
    else
220
0
      goto freerdp_connect_finally;
221
0
  }
222
223
0
  if (!status || (status2 != CHANNEL_RC_OK) || !update_post_connect(instance->context->update))
224
0
  {
225
0
    rdpContext* context = instance->context;
226
0
    WINPR_ASSERT(context);
227
0
    WLog_Print(context->log, WLOG_ERROR, "freerdp_post_connect failed");
228
229
0
    freerdp_set_last_error_if_not(context, FREERDP_ERROR_POST_CONNECT_FAILED);
230
231
0
    status = FALSE;
232
0
    goto freerdp_connect_finally;
233
0
  }
234
235
0
  if (rdp->settings->PlayRemoteFx)
236
0
  {
237
0
    wStream* s = NULL;
238
0
    rdp_update_internal* update = update_cast(instance->context->update);
239
0
    pcap_record record = { 0 };
240
241
0
    WINPR_ASSERT(update);
242
0
    update->pcap_rfx = pcap_open(rdp->settings->PlayRemoteFxFile, FALSE);
243
0
    status = FALSE;
244
245
0
    if (!update->pcap_rfx)
246
0
      goto freerdp_connect_finally;
247
0
    else
248
0
      update->play_rfx = TRUE;
249
250
0
    status = TRUE;
251
252
0
    while (pcap_has_next_record(update->pcap_rfx) && status)
253
0
    {
254
0
      pcap_get_next_record_header(update->pcap_rfx, &record);
255
256
0
      s = transport_take_from_pool(rdp->transport, record.length);
257
0
      if (!s)
258
0
        break;
259
260
0
      record.data = Stream_Buffer(s);
261
0
      pcap_get_next_record_content(update->pcap_rfx, &record);
262
0
      Stream_SetLength(s, record.length);
263
0
      Stream_SetPosition(s, 0);
264
265
0
      if (!update_begin_paint(&update->common))
266
0
        status = FALSE;
267
0
      else
268
0
      {
269
0
        if (update_recv_surfcmds(&update->common, s) < 0)
270
0
          status = FALSE;
271
272
0
        if (!update_end_paint(&update->common))
273
0
          status = FALSE;
274
0
      }
275
276
0
      Stream_Release(s);
277
0
    }
278
279
0
    pcap_close(update->pcap_rfx);
280
0
    update->pcap_rfx = NULL;
281
0
    goto freerdp_connect_finally;
282
0
  }
283
284
0
  if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES)
285
0
    freerdp_set_last_error_log(instance->context, FREERDP_ERROR_INSUFFICIENT_PRIVILEGES);
286
287
0
  transport_set_connected_event(rdp->transport);
288
289
0
freerdp_connect_finally:
290
0
  EventArgsInit(&e, "freerdp");
291
0
  e.result = status ? 0 : -1;
292
0
  PubSub_OnConnectionResult(rdp->pubSub, instance->context, &e);
293
294
0
  if (!status)
295
0
    freerdp_disconnect(instance);
296
297
0
  return status;
298
0
}
299
300
BOOL freerdp_abort_connect(freerdp* instance)
301
0
{
302
0
  if (!instance)
303
0
    return FALSE;
304
305
0
  return freerdp_abort_connect_context(instance->context);
306
0
}
307
308
BOOL freerdp_abort_connect_context(rdpContext* context)
309
0
{
310
0
  if (!context)
311
0
    return FALSE;
312
313
0
  freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
314
315
0
  return utils_abort_connect(context->rdp);
316
0
}
317
318
#if defined(WITH_FREERDP_DEPRECATED)
319
BOOL freerdp_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount)
320
{
321
  rdpRdp* rdp = NULL;
322
323
  WINPR_ASSERT(instance);
324
  WINPR_ASSERT(instance->context);
325
326
  rdp = instance->context->rdp;
327
  WINPR_ASSERT(rdp);
328
329
  transport_get_fds(rdp->transport, rfds, rcount);
330
  return TRUE;
331
}
332
#endif
333
334
BOOL freerdp_check_fds(freerdp* instance)
335
0
{
336
0
  int status = 0;
337
0
  rdpRdp* rdp = NULL;
338
339
0
  if (!instance)
340
0
    return FALSE;
341
342
0
  if (!instance->context)
343
0
    return FALSE;
344
345
0
  if (!instance->context->rdp)
346
0
    return FALSE;
347
348
0
  rdp = instance->context->rdp;
349
0
  status = rdp_check_fds(rdp);
350
351
0
  if (status < 0)
352
0
  {
353
0
    TerminateEventArgs e;
354
0
    rdpContext* context = instance->context;
355
0
    WINPR_ASSERT(context);
356
357
0
    WLog_Print(context->log, WLOG_DEBUG, "rdp_check_fds() - %i", status);
358
0
    EventArgsInit(&e, "freerdp");
359
0
    e.code = 0;
360
0
    PubSub_OnTerminate(rdp->pubSub, context, &e);
361
0
    return FALSE;
362
0
  }
363
364
0
  return TRUE;
365
0
}
366
367
DWORD freerdp_get_event_handles(rdpContext* context, HANDLE* events, DWORD count)
368
0
{
369
0
  DWORD nCount = 0;
370
371
0
  WINPR_ASSERT(context);
372
0
  WINPR_ASSERT(context->rdp);
373
0
  WINPR_ASSERT(events || (count == 0));
374
375
0
  nCount += transport_get_event_handles(context->rdp->transport, events, count);
376
377
0
  if (nCount == 0)
378
0
    return 0;
379
380
0
  if (events && (nCount < count + 2))
381
0
  {
382
0
    events[nCount++] = freerdp_channels_get_event_handle(context->instance);
383
0
    events[nCount++] = getChannelErrorEventHandle(context);
384
0
    events[nCount++] = utils_get_abort_event(context->rdp);
385
0
  }
386
0
  else
387
0
    return 0;
388
389
0
  return nCount;
390
0
}
391
392
/* Resend mouse cursor position to prevent session lock in prevent-session-lock mode */
393
static BOOL freerdp_prevent_session_lock(rdpContext* context)
394
0
{
395
0
  WINPR_ASSERT(context);
396
0
  WINPR_ASSERT(context->input);
397
398
0
  rdp_input_internal* in = input_cast(context->input);
399
400
0
  UINT32 FakeMouseMotionInterval =
401
0
      freerdp_settings_get_uint32(context->settings, FreeRDP_FakeMouseMotionInterval);
402
0
  if (FakeMouseMotionInterval && in->lastInputTimestamp)
403
0
  {
404
0
    const time_t now = time(NULL);
405
0
    if (now - in->lastInputTimestamp > FakeMouseMotionInterval)
406
0
    {
407
0
      WLog_Print(context->log, WLOG_DEBUG,
408
0
                 "fake mouse move: x=%d y=%d lastInputTimestamp=%" PRIu64 " "
409
0
                 "FakeMouseMotionInterval=%" PRIu32,
410
0
                 in->lastX, in->lastY, in->lastInputTimestamp, FakeMouseMotionInterval);
411
412
0
      BOOL status = freerdp_input_send_mouse_event(context->input, PTR_FLAGS_MOVE, in->lastX,
413
0
                                                   in->lastY);
414
0
      if (!status)
415
0
      {
416
0
        if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
417
0
          WLog_Print(context->log, WLOG_ERROR,
418
0
                     "freerdp_prevent_session_lock() failed - %" PRIi32 "", status);
419
420
0
        return FALSE;
421
0
      }
422
423
0
      return status;
424
0
    }
425
0
  }
426
427
0
  return TRUE;
428
0
}
429
430
BOOL freerdp_check_event_handles(rdpContext* context)
431
0
{
432
0
  WINPR_ASSERT(context);
433
434
0
  BOOL status = freerdp_check_fds(context->instance);
435
436
0
  if (!status)
437
0
  {
438
0
    if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
439
0
      WLog_Print(context->log, WLOG_ERROR, "freerdp_check_fds() failed - %" PRIi32 "",
440
0
                 status);
441
442
0
    return FALSE;
443
0
  }
444
445
0
  status = freerdp_channels_check_fds(context->channels, context->instance);
446
447
0
  if (!status)
448
0
  {
449
0
    if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
450
0
      WLog_Print(context->log, WLOG_ERROR,
451
0
                 "freerdp_channels_check_fds() failed - %" PRIi32 "", status);
452
453
0
    return FALSE;
454
0
  }
455
456
0
  status = checkChannelErrorEvent(context);
457
458
0
  if (!status)
459
0
  {
460
0
    if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
461
0
      WLog_Print(context->log, WLOG_ERROR, "checkChannelErrorEvent() failed - %" PRIi32 "",
462
0
                 status);
463
464
0
    return FALSE;
465
0
  }
466
467
0
  status = freerdp_prevent_session_lock(context);
468
469
0
  return status;
470
0
}
471
472
wMessageQueue* freerdp_get_message_queue(freerdp* instance, DWORD id)
473
0
{
474
0
  wMessageQueue* queue = NULL;
475
476
0
  WINPR_ASSERT(instance);
477
478
0
  rdpContext* context = instance->context;
479
0
  WINPR_ASSERT(context);
480
481
0
  switch (id)
482
0
  {
483
0
    case FREERDP_UPDATE_MESSAGE_QUEUE:
484
0
    {
485
0
      rdp_update_internal* update = update_cast(context->update);
486
0
      queue = update->queue;
487
0
    }
488
0
    break;
489
490
0
    case FREERDP_INPUT_MESSAGE_QUEUE:
491
0
    {
492
0
      rdp_input_internal* input = input_cast(context->input);
493
0
      queue = input->queue;
494
0
    }
495
0
    break;
496
0
  }
497
498
0
  return queue;
499
0
}
500
501
HANDLE freerdp_get_message_queue_event_handle(freerdp* instance, DWORD id)
502
0
{
503
0
  HANDLE event = NULL;
504
0
  wMessageQueue* queue = freerdp_get_message_queue(instance, id);
505
506
0
  if (queue)
507
0
    event = MessageQueue_Event(queue);
508
509
0
  return event;
510
0
}
511
512
int freerdp_message_queue_process_message(freerdp* instance, DWORD id, wMessage* message)
513
0
{
514
0
  int status = -1;
515
0
  rdpContext* context = NULL;
516
517
0
  WINPR_ASSERT(instance);
518
519
0
  context = instance->context;
520
0
  WINPR_ASSERT(context);
521
522
0
  switch (id)
523
0
  {
524
0
    case FREERDP_UPDATE_MESSAGE_QUEUE:
525
0
      status = update_message_queue_process_message(context->update, message);
526
0
      break;
527
528
0
    case FREERDP_INPUT_MESSAGE_QUEUE:
529
0
      status = input_message_queue_process_message(context->input, message);
530
0
      break;
531
0
  }
532
533
0
  return status;
534
0
}
535
536
int freerdp_message_queue_process_pending_messages(freerdp* instance, DWORD id)
537
0
{
538
0
  int status = -1;
539
0
  rdpContext* context = NULL;
540
541
0
  WINPR_ASSERT(instance);
542
543
0
  context = instance->context;
544
0
  WINPR_ASSERT(context);
545
546
0
  switch (id)
547
0
  {
548
0
    case FREERDP_UPDATE_MESSAGE_QUEUE:
549
0
      status = update_message_queue_process_pending_messages(context->update);
550
0
      break;
551
552
0
    case FREERDP_INPUT_MESSAGE_QUEUE:
553
0
      status = input_message_queue_process_pending_messages(context->input);
554
0
      break;
555
0
  }
556
557
0
  return status;
558
0
}
559
560
static BOOL freerdp_send_channel_data(freerdp* instance, UINT16 channelId, const BYTE* data,
561
                                      size_t size)
562
0
{
563
0
  WINPR_ASSERT(instance);
564
0
  WINPR_ASSERT(instance->context);
565
0
  WINPR_ASSERT(instance->context->rdp);
566
0
  return rdp_send_channel_data(instance->context->rdp, channelId, data, size);
567
0
}
568
569
static BOOL freerdp_send_channel_packet(freerdp* instance, UINT16 channelId, size_t totalSize,
570
                                        UINT32 flags, const BYTE* data, size_t chunkSize)
571
0
{
572
0
  WINPR_ASSERT(instance);
573
0
  WINPR_ASSERT(instance->context);
574
0
  WINPR_ASSERT(instance->context->rdp);
575
0
  return rdp_channel_send_packet(instance->context->rdp, channelId, totalSize, flags, data,
576
0
                                 chunkSize);
577
0
}
578
579
BOOL freerdp_disconnect(freerdp* instance)
580
0
{
581
0
  BOOL rc = TRUE;
582
0
  rdpRdp* rdp = NULL;
583
0
  rdp_update_internal* up = NULL;
584
585
0
  if (!instance || !instance->context)
586
0
    return FALSE;
587
588
0
  rdp = instance->context->rdp;
589
0
  utils_abort_connect(rdp);
590
591
0
  if (!rdp_client_disconnect(rdp))
592
0
    rc = FALSE;
593
594
0
  up = update_cast(rdp->update);
595
596
0
  update_post_disconnect(rdp->update);
597
598
0
  IFCALL(instance->PostDisconnect, instance);
599
600
0
  if (up->pcap_rfx)
601
0
  {
602
0
    up->dump_rfx = FALSE;
603
0
    pcap_close(up->pcap_rfx);
604
0
    up->pcap_rfx = NULL;
605
0
  }
606
607
0
  freerdp_channels_close(instance->context->channels, instance);
608
609
0
  IFCALL(instance->PostFinalDisconnect, instance);
610
611
0
  freerdp_del_signal_cleanup_handler(instance->context, sig_abort_connect);
612
0
  return rc;
613
0
}
614
615
BOOL freerdp_disconnect_before_reconnect(freerdp* instance)
616
0
{
617
0
  WINPR_ASSERT(instance);
618
0
  return freerdp_disconnect_before_reconnect_context(instance->context);
619
0
}
620
621
BOOL freerdp_disconnect_before_reconnect_context(rdpContext* context)
622
0
{
623
0
  rdpRdp* rdp = NULL;
624
625
0
  WINPR_ASSERT(context);
626
627
0
  rdp = context->rdp;
628
0
  return rdp_client_disconnect_and_clear(rdp);
629
0
}
630
631
BOOL freerdp_reconnect(freerdp* instance)
632
0
{
633
0
  rdpRdp* rdp = NULL;
634
635
0
  WINPR_ASSERT(instance);
636
0
  WINPR_ASSERT(instance->context);
637
638
0
  if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_CANCELLED)
639
0
    return FALSE;
640
641
0
  rdp = instance->context->rdp;
642
643
0
  if (!utils_reset_abort(instance->context->rdp))
644
0
    return FALSE;
645
0
  return rdp_client_reconnect(rdp);
646
0
}
647
648
BOOL freerdp_shall_disconnect(freerdp* instance)
649
0
{
650
0
  if (!instance)
651
0
    return FALSE;
652
653
0
  return freerdp_shall_disconnect_context(instance->context);
654
0
}
655
656
BOOL freerdp_shall_disconnect_context(rdpContext* context)
657
235
{
658
235
  if (!context)
659
0
    return FALSE;
660
661
235
  return utils_abort_event_is_set(context->rdp);
662
235
}
663
664
BOOL freerdp_focus_required(freerdp* instance)
665
0
{
666
0
  rdpRdp* rdp = NULL;
667
0
  BOOL bRetCode = FALSE;
668
669
0
  WINPR_ASSERT(instance);
670
0
  WINPR_ASSERT(instance->context);
671
672
0
  rdp = instance->context->rdp;
673
0
  WINPR_ASSERT(rdp);
674
675
0
  if (rdp->resendFocus)
676
0
  {
677
0
    bRetCode = TRUE;
678
0
    rdp->resendFocus = FALSE;
679
0
  }
680
681
0
  return bRetCode;
682
0
}
683
684
void freerdp_set_focus(freerdp* instance)
685
0
{
686
0
  rdpRdp* rdp = NULL;
687
688
0
  WINPR_ASSERT(instance);
689
0
  WINPR_ASSERT(instance->context);
690
691
0
  rdp = instance->context->rdp;
692
0
  WINPR_ASSERT(rdp);
693
694
0
  rdp->resendFocus = TRUE;
695
0
}
696
697
void freerdp_get_version(int* major, int* minor, int* revision)
698
0
{
699
0
  if (major != NULL)
700
0
    *major = FREERDP_VERSION_MAJOR;
701
702
0
  if (minor != NULL)
703
0
    *minor = FREERDP_VERSION_MINOR;
704
705
0
  if (revision != NULL)
706
0
    *revision = FREERDP_VERSION_REVISION;
707
0
}
708
709
const char* freerdp_get_version_string(void)
710
0
{
711
0
  return FREERDP_VERSION_FULL;
712
0
}
713
714
const char* freerdp_get_build_config(void)
715
0
{
716
0
  static const char build_config[] =
717
0
      "Build configuration: " FREERDP_BUILD_CONFIG "\n"
718
0
      "Build type:          " FREERDP_BUILD_TYPE "\n"
719
0
      "CFLAGS:              " FREERDP_CFLAGS "\n"
720
0
      "Compiler:            " FREERDP_COMPILER_ID ", " FREERDP_COMPILER_VERSION "\n"
721
0
      "Target architecture: " FREERDP_TARGET_ARCH "\n";
722
0
  return build_config;
723
0
}
724
725
const char* freerdp_get_build_revision(void)
726
0
{
727
0
  return FREERDP_GIT_REVISION;
728
0
}
729
730
static wEventType FreeRDP_Events[] = {
731
  DEFINE_EVENT_ENTRY(WindowStateChange),   DEFINE_EVENT_ENTRY(ResizeWindow),
732
  DEFINE_EVENT_ENTRY(LocalResizeWindow),   DEFINE_EVENT_ENTRY(EmbedWindow),
733
  DEFINE_EVENT_ENTRY(PanningChange),       DEFINE_EVENT_ENTRY(ZoomingChange),
734
  DEFINE_EVENT_ENTRY(ErrorInfo),           DEFINE_EVENT_ENTRY(Terminate),
735
  DEFINE_EVENT_ENTRY(ConnectionResult),    DEFINE_EVENT_ENTRY(ChannelConnected),
736
  DEFINE_EVENT_ENTRY(ChannelDisconnected), DEFINE_EVENT_ENTRY(MouseEvent),
737
  DEFINE_EVENT_ENTRY(Activated),           DEFINE_EVENT_ENTRY(Timer),
738
  DEFINE_EVENT_ENTRY(GraphicsReset)
739
};
740
741
/** Allocator function for a rdp context.
742
 *  The function will allocate a rdpRdp structure using rdp_new(), then copy
743
 *  its contents to the appropriate fields in the rdp_freerdp structure given in parameters.
744
 *  It will also initialize the 'context' field in the rdp_freerdp structure as needed.
745
 *  If the caller has set the ContextNew callback in the 'instance' parameter, it will be called at
746
 * the end of the function.
747
 *
748
 *  @param instance - Pointer to the rdp_freerdp structure that will be initialized with the new
749
 * context.
750
 */
751
BOOL freerdp_context_new(freerdp* instance)
752
0
{
753
0
  return freerdp_context_new_ex(instance, NULL);
754
0
}
755
756
BOOL freerdp_context_new_ex(freerdp* instance, rdpSettings* settings)
757
7.99k
{
758
7.99k
  rdpRdp* rdp = NULL;
759
7.99k
  rdpContext* context = NULL;
760
7.99k
  BOOL ret = TRUE;
761
762
7.99k
  WINPR_ASSERT(instance);
763
764
7.99k
  instance->context = context = (rdpContext*)calloc(1, instance->ContextSize);
765
766
7.99k
  if (!context)
767
0
    return FALSE;
768
769
7.99k
  context->log = WLog_Get(TAG);
770
7.99k
  if (!context->log)
771
0
    goto fail;
772
773
  /* Set to external settings, prevents rdp_new from creating its own instance */
774
7.99k
  context->settings = settings;
775
7.99k
  context->instance = instance;
776
7.99k
  context->ServerMode = FALSE;
777
7.99k
  context->disconnectUltimatum = 0;
778
779
7.99k
  context->metrics = metrics_new(context);
780
781
7.99k
  if (!context->metrics)
782
0
    goto fail;
783
784
7.99k
  rdp = rdp_new(context);
785
786
7.99k
  if (!rdp)
787
0
    goto fail;
788
789
7.99k
  rdp_log_build_warnings(rdp);
790
7.99k
  context->rdp = rdp;
791
7.99k
  context->pubSub = rdp->pubSub;
792
793
7.99k
  if (!context->pubSub)
794
0
    goto fail;
795
796
7.99k
  PubSub_AddEventTypes(rdp->pubSub, FreeRDP_Events, ARRAYSIZE(FreeRDP_Events));
797
798
#if defined(WITH_FREERDP_DEPRECATED)
799
  instance->input = rdp->input;
800
  instance->update = rdp->update;
801
  instance->settings = rdp->settings;
802
  instance->autodetect = rdp->autodetect;
803
#endif
804
805
7.99k
  instance->heartbeat = rdp->heartbeat;
806
7.99k
  context->graphics = graphics_new(context);
807
808
7.99k
  if (!context->graphics)
809
0
    goto fail;
810
811
7.99k
  context->input = rdp->input;
812
7.99k
  context->update = rdp->update;
813
7.99k
  context->settings = rdp->settings;
814
7.99k
  context->autodetect = rdp->autodetect;
815
816
7.99k
  if (!(context->errorDescription = calloc(1, 500)))
817
0
  {
818
0
    WLog_Print(context->log, WLOG_ERROR, "calloc failed!");
819
0
    goto fail;
820
0
  }
821
822
7.99k
  if (!(context->channelErrorEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
823
0
  {
824
0
    WLog_Print(context->log, WLOG_ERROR, "CreateEvent failed!");
825
0
    goto fail;
826
0
  }
827
828
7.99k
  update_register_client_callbacks(rdp->update);
829
830
7.99k
  if (!(context->channels = freerdp_channels_new(instance)))
831
0
    goto fail;
832
833
7.99k
  context->dump = stream_dump_new();
834
7.99k
  if (!context->dump)
835
0
    goto fail;
836
837
7.99k
  IFCALLRET(instance->ContextNew, ret, instance, context);
838
839
7.99k
  if (ret)
840
7.99k
    return TRUE;
841
842
0
fail:
843
0
  freerdp_context_free(instance);
844
0
  return FALSE;
845
7.99k
}
846
847
BOOL freerdp_context_reset(freerdp* instance)
848
0
{
849
0
  if (!instance)
850
0
    return FALSE;
851
852
0
  WINPR_ASSERT(instance->context);
853
0
  rdpRdp* rdp = instance->context->rdp;
854
855
0
  return rdp_reset_runtime_settings(rdp);
856
0
}
857
858
/** Deallocator function for a rdp context.
859
 *  The function will deallocate the resources from the 'instance' parameter that were allocated
860
 * from a call to freerdp_context_new(). If the ContextFree callback is set in the 'instance'
861
 * parameter, it will be called before deallocation occurs.
862
 *
863
 *  @param instance - Pointer to the rdp_freerdp structure that was initialized by a call to
864
 * freerdp_context_new(). On return, the fields associated to the context are invalid.
865
 */
866
void freerdp_context_free(freerdp* instance)
867
7.99k
{
868
7.99k
  rdpContext* ctx = NULL;
869
870
7.99k
  if (!instance)
871
0
    return;
872
873
7.99k
  if (!instance->context)
874
0
    return;
875
876
7.99k
  ctx = instance->context;
877
878
7.99k
  IFCALL(instance->ContextFree, instance, ctx);
879
7.99k
  rdp_free(ctx->rdp);
880
7.99k
  ctx->rdp = NULL;
881
7.99k
  ctx->settings = NULL; /* owned by rdpRdp */
882
883
7.99k
  graphics_free(ctx->graphics);
884
7.99k
  ctx->graphics = NULL;
885
886
7.99k
  metrics_free(ctx->metrics);
887
7.99k
  ctx->metrics = NULL;
888
889
7.99k
  if (ctx->channelErrorEvent)
890
7.99k
    CloseHandle(ctx->channelErrorEvent);
891
7.99k
  ctx->channelErrorEvent = NULL;
892
893
7.99k
  free(ctx->errorDescription);
894
7.99k
  ctx->errorDescription = NULL;
895
896
7.99k
  freerdp_channels_free(ctx->channels);
897
7.99k
  ctx->channels = NULL;
898
899
7.99k
  codecs_free(ctx->codecs);
900
7.99k
  ctx->codecs = NULL;
901
902
7.99k
  stream_dump_free(ctx->dump);
903
7.99k
  ctx->dump = NULL;
904
905
7.99k
  ctx->input = NULL;      /* owned by rdpRdp */
906
7.99k
  ctx->update = NULL;     /* owned by rdpRdp */
907
7.99k
  ctx->settings = NULL;   /* owned by rdpRdp */
908
7.99k
  ctx->autodetect = NULL; /* owned by rdpRdp */
909
910
7.99k
  free(ctx);
911
7.99k
  instance->context = NULL;
912
#if defined(WITH_FREERDP_DEPRECATED)
913
  instance->input = NULL;      /* owned by rdpRdp */
914
  instance->update = NULL;     /* owned by rdpRdp */
915
  instance->settings = NULL;   /* owned by rdpRdp */
916
  instance->autodetect = NULL; /* owned by rdpRdp */
917
#endif
918
7.99k
  instance->heartbeat = NULL; /* owned by rdpRdp */
919
7.99k
}
920
921
int freerdp_get_disconnect_ultimatum(rdpContext* context)
922
0
{
923
0
  WINPR_ASSERT(context);
924
0
  return context->disconnectUltimatum;
925
0
}
926
927
UINT32 freerdp_error_info(freerdp* instance)
928
0
{
929
0
  WINPR_ASSERT(instance);
930
0
  WINPR_ASSERT(instance->context);
931
0
  WINPR_ASSERT(instance->context->rdp);
932
0
  return instance->context->rdp->errorInfo;
933
0
}
934
935
void freerdp_set_error_info(rdpRdp* rdp, UINT32 error)
936
0
{
937
0
  if (!rdp)
938
0
    return;
939
940
0
  rdp_set_error_info(rdp, error);
941
0
}
942
943
BOOL freerdp_send_error_info(rdpRdp* rdp)
944
0
{
945
0
  if (!rdp)
946
0
    return FALSE;
947
948
0
  return rdp_send_error_info(rdp);
949
0
}
950
951
UINT32 freerdp_get_last_error(rdpContext* context)
952
3.28k
{
953
3.28k
  WINPR_ASSERT(context);
954
3.28k
  return context->LastError;
955
3.28k
}
956
957
const char* freerdp_get_last_error_name(UINT32 code)
958
4.09k
{
959
4.09k
  const char* name = NULL;
960
4.09k
  const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
961
4.09k
  const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
962
963
4.09k
  switch (cls)
964
4.09k
  {
965
0
    case FREERDP_ERROR_ERRBASE_CLASS:
966
0
      name = freerdp_get_error_base_name(type);
967
0
      break;
968
969
599
    case FREERDP_ERROR_ERRINFO_CLASS:
970
599
      name = freerdp_get_error_info_name(type);
971
599
      break;
972
973
3.19k
    case FREERDP_ERROR_CONNECT_CLASS:
974
3.19k
      name = freerdp_get_error_connect_name(type);
975
3.19k
      break;
976
977
303
    default:
978
303
      name = rpc_error_to_string(code);
979
303
      break;
980
4.09k
  }
981
982
4.09k
  return name;
983
4.09k
}
984
985
const char* freerdp_get_last_error_string(UINT32 code)
986
0
{
987
0
  const char* string = NULL;
988
0
  const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
989
0
  const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
990
991
0
  switch (cls)
992
0
  {
993
0
    case FREERDP_ERROR_ERRBASE_CLASS:
994
0
      string = freerdp_get_error_base_string(type);
995
0
      break;
996
997
0
    case FREERDP_ERROR_ERRINFO_CLASS:
998
0
      string = freerdp_get_error_info_string(type);
999
0
      break;
1000
1001
0
    case FREERDP_ERROR_CONNECT_CLASS:
1002
0
      string = freerdp_get_error_connect_string(type);
1003
0
      break;
1004
1005
0
    default:
1006
0
      string = rpc_error_to_string(code);
1007
0
      break;
1008
0
  }
1009
1010
0
  return string;
1011
0
}
1012
1013
const char* freerdp_get_last_error_category(UINT32 code)
1014
0
{
1015
0
  const char* string = NULL;
1016
0
  const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
1017
0
  const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
1018
1019
0
  switch (cls)
1020
0
  {
1021
0
    case FREERDP_ERROR_ERRBASE_CLASS:
1022
0
      string = freerdp_get_error_base_category(type);
1023
0
      break;
1024
1025
0
    case FREERDP_ERROR_ERRINFO_CLASS:
1026
0
      string = freerdp_get_error_info_category(type);
1027
0
      break;
1028
1029
0
    case FREERDP_ERROR_CONNECT_CLASS:
1030
0
      string = freerdp_get_error_connect_category(type);
1031
0
      break;
1032
1033
0
    default:
1034
0
      string = rpc_error_to_category(code);
1035
0
      break;
1036
0
  }
1037
1038
0
  return string;
1039
0
}
1040
1041
void freerdp_set_last_error_ex(rdpContext* context, UINT32 lastError, const char* fkt,
1042
                               const char* file, int line)
1043
3.97k
{
1044
3.97k
  WINPR_ASSERT(context);
1045
1046
3.97k
  if (lastError)
1047
3.96k
  {
1048
3.96k
    if (WLog_IsLevelActive(context->log, WLOG_ERROR))
1049
3.96k
    {
1050
3.96k
      WLog_PrintMessage(context->log, WLOG_MESSAGE_TEXT, WLOG_ERROR, line, file, fkt,
1051
3.96k
                        "%s [0x%08" PRIX32 "]", freerdp_get_last_error_name(lastError),
1052
3.96k
                        lastError);
1053
3.96k
    }
1054
3.96k
  }
1055
1056
3.97k
  if (lastError == FREERDP_ERROR_SUCCESS)
1057
15
  {
1058
15
    if (WLog_IsLevelActive(context->log, WLOG_DEBUG))
1059
0
      WLog_PrintMessage(context->log, WLOG_MESSAGE_TEXT, WLOG_DEBUG, line, file, fkt,
1060
0
                        "resetting error state");
1061
15
  }
1062
3.96k
  else if (context->LastError != FREERDP_ERROR_SUCCESS)
1063
69
  {
1064
69
    if (WLog_IsLevelActive(context->log, WLOG_ERROR))
1065
69
    {
1066
69
      WLog_PrintMessage(context->log, WLOG_MESSAGE_TEXT, WLOG_ERROR, line, file, fkt,
1067
69
                        "TODO: Trying to set error code %s, but %s already set!",
1068
69
                        freerdp_get_last_error_name(lastError),
1069
69
                        freerdp_get_last_error_name(context->LastError));
1070
69
    }
1071
69
  }
1072
3.97k
  context->LastError = lastError;
1073
3.97k
}
1074
1075
const char* freerdp_get_logon_error_info_type_ex(UINT32 type, char* buffer, size_t size)
1076
0
{
1077
0
  const char* str = freerdp_get_logon_error_info_type(type);
1078
0
  _snprintf(buffer, size, "%s(0x%04" PRIx32 ")", str, type);
1079
0
  return buffer;
1080
0
}
1081
1082
const char* freerdp_get_logon_error_info_type(UINT32 type)
1083
113
{
1084
113
  switch (type)
1085
113
  {
1086
0
    case LOGON_MSG_DISCONNECT_REFUSED:
1087
0
      return "LOGON_MSG_DISCONNECT_REFUSED";
1088
1089
0
    case LOGON_MSG_NO_PERMISSION:
1090
0
      return "LOGON_MSG_NO_PERMISSION";
1091
1092
0
    case LOGON_MSG_BUMP_OPTIONS:
1093
0
      return "LOGON_MSG_BUMP_OPTIONS";
1094
1095
0
    case LOGON_MSG_RECONNECT_OPTIONS:
1096
0
      return "LOGON_MSG_RECONNECT_OPTIONS";
1097
1098
0
    case LOGON_MSG_SESSION_TERMINATE:
1099
0
      return "LOGON_MSG_SESSION_TERMINATE";
1100
1101
1
    case LOGON_MSG_SESSION_CONTINUE:
1102
1
      return "LOGON_MSG_SESSION_CONTINUE";
1103
1104
112
    default:
1105
112
      return "UNKNOWN";
1106
113
  }
1107
113
}
1108
1109
const char* freerdp_get_logon_error_info_data(UINT32 data)
1110
113
{
1111
113
  switch (data)
1112
113
  {
1113
29
    case LOGON_FAILED_BAD_PASSWORD:
1114
29
      return "LOGON_FAILED_BAD_PASSWORD";
1115
1116
1
    case LOGON_FAILED_UPDATE_PASSWORD:
1117
1
      return "LOGON_FAILED_UPDATE_PASSWORD";
1118
1119
0
    case LOGON_FAILED_OTHER:
1120
0
      return "LOGON_FAILED_OTHER";
1121
1122
0
    case LOGON_WARNING:
1123
0
      return "LOGON_WARNING";
1124
1125
83
    default:
1126
83
      return "SESSION_ID";
1127
113
  }
1128
113
}
1129
1130
const char* freerdp_get_logon_error_info_data_ex(UINT32 data, char* buffer, size_t size)
1131
0
{
1132
0
  const char* str = freerdp_get_logon_error_info_data(data);
1133
0
  _snprintf(buffer, size, "%s(0x%04" PRIx32 ")", str, data);
1134
0
  return buffer;
1135
0
}
1136
1137
/** Allocator function for the rdp_freerdp structure.
1138
 *  @return an allocated structure filled with 0s. Need to be deallocated using freerdp_free()
1139
 */
1140
freerdp* freerdp_new(void)
1141
7.99k
{
1142
7.99k
  freerdp* instance = NULL;
1143
7.99k
  instance = (freerdp*)calloc(1, sizeof(freerdp));
1144
1145
7.99k
  if (!instance)
1146
0
    return NULL;
1147
1148
7.99k
  instance->ContextSize = sizeof(rdpContext);
1149
7.99k
  instance->SendChannelData = freerdp_send_channel_data;
1150
7.99k
  instance->SendChannelPacket = freerdp_send_channel_packet;
1151
7.99k
  instance->ReceiveChannelData = freerdp_channels_data;
1152
7.99k
  return instance;
1153
7.99k
}
1154
1155
/** Deallocator function for the rdp_freerdp structure.
1156
 *  @param instance - pointer to the rdp_freerdp structure to deallocate.
1157
 *                    On return, this pointer is not valid anymore.
1158
 */
1159
void freerdp_free(freerdp* instance)
1160
7.99k
{
1161
7.99k
  free(instance);
1162
7.99k
}
1163
1164
ULONG freerdp_get_transport_sent(rdpContext* context, BOOL resetCount)
1165
0
{
1166
0
  WINPR_ASSERT(context);
1167
0
  WINPR_ASSERT(context->rdp);
1168
0
  return transport_get_bytes_sent(context->rdp->transport, resetCount);
1169
0
}
1170
1171
BOOL freerdp_nla_impersonate(rdpContext* context)
1172
0
{
1173
0
  rdpNla* nla = NULL;
1174
1175
0
  if (!context)
1176
0
    return FALSE;
1177
1178
0
  if (!context->rdp)
1179
0
    return FALSE;
1180
1181
0
  if (!context->rdp->transport)
1182
0
    return FALSE;
1183
1184
0
  nla = transport_get_nla(context->rdp->transport);
1185
0
  return nla_impersonate(nla);
1186
0
}
1187
1188
BOOL freerdp_nla_revert_to_self(rdpContext* context)
1189
0
{
1190
0
  rdpNla* nla = NULL;
1191
1192
0
  if (!context)
1193
0
    return FALSE;
1194
1195
0
  if (!context->rdp)
1196
0
    return FALSE;
1197
1198
0
  if (!context->rdp->transport)
1199
0
    return FALSE;
1200
1201
0
  nla = transport_get_nla(context->rdp->transport);
1202
0
  return nla_revert_to_self(nla);
1203
0
}
1204
1205
UINT32 freerdp_get_nla_sspi_error(rdpContext* context)
1206
0
{
1207
0
  rdpNla* nla = NULL;
1208
1209
0
  WINPR_ASSERT(context);
1210
0
  WINPR_ASSERT(context->rdp);
1211
0
  WINPR_ASSERT(context->rdp->transport);
1212
1213
0
  nla = transport_get_nla(context->rdp->transport);
1214
1215
0
  return nla_get_sspi_error(nla);
1216
0
}
1217
1218
HANDLE getChannelErrorEventHandle(rdpContext* context)
1219
0
{
1220
0
  WINPR_ASSERT(context);
1221
0
  return context->channelErrorEvent;
1222
0
}
1223
1224
BOOL checkChannelErrorEvent(rdpContext* context)
1225
0
{
1226
0
  WINPR_ASSERT(context);
1227
1228
0
  if (WaitForSingleObject(context->channelErrorEvent, 0) == WAIT_OBJECT_0)
1229
0
  {
1230
0
    WLog_Print(context->log, WLOG_ERROR, "%s. Error was %" PRIu32 "", context->errorDescription,
1231
0
               context->channelErrorNum);
1232
0
    return FALSE;
1233
0
  }
1234
1235
0
  return TRUE;
1236
0
}
1237
1238
/**
1239
 * Function description
1240
 *
1241
 * @return 0 on success, otherwise a Win32 error code
1242
 */
1243
UINT getChannelError(rdpContext* context)
1244
0
{
1245
0
  WINPR_ASSERT(context);
1246
0
  return context->channelErrorNum;
1247
0
}
1248
1249
const char* getChannelErrorDescription(rdpContext* context)
1250
0
{
1251
0
  WINPR_ASSERT(context);
1252
0
  return context->errorDescription;
1253
0
}
1254
1255
void clearChannelError(rdpContext* context)
1256
0
{
1257
0
  WINPR_ASSERT(context);
1258
0
  context->channelErrorNum = 0;
1259
0
  memset(context->errorDescription, 0, 500);
1260
0
  ResetEvent(context->channelErrorEvent);
1261
0
}
1262
1263
WINPR_ATTR_FORMAT_ARG(3, 4)
1264
void setChannelError(rdpContext* context, UINT errorNum, WINPR_FORMAT_ARG const char* format, ...)
1265
0
{
1266
0
  va_list ap;
1267
0
  va_start(ap, format);
1268
1269
0
  WINPR_ASSERT(context);
1270
1271
0
  context->channelErrorNum = errorNum;
1272
0
  vsnprintf(context->errorDescription, 499, format, ap);
1273
0
  va_end(ap);
1274
0
  SetEvent(context->channelErrorEvent);
1275
0
}
1276
1277
const char* freerdp_nego_get_routing_token(rdpContext* context, DWORD* length)
1278
0
{
1279
0
  if (!context || !context->rdp)
1280
0
    return NULL;
1281
1282
0
  return (const char*)nego_get_routing_token(context->rdp->nego, length);
1283
0
}
1284
1285
BOOL freerdp_io_callback_set_event(rdpContext* context, BOOL set)
1286
0
{
1287
0
  WINPR_ASSERT(context);
1288
0
  return rdp_io_callback_set_event(context->rdp, set);
1289
0
}
1290
1291
const rdpTransportIo* freerdp_get_io_callbacks(rdpContext* context)
1292
0
{
1293
0
  WINPR_ASSERT(context);
1294
0
  return rdp_get_io_callbacks(context->rdp);
1295
0
}
1296
1297
BOOL freerdp_set_io_callbacks(rdpContext* context, const rdpTransportIo* io_callbacks)
1298
0
{
1299
0
  WINPR_ASSERT(context);
1300
0
  return rdp_set_io_callbacks(context->rdp, io_callbacks);
1301
0
}
1302
1303
BOOL freerdp_set_io_callback_context(rdpContext* context, void* usercontext)
1304
0
{
1305
0
  WINPR_ASSERT(context);
1306
0
  return rdp_set_io_callback_context(context->rdp, usercontext);
1307
0
}
1308
1309
void* freerdp_get_io_callback_context(rdpContext* context)
1310
0
{
1311
0
  WINPR_ASSERT(context);
1312
0
  return rdp_get_io_callback_context(context->rdp);
1313
0
}
1314
1315
CONNECTION_STATE freerdp_get_state(const rdpContext* context)
1316
0
{
1317
0
  WINPR_ASSERT(context);
1318
0
  return rdp_get_state(context->rdp);
1319
0
}
1320
1321
const char* freerdp_state_string(CONNECTION_STATE state)
1322
0
{
1323
0
  return rdp_state_string(state);
1324
0
}
1325
1326
BOOL freerdp_is_active_state(const rdpContext* context)
1327
0
{
1328
0
  WINPR_ASSERT(context);
1329
0
  return rdp_is_active_state(context->rdp);
1330
0
}
1331
1332
BOOL freerdp_channels_from_mcs(rdpSettings* settings, const rdpContext* context)
1333
0
{
1334
0
  WINPR_ASSERT(context);
1335
0
  return rdp_channels_from_mcs(settings, context->rdp);
1336
0
}
1337
1338
HANDLE freerdp_abort_event(rdpContext* context)
1339
0
{
1340
0
  WINPR_ASSERT(context);
1341
0
  return utils_get_abort_event(context->rdp);
1342
0
}
1343
1344
static void test_mcs_free(rdpMcs* mcs)
1345
29.9k
{
1346
29.9k
  if (!mcs)
1347
0
    return;
1348
1349
29.9k
  rdpTransport* transport = mcs->transport;
1350
29.9k
  rdpContext* context = transport_get_context(transport);
1351
29.9k
  if (context)
1352
29.9k
  {
1353
29.9k
    rdpSettings* settings = context->settings;
1354
29.9k
    freerdp_settings_free(settings);
1355
29.9k
  }
1356
29.9k
  free(context);
1357
29.9k
  transport_free(transport);
1358
1359
29.9k
  mcs_free(mcs);
1360
29.9k
}
1361
1362
static rdpMcs* test_mcs_new(void)
1363
29.9k
{
1364
29.9k
  rdpTransport* transport = NULL;
1365
29.9k
  rdpSettings* settings = freerdp_settings_new(0);
1366
29.9k
  rdpContext* context = calloc(1, sizeof(rdpContext));
1367
1368
29.9k
  if (!settings)
1369
0
    goto fail;
1370
29.9k
  if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDumpReplay, TRUE))
1371
0
    goto fail;
1372
1373
29.9k
  if (!context)
1374
0
    goto fail;
1375
29.9k
  context->settings = settings;
1376
29.9k
  transport = transport_new(context);
1377
29.9k
  if (!transport)
1378
0
    goto fail;
1379
29.9k
  return mcs_new(transport);
1380
1381
0
fail:
1382
0
  transport_free(transport);
1383
0
  free(context);
1384
0
  freerdp_settings_free(settings);
1385
1386
0
  return NULL;
1387
29.9k
}
1388
1389
BOOL freerdp_is_valid_mcs_create_request(const BYTE* data, size_t size)
1390
14.9k
{
1391
1392
14.9k
  wStream sbuffer = { 0 };
1393
14.9k
  wStream* s = Stream_StaticConstInit(&sbuffer, data, size);
1394
1395
14.9k
  WINPR_ASSERT(data || (size == 0));
1396
14.9k
  WINPR_ASSERT(s);
1397
1398
14.9k
  rdpMcs* mcs = test_mcs_new();
1399
14.9k
  WINPR_ASSERT(mcs);
1400
1401
14.9k
  BOOL result = mcs_recv_connect_initial(mcs, s);
1402
14.9k
  test_mcs_free(mcs);
1403
14.9k
  return result;
1404
14.9k
}
1405
1406
BOOL freerdp_is_valid_mcs_create_response(const BYTE* data, size_t size)
1407
14.9k
{
1408
1409
14.9k
  wStream sbuffer = { 0 };
1410
14.9k
  wStream* s = Stream_StaticConstInit(&sbuffer, data, size);
1411
1412
14.9k
  WINPR_ASSERT(data || (size == 0));
1413
14.9k
  WINPR_ASSERT(s);
1414
1415
14.9k
  rdpMcs* mcs = test_mcs_new();
1416
14.9k
  WINPR_ASSERT(mcs);
1417
1418
14.9k
  BOOL result = mcs_recv_connect_response(mcs, s);
1419
14.9k
  test_mcs_free(mcs);
1420
14.9k
  return result;
1421
14.9k
}