FreeRDP
Loading...
Searching...
No Matches
sfreerdp.c
1
22#include <freerdp/config.h>
23
24#include <errno.h>
25#include <signal.h>
26
27#include <winpr/winpr.h>
28#include <winpr/crt.h>
29#include <winpr/cast.h>
30#include <winpr/assert.h>
31#include <winpr/ssl.h>
32#include <winpr/synch.h>
33#include <winpr/file.h>
34#include <winpr/string.h>
35#include <winpr/path.h>
36#include <winpr/image.h>
37#include <winpr/winsock.h>
38
39#include <freerdp/streamdump.h>
40#include <freerdp/transport_io.h>
41
42#include <freerdp/channels/wtsvc.h>
43#include <freerdp/channels/channels.h>
44#include <freerdp/channels/drdynvc.h>
45
46#include <freerdp/freerdp.h>
47#include <freerdp/constants.h>
48#include <freerdp/server/rdpsnd.h>
49#include <freerdp/settings.h>
50#include <freerdp/build-config.h>
51#include <freerdp/version.h>
52#include <freerdp/utils/helpers.h>
53
54#include "sf_ainput.h"
55#include "sf_audin.h"
56#include "sf_rdpsnd.h"
57#include "sf_encomsp.h"
58
59#include "sfreerdp.h"
60
61#include <freerdp/log.h>
62#define TAG SERVER_TAG("sample")
63
64#define SAMPLE_SERVER_USE_CLIENT_RESOLUTION 1
65#define SAMPLE_SERVER_DEFAULT_WIDTH 1024
66#define SAMPLE_SERVER_DEFAULT_HEIGHT 768
67
68struct server_info
69{
70 BOOL test_dump_rfx_realtime;
71 const char* test_pcap_file;
72 const char* replay_dump;
73 const char* cert;
74 const char* key;
75};
76
77static void test_peer_context_free(freerdp_peer* client, rdpContext* ctx)
78{
79 testPeerContext* context = (testPeerContext*)ctx;
80
81 WINPR_UNUSED(client);
82
83 if (context)
84 {
85 winpr_image_free(context->image, TRUE);
86 if (context->debug_channel_thread)
87 {
88 WINPR_ASSERT(context->stopEvent);
89 (void)SetEvent(context->stopEvent);
90 (void)WaitForSingleObject(context->debug_channel_thread, INFINITE);
91 (void)CloseHandle(context->debug_channel_thread);
92 }
93
94 Stream_Free(context->s, TRUE);
95 free(context->bg_data);
96 rfx_context_free(context->rfx_context);
97 nsc_context_free(context->nsc_context);
98
99 if (context->debug_channel)
100 (void)WTSVirtualChannelClose(context->debug_channel);
101
102 sf_peer_audin_uninit(context);
103
104#if defined(CHANNEL_AINPUT_SERVER)
105 sf_peer_ainput_uninit(context);
106#endif
107
108 rdpsnd_server_context_free(context->rdpsnd);
109 encomsp_server_context_free(context->encomsp);
110
111 WTSCloseServer(context->vcm);
112 }
113}
114
115WINPR_ATTR_NODISCARD
116static BOOL test_peer_context_new(freerdp_peer* client, rdpContext* ctx)
117{
118 testPeerContext* context = (testPeerContext*)ctx;
119
120 WINPR_ASSERT(client);
121 WINPR_ASSERT(context);
122 WINPR_ASSERT(ctx->settings);
123
124 context->image = winpr_image_new();
125 if (!context->image)
126 goto fail;
127 if (!(context->rfx_context = rfx_context_new_ex(
128 TRUE, freerdp_settings_get_uint32(ctx->settings, FreeRDP_ThreadingFlags))))
129 goto fail;
130
131 if (!rfx_context_reset(context->rfx_context, SAMPLE_SERVER_DEFAULT_WIDTH,
132 SAMPLE_SERVER_DEFAULT_HEIGHT))
133 goto fail;
134
135 {
136 const UINT32 rlgr = freerdp_settings_get_uint32(ctx->settings, FreeRDP_RemoteFxRlgrMode);
137 if (!rfx_context_set_mode(context->rfx_context, WINPR_ASSERTING_INT_CAST(RLGR_MODE, rlgr)))
138 goto fail;
139 }
140
141 if (!(context->nsc_context = nsc_context_new()))
142 goto fail;
143
144 if (!(context->s = Stream_New(nullptr, 65536)))
145 goto fail;
146
147 context->icon_x = UINT32_MAX;
148 context->icon_y = UINT32_MAX;
149 context->vcm = WTSOpenServerA((LPSTR)client->context);
150
151 if (!context->vcm || context->vcm == INVALID_HANDLE_VALUE)
152 goto fail;
153
154 return TRUE;
155fail:
156 test_peer_context_free(client, ctx);
157 return FALSE;
158}
159
160WINPR_ATTR_NODISCARD
161static BOOL test_peer_init(freerdp_peer* client)
162{
163 WINPR_ASSERT(client);
164
165 client->ContextSize = sizeof(testPeerContext);
166 client->ContextNew = test_peer_context_new;
167 client->ContextFree = test_peer_context_free;
168 return freerdp_peer_context_new(client);
169}
170
171WINPR_ATTR_NODISCARD
172static wStream* test_peer_stream_init(testPeerContext* context)
173{
174 WINPR_ASSERT(context);
175 WINPR_ASSERT(context->s);
176
177 Stream_Clear(context->s);
178 Stream_ResetPosition(context->s);
179 return context->s;
180}
181
182static void test_peer_begin_frame(freerdp_peer* client)
183{
184 rdpUpdate* update = nullptr;
185 SURFACE_FRAME_MARKER fm = WINPR_C_ARRAY_INIT;
186 testPeerContext* context = nullptr;
187
188 WINPR_ASSERT(client);
189 WINPR_ASSERT(client->context);
190
191 update = client->context->update;
192 WINPR_ASSERT(update);
193
194 context = (testPeerContext*)client->context;
195 WINPR_ASSERT(context);
196
197 fm.frameAction = SURFACECMD_FRAMEACTION_BEGIN;
198 fm.frameId = context->frame_id;
199 WINPR_ASSERT(update->SurfaceFrameMarker);
200 if (!update->SurfaceFrameMarker(update->context, &fm))
201 WLog_WARN(TAG, "SurfaceFrameMarker failed");
202}
203
204static void test_peer_end_frame(freerdp_peer* client)
205{
206 rdpUpdate* update = nullptr;
207 SURFACE_FRAME_MARKER fm = WINPR_C_ARRAY_INIT;
208 testPeerContext* context = nullptr;
209
210 WINPR_ASSERT(client);
211
212 context = (testPeerContext*)client->context;
213 WINPR_ASSERT(context);
214
215 update = client->context->update;
216 WINPR_ASSERT(update);
217
218 fm.frameAction = SURFACECMD_FRAMEACTION_END;
219 fm.frameId = context->frame_id;
220 WINPR_ASSERT(update->SurfaceFrameMarker);
221 if (!update->SurfaceFrameMarker(update->context, &fm))
222 WLog_WARN(TAG, "SurfaceFrameMarker failed");
223 context->frame_id++;
224}
225
226WINPR_ATTR_NODISCARD
227static BOOL stream_surface_bits_supported(const rdpSettings* settings)
228{
229 const UINT32 supported =
230 freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
231 return ((supported & SURFCMDS_STREAM_SURFACE_BITS) != 0);
232}
233
234static BOOL test_peer_draw_background(freerdp_peer* client, const RFX_RECT* rect)
235{
236 SURFACE_BITS_COMMAND cmd = WINPR_C_ARRAY_INIT;
237 BOOL ret = FALSE;
238 const UINT32 colorFormat = PIXEL_FORMAT_RGB24;
239 const size_t bpp = FreeRDPGetBytesPerPixel(colorFormat);
240
241 WINPR_ASSERT(client);
242
243 testPeerContext* context = (testPeerContext*)client->context;
244 WINPR_ASSERT(context);
245
246 rdpSettings* settings = client->context->settings;
247 WINPR_ASSERT(settings);
248
249 rdpUpdate* update = client->context->update;
250 WINPR_ASSERT(update);
251
252 const BOOL RemoteFxCodec = freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec);
253 if (!RemoteFxCodec && !freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
254 return FALSE;
255
256 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) <= UINT16_MAX);
257 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) <= UINT16_MAX);
258
259 wStream* s = test_peer_stream_init(context);
260 const size_t size = bpp * rect->width * rect->height;
261 if (size == 0)
262 return FALSE;
263
264 BYTE* rgb_data = malloc(size);
265 if (!rgb_data)
266 {
267 WLog_ERR(TAG, "Problem allocating memory");
268 return FALSE;
269 }
270
271 memset(rgb_data, 0xA0, size);
272
273 if (RemoteFxCodec && stream_surface_bits_supported(settings))
274 {
275 WLog_DBG(TAG, "Using RemoteFX codec");
276 rfx_context_set_pixel_format(context->rfx_context, colorFormat);
277
278 WINPR_ASSERT(bpp <= UINT16_MAX);
279 RFX_RECT rrect = { .x = 0, .y = 0, .width = rect->width, .height = rect->height };
280
281 if (!rfx_compose_message(context->rfx_context, s, &rrect, 1, rgb_data, rect->width,
282 rect->height, (UINT32)(bpp * rect->width)))
283 {
284 goto out;
285 }
286
287 const UINT32 RemoteFxCodecId =
288 freerdp_settings_get_uint32(settings, FreeRDP_RemoteFxCodecId);
289 WINPR_ASSERT(RemoteFxCodecId <= UINT16_MAX);
290 cmd.bmp.codecID = (UINT16)RemoteFxCodecId;
291 cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
292 }
293 else
294 {
295 WLog_DBG(TAG, "Using NSCodec");
296 if (!nsc_context_set_parameters(context->nsc_context, NSC_COLOR_FORMAT, colorFormat))
297 goto out;
298
299 WINPR_ASSERT(bpp <= UINT16_MAX);
300 if (!nsc_compose_message(context->nsc_context, s, rgb_data, rect->width, rect->height,
301 (UINT32)(bpp * rect->width)))
302 goto out;
303 const UINT32 NSCodecId = freerdp_settings_get_uint32(settings, FreeRDP_NSCodecId);
304 WINPR_ASSERT(NSCodecId <= UINT16_MAX);
305 cmd.bmp.codecID = (UINT16)NSCodecId;
306 cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
307 }
308
309 cmd.destLeft = rect->x;
310 cmd.destTop = rect->y;
311 cmd.destRight = rect->x + rect->width;
312 cmd.destBottom = rect->y + rect->height;
313 cmd.bmp.bpp = 32;
314 cmd.bmp.flags = 0;
315 cmd.bmp.width = rect->width;
316 cmd.bmp.height = rect->height;
317
318 cmd.bmp.bitmapDataLength = WINPR_ASSERTING_INT_CAST(UINT32, Stream_GetPosition(s));
319 cmd.bmp.bitmapData = Stream_Buffer(s);
320
321 ret = update->SurfaceBits(update->context, &cmd);
322out:
323 free(rgb_data);
324 return ret;
325}
326
327WINPR_ATTR_NODISCARD
328static int open_icon(wImage* img)
329{
330 char* paths[] = { SAMPLE_RESOURCE_ROOT, "." };
331 const char* names[] = { "test_icon.webp", "test_icon.png", "test_icon.jpg", "test_icon.bmp" };
332
333 for (size_t x = 0; x < ARRAYSIZE(paths); x++)
334 {
335 const char* path = paths[x];
336 if (!winpr_PathFileExists(path))
337 continue;
338
339 for (size_t y = 0; y < ARRAYSIZE(names); y++)
340 {
341 const char* name = names[y];
342 char* file = GetCombinedPath(path, name);
343 int rc = winpr_image_read(img, file);
344 free(file);
345 if (rc > 0)
346 return rc;
347 }
348 }
349 WLog_ERR(TAG, "Unable to open test icon");
350 return -1;
351}
352
353WINPR_ATTR_NODISCARD
354static BOOL test_peer_load_icon(freerdp_peer* client)
355{
356 testPeerContext* context = nullptr;
357 rdpSettings* settings = nullptr;
358
359 WINPR_ASSERT(client);
360
361 context = (testPeerContext*)client->context;
362 WINPR_ASSERT(context);
363
364 settings = client->context->settings;
365 WINPR_ASSERT(settings);
366
367 if (!freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec) &&
368 !freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
369 {
370 WLog_ERR(TAG, "Client doesn't support RemoteFX or NSCodec");
371 return FALSE;
372 }
373
374 int rc = open_icon(context->image);
375 if (rc <= 0)
376 goto out_fail;
377
378 /* background with same size, which will be used to erase the icon from old position */
379 if (!(context->bg_data = calloc(context->image->height, 3ULL * context->image->width)))
380 goto out_fail;
381
382 memset(context->bg_data, 0xA0, 3ULL * context->image->height * context->image->width);
383 return TRUE;
384out_fail:
385 context->bg_data = nullptr;
386 return FALSE;
387}
388
389static void test_send_cursor_update(freerdp_peer* client, UINT32 x, UINT32 y)
390{
391 WINPR_ASSERT(client);
392
393 testPeerContext* context = (testPeerContext*)client->context;
394 WINPR_ASSERT(context);
395
396 rdpSettings* settings = client->context->settings;
397
398 const BOOL RemoteFxCodec = freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec);
399
400 if (context->image->width < 1 || !context->activated)
401 return;
402
403 RFX_RECT rect = { .x = 0,
404 .y = 0,
405 .width = WINPR_ASSERTING_INT_CAST(UINT16, context->image->width),
406 .height = WINPR_ASSERTING_INT_CAST(UINT16, context->image->height) };
407
408 const UINT32 w = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
409 const UINT32 h = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
410 if (context->icon_x + context->image->width > w)
411 return;
412 if (context->icon_y + context->image->height > h)
413 return;
414 if (x + context->image->width > w)
415 return;
416 if (y + context->image->height > h)
417 return;
418
419 SURFACE_BITS_COMMAND cmd = WINPR_C_ARRAY_INIT;
420 if (RemoteFxCodec && stream_surface_bits_supported(settings))
421 {
422 const UINT32 RemoteFxCodecId =
423 freerdp_settings_get_uint32(settings, FreeRDP_RemoteFxCodecId);
424 WINPR_ASSERT(RemoteFxCodecId <= UINT16_MAX);
425 cmd.bmp.codecID = (UINT16)RemoteFxCodecId;
426 cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
427 }
428 else
429 {
430 const UINT32 NSCodecId = freerdp_settings_get_uint32(settings, FreeRDP_NSCodecId);
431 WINPR_ASSERT(NSCodecId <= UINT16_MAX);
432 cmd.bmp.codecID = (UINT16)NSCodecId;
433 cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
434 }
435
436 wStream* s = test_peer_stream_init(context);
437
438 {
439 const UINT32 colorFormat =
440 context->image->bitsPerPixel > 24 ? PIXEL_FORMAT_BGRA32 : PIXEL_FORMAT_BGR24;
441
442 if (RemoteFxCodec)
443 {
444 rfx_context_set_pixel_format(context->rfx_context, colorFormat);
445 if (!rfx_compose_message(context->rfx_context, s, &rect, 1, context->image->data,
446 rect.width, rect.height, context->image->scanline))
447 WLog_WARN(TAG, "rfx_compose_message failed");
448 }
449 else
450 {
451 if (!nsc_context_set_parameters(context->nsc_context, NSC_COLOR_FORMAT, colorFormat))
452 WLog_WARN(TAG, "nsc_context_set_parameters failed");
453 else if (!nsc_compose_message(context->nsc_context, s, context->image->data, rect.width,
454 rect.height, context->image->scanline))
455 WLog_WARN(TAG, "rfx_compose_message failed");
456 }
457 }
458
459 cmd.destLeft = x;
460 cmd.destTop = y;
461 cmd.destRight = x + rect.width;
462 cmd.destBottom = y + rect.height;
463 cmd.bmp.bpp = 32;
464 cmd.bmp.width = rect.width;
465 cmd.bmp.height = rect.height;
466 cmd.bmp.bitmapDataLength = (UINT32)Stream_GetPosition(s);
467 cmd.bmp.bitmapData = Stream_Buffer(s);
468
469 rdpUpdate* update = client->context->update;
470 WINPR_ASSERT(update);
471 WINPR_ASSERT(update->SurfaceBits);
472 if (!update->SurfaceBits(update->context, &cmd))
473 {
474 WLog_WARN(TAG, "update->SurfaceBits failed");
475 }
476 context->icon_x = x;
477 context->icon_y = y;
478}
479
480static void test_peer_draw_icon(freerdp_peer* client, UINT32 x, UINT32 y)
481{
482 WINPR_ASSERT(client);
483
484 rdpSettings* settings = client->context->settings;
485 WINPR_ASSERT(settings);
486
487 if (freerdp_settings_get_bool(settings, FreeRDP_DumpRemoteFx))
488 return;
489
490 test_peer_begin_frame(client);
491
492 testPeerContext* context = (testPeerContext*)client->context;
493 if ((context->icon_x != UINT32_MAX) && (context->icon_y != UINT32_MAX))
494 {
495 RFX_RECT rect = { .x = WINPR_ASSERTING_INT_CAST(uint16_t, context->icon_x),
496 .y = WINPR_ASSERTING_INT_CAST(uint16_t, context->icon_y),
497 .width = WINPR_ASSERTING_INT_CAST(uint16_t, context->image->width),
498 .height = WINPR_ASSERTING_INT_CAST(uint16_t, context->image->height) };
499
500 test_peer_draw_background(client, &rect);
501 }
502 test_send_cursor_update(client, x, y);
503 test_peer_end_frame(client);
504}
505
506WINPR_ATTR_NODISCARD
507static BOOL test_sleep_tsdiff(UINT32* old_sec, UINT32* old_usec, UINT32 new_sec, UINT32 new_usec)
508{
509 INT64 sec = 0;
510 INT64 usec = 0;
511
512 WINPR_ASSERT(old_sec);
513 WINPR_ASSERT(old_usec);
514
515 if ((*old_sec == 0) && (*old_usec == 0))
516 {
517 *old_sec = new_sec;
518 *old_usec = new_usec;
519 return TRUE;
520 }
521
522 sec = new_sec - *old_sec;
523 usec = new_usec - *old_usec;
524
525 if ((sec < 0) || ((sec == 0) && (usec < 0)))
526 {
527 WLog_ERR(TAG, "Invalid time stamp detected.");
528 return FALSE;
529 }
530
531 *old_sec = new_sec;
532 *old_usec = new_usec;
533
534 while (usec < 0)
535 {
536 usec += 1000000;
537 sec--;
538 }
539
540 if (sec > 0)
541 Sleep((DWORD)sec * 1000);
542
543 if (usec > 0)
544 USleep((DWORD)usec);
545
546 return TRUE;
547}
548
549static BOOL tf_peer_dump_rfx(freerdp_peer* client)
550{
551 BOOL rc = FALSE;
552 wStream* s = nullptr;
553 UINT32 prev_seconds = 0;
554 UINT32 prev_useconds = 0;
555 rdpUpdate* update = nullptr;
556 rdpPcap* pcap_rfx = nullptr;
557 pcap_record record = WINPR_C_ARRAY_INIT;
558
559 WINPR_ASSERT(client);
560 WINPR_ASSERT(client->context);
561
562 struct server_info* info = client->ContextExtra;
563 WINPR_ASSERT(info);
564
565 s = Stream_New(nullptr, 512);
566
567 if (!s)
568 return FALSE;
569
570 update = client->context->update;
571 WINPR_ASSERT(update);
572
573 pcap_rfx = pcap_open(info->test_pcap_file, FALSE);
574 if (!pcap_rfx)
575 goto fail;
576
577 prev_seconds = prev_useconds = 0;
578
579 while (pcap_has_next_record(pcap_rfx))
580 {
581 if (!pcap_get_next_record_header(pcap_rfx, &record))
582 break;
583
584 if (!Stream_EnsureCapacity(s, record.length))
585 break;
586
587 record.data = Stream_Buffer(s);
588 if (!pcap_get_next_record_content(pcap_rfx, &record))
589 break;
590 if (!Stream_SetPosition(s, Stream_Capacity(s)))
591 goto fail;
592
593 if (info->test_dump_rfx_realtime &&
594 test_sleep_tsdiff(&prev_seconds, &prev_useconds, record.header.ts_sec,
595 record.header.ts_usec) == FALSE)
596 break;
597
598 WINPR_ASSERT(update->SurfaceCommand);
599 if (!update->SurfaceCommand(update->context, s))
600 break;
601
602 WINPR_ASSERT(client->CheckFileDescriptor);
603 if (client->CheckFileDescriptor(client) != TRUE)
604 break;
605 }
606
607 rc = TRUE;
608fail:
609 Stream_Free(s, TRUE);
610 pcap_close(pcap_rfx);
611 return rc;
612}
613
614WINPR_ATTR_NODISCARD
615static DWORD WINAPI tf_debug_channel_thread_func(LPVOID arg)
616{
617 void* fd = nullptr;
618 void* buffer = nullptr;
619 DWORD BytesReturned = 0;
620 ULONG written = 0;
621 testPeerContext* context = (testPeerContext*)arg;
622
623 WINPR_ASSERT(context);
624 if (WTSVirtualChannelQuery(context->debug_channel, WTSVirtualFileHandle, &buffer,
625 &BytesReturned) == TRUE)
626 {
627 fd = *((void**)buffer);
628 WTSFreeMemory(buffer);
629
630 if (!(context->event = CreateWaitObjectEvent(nullptr, TRUE, FALSE, fd)))
631 return 0;
632 }
633
634 wStream* s = Stream_New(nullptr, 4096);
635 if (!s)
636 goto fail;
637
638 if (!WTSVirtualChannelWrite(context->debug_channel, (PCHAR) "test1", 5, &written))
639 goto fail;
640
641 while (1)
642 {
643 DWORD status = 0;
644 DWORD nCount = 0;
645 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
646
647 handles[nCount++] = context->event;
648 handles[nCount++] = freerdp_abort_event(&context->_p);
649 handles[nCount++] = context->stopEvent;
650 status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
651 switch (status)
652 {
653 case WAIT_OBJECT_0:
654 break;
655 default:
656 goto fail;
657 }
658
659 Stream_ResetPosition(s);
660
661 if (WTSVirtualChannelRead(context->debug_channel, 0, Stream_BufferAs(s, char),
662 (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
663 {
664 if (BytesReturned == 0)
665 break;
666
667 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
668 break;
669
670 if (WTSVirtualChannelRead(context->debug_channel, 0, Stream_BufferAs(s, char),
671 (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
672 {
673 /* should not happen */
674 break;
675 }
676 }
677
678 if (!Stream_SetPosition(s, BytesReturned))
679 goto fail;
680 WLog_DBG(TAG, "got %" PRIu32 " bytes", BytesReturned);
681 }
682fail:
683 Stream_Free(s, TRUE);
684 return 0;
685}
686
687WINPR_ATTR_NODISCARD
688static BOOL tf_peer_post_connect(freerdp_peer* client)
689{
690 testPeerContext* context = nullptr;
691 rdpSettings* settings = nullptr;
692
693 WINPR_ASSERT(client);
694
695 context = (testPeerContext*)client->context;
696 WINPR_ASSERT(context);
697
698 settings = client->context->settings;
699 WINPR_ASSERT(settings);
700
707 WLog_DBG(TAG, "Client %s is activated (osMajorType %" PRIu32 " osMinorType %" PRIu32 ")",
708 client->local ? "(local)" : client->hostname,
709 freerdp_settings_get_uint32(settings, FreeRDP_OsMajorType),
710 freerdp_settings_get_uint32(settings, FreeRDP_OsMinorType));
711
712 if (freerdp_settings_get_bool(settings, FreeRDP_AutoLogonEnabled))
713 {
714 const char* Username = freerdp_settings_get_string(settings, FreeRDP_Username);
715 const char* Domain = freerdp_settings_get_string(settings, FreeRDP_Domain);
716 WLog_DBG(TAG, " and wants to login automatically as %s\\%s", Domain ? Domain : "",
717 Username);
718 /* A real server may perform OS login here if NLA is not executed previously. */
719 }
720
721 WLog_DBG(TAG, "Client requested desktop: %" PRIu32 "x%" PRIu32 "x%" PRIu32 "",
722 freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
723 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight),
724 freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth));
725#if (SAMPLE_SERVER_USE_CLIENT_RESOLUTION == 1)
726
727 if (!rfx_context_reset(context->rfx_context,
728 freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
729 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)))
730 return FALSE;
731
732 WLog_DBG(TAG, "Using resolution requested by client.");
733#else
734 client->freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) =
735 context->rfx_context->width;
736 client->freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) =
737 context->rfx_context->height;
738 WLog_DBG(TAG, "Resizing client to %" PRIu32 "x%" PRIu32 "",
739 client->freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
740 client->freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
741 client->update->DesktopResize(client->update->context);
742#endif
743
744 /* A real server should tag the peer as activated here and start sending updates in main loop.
745 */
746 if (!test_peer_load_icon(client))
747 {
748 WLog_DBG(TAG, "Unable to load icon");
749 return FALSE;
750 }
751
752 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "rdpdbg"))
753 {
754 context->debug_channel = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpdbg");
755
756 if (context->debug_channel != nullptr)
757 {
758 WLog_DBG(TAG, "Open channel rdpdbg.");
759
760 if (!(context->stopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
761 {
762 WLog_ERR(TAG, "Failed to create stop event");
763 return FALSE;
764 }
765
766 if (!(context->debug_channel_thread = CreateThread(
767 nullptr, 0, tf_debug_channel_thread_func, (void*)context, 0, nullptr)))
768 {
769 WLog_ERR(TAG, "Failed to create debug channel thread");
770 (void)CloseHandle(context->stopEvent);
771 context->stopEvent = nullptr;
772 return FALSE;
773 }
774 }
775 }
776
777 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, RDPSND_CHANNEL_NAME))
778 {
779 if (!sf_peer_rdpsnd_init(context)) /* Audio Output */
780 return FALSE;
781 }
782
783 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, ENCOMSP_SVC_CHANNEL_NAME))
784 {
785 if (!sf_peer_encomsp_init(context)) /* Lync Multiparty */
786 return FALSE;
787 }
788
789 /* Dynamic Virtual Channels */
790 if (!sf_peer_audin_init(context)) /* Audio Input */
791 return FALSE;
792
793#if defined(CHANNEL_AINPUT_SERVER)
794 sf_peer_ainput_init(context);
795#endif
796
797 /* Return FALSE here would stop the execution of the peer main loop. */
798 return TRUE;
799}
800
801WINPR_ATTR_NODISCARD
802static BOOL tf_peer_activate(freerdp_peer* client)
803{
804 BOOL rc = TRUE;
805 WINPR_ASSERT(client);
806
807 testPeerContext* context = (testPeerContext*)client->context;
808 WINPR_ASSERT(context);
809
810 rdpSettings* settings = client->context->settings;
811 WINPR_ASSERT(settings);
812
813 struct server_info* info = client->ContextExtra;
814 WINPR_ASSERT(info);
815
816 context->activated = TRUE;
817 // PACKET_COMPR_TYPE_8K;
818 // PACKET_COMPR_TYPE_64K;
819 // PACKET_COMPR_TYPE_RDP6;
820 if (!freerdp_settings_set_uint32(settings, FreeRDP_CompressionLevel, PACKET_COMPR_TYPE_RDP8))
821 return FALSE;
822
823 if (info->test_pcap_file != nullptr)
824 {
825 if (!freerdp_settings_set_bool(settings, FreeRDP_DumpRemoteFx, TRUE))
826 return FALSE;
827
828 if (!tf_peer_dump_rfx(client))
829 return FALSE;
830 }
831 else
832 {
833 const RFX_RECT rect = {
834 .x = 0,
835 .y = 0,
836 .width = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
837 .height = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)
838 };
839 test_peer_begin_frame(client);
840 rc = test_peer_draw_background(client, &rect);
841 test_peer_end_frame(client);
842 }
843
844 return rc;
845}
846
847WINPR_ATTR_NODISCARD
848static BOOL tf_peer_synchronize_event(rdpInput* input, UINT32 flags)
849{
850 WINPR_UNUSED(input);
851 WINPR_ASSERT(input);
852 WLog_DBG(TAG, "Client sent a synchronize event (flags:0x%" PRIX32 ")", flags);
853 return TRUE;
854}
855
856WINPR_ATTR_NODISCARD
857static BOOL tf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
858{
859 freerdp_peer* client = nullptr;
860 rdpUpdate* update = nullptr;
861 rdpContext* context = nullptr;
862 testPeerContext* tcontext = nullptr;
863 rdpSettings* settings = nullptr;
864
865 WINPR_ASSERT(input);
866
867 context = input->context;
868 WINPR_ASSERT(context);
869
870 client = context->peer;
871 WINPR_ASSERT(client);
872
873 settings = context->settings;
874 WINPR_ASSERT(settings);
875
876 update = context->update;
877 WINPR_ASSERT(update);
878
879 tcontext = (testPeerContext*)context;
880 WINPR_ASSERT(tcontext);
881
882 WLog_DBG(TAG, "Client sent a keyboard event (flags:0x%04" PRIX16 " code:0x%04" PRIX8 ")", flags,
883 code);
884
885 if (((flags & KBD_FLAGS_RELEASE) == 0) && (code == RDP_SCANCODE_KEY_G)) /* 'g' key */
886 {
887 if (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) != 800)
888 {
889 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, 800))
890 return FALSE;
891 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, 600))
892 return FALSE;
893 }
894 else
895 {
896 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth,
897 SAMPLE_SERVER_DEFAULT_WIDTH))
898 return FALSE;
899 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight,
900 SAMPLE_SERVER_DEFAULT_HEIGHT))
901 return FALSE;
902 }
903
904 if (!rfx_context_reset(tcontext->rfx_context,
905 freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
906 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)))
907 return FALSE;
908
909 WINPR_ASSERT(update->DesktopResize);
910 if (!update->DesktopResize(update->context))
911 return FALSE;
912 tcontext->activated = FALSE;
913 }
914 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_C) /* 'c' key */
915 {
916 if (tcontext->debug_channel)
917 {
918 ULONG written = 0;
919 if (!WTSVirtualChannelWrite(tcontext->debug_channel, (PCHAR) "test2", 5, &written))
920 return FALSE;
921 }
922 }
923 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_X) /* 'x' key */
924 {
925 WINPR_ASSERT(client->Close);
926 if (!client->Close(client))
927 return FALSE;
928 }
929 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_R) /* 'r' key */
930 {
931 tcontext->audin_open = !tcontext->audin_open;
932 }
933#if defined(CHANNEL_AINPUT_SERVER)
934 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_I) /* 'i' key */
935 {
936 tcontext->ainput_open = !tcontext->ainput_open;
937 }
938#endif
939 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_S) /* 's' key */
940 {
941 }
942
943 return TRUE;
944}
945
946WINPR_ATTR_NODISCARD
947static BOOL tf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
948{
949 WINPR_UNUSED(input);
950 WINPR_ASSERT(input);
951
952 WLog_DBG(TAG,
953 "Client sent a unicode keyboard event (flags:0x%04" PRIX16 " code:0x%04" PRIX16 ")",
954 flags, code);
955 return TRUE;
956}
957
958WINPR_ATTR_NODISCARD
959static BOOL tf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
960{
961 WINPR_UNUSED(flags);
962 WINPR_ASSERT(input);
963 WINPR_ASSERT(input->context);
964
965 WLog_DBG(TAG, "Client sent a mouse event (flags:0x%04" PRIX16 " pos:%" PRIu16 ",%" PRIu16 ")",
966 flags, x, y);
967 test_peer_draw_icon(input->context->peer, x + 10, y);
968 return TRUE;
969}
970
971WINPR_ATTR_NODISCARD
972static UINT32 add(UINT32 old, UINT32 max, INT16 diff)
973{
974 INT64 val = old;
975 val += diff;
976 if (val > max)
977 val = val % max;
978 else if (val < 0)
979 val = max - val;
980 return WINPR_ASSERTING_INT_CAST(uint32_t, val);
981}
982
983WINPR_ATTR_NODISCARD
984static BOOL tf_peer_rel_mouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, INT16 yDelta)
985{
986 WINPR_UNUSED(flags);
987 WINPR_ASSERT(input);
988 WINPR_ASSERT(input->context);
989
990 const UINT32 w = freerdp_settings_get_uint32(input->context->settings, FreeRDP_DesktopWidth);
991 const UINT32 h = freerdp_settings_get_uint32(input->context->settings, FreeRDP_DesktopHeight);
992
993 static UINT32 xpos = 0;
994 static UINT32 ypos = 0;
995
996 xpos = add(xpos, w, xDelta);
997 ypos = add(ypos, h, yDelta);
998
999 WLog_DBG(TAG,
1000 "Client sent a relative mouse event (flags:0x%04" PRIX16 " pos:%" PRId16 ",%" PRId16
1001 ")",
1002 flags, xDelta, yDelta);
1003 test_peer_draw_icon(input->context->peer, xpos + 10, ypos);
1004 return TRUE;
1005}
1006
1007WINPR_ATTR_NODISCARD
1008static BOOL tf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
1009{
1010 WINPR_UNUSED(flags);
1011 WINPR_ASSERT(input);
1012 WINPR_ASSERT(input->context);
1013
1014 WLog_DBG(TAG,
1015 "Client sent an extended mouse event (flags:0x%04" PRIX16 " pos:%" PRIu16 ",%" PRIu16
1016 ")",
1017 flags, x, y);
1018 test_peer_draw_icon(input->context->peer, x + 10, y);
1019 return TRUE;
1020}
1021
1022WINPR_ATTR_NODISCARD
1023static BOOL tf_peer_refresh_rect(rdpContext* context, BYTE count, const RECTANGLE_16* areas)
1024{
1025 WINPR_UNUSED(context);
1026 WINPR_ASSERT(context);
1027 WINPR_ASSERT(areas || (count == 0));
1028
1029 WLog_DBG(TAG, "Client requested to refresh:");
1030
1031 for (BYTE i = 0; i < count; i++)
1032 {
1033 WLog_DBG(TAG, " (%" PRIu16 ", %" PRIu16 ") (%" PRIu16 ", %" PRIu16 ")", areas[i].left,
1034 areas[i].top, areas[i].right, areas[i].bottom);
1035 }
1036
1037 return TRUE;
1038}
1039
1040WINPR_ATTR_NODISCARD
1041static BOOL tf_peer_suppress_output(rdpContext* context, BYTE allow, const RECTANGLE_16* area)
1042{
1043 WINPR_UNUSED(context);
1044
1045 if (allow > 0)
1046 {
1047 WINPR_ASSERT(area);
1048 WLog_DBG(TAG,
1049 "Client restore output (%" PRIu16 ", %" PRIu16 ") (%" PRIu16 ", %" PRIu16 ").",
1050 area->left, area->top, area->right, area->bottom);
1051 }
1052 else
1053 {
1054 WLog_DBG(TAG, "Client minimized and suppress output.");
1055 }
1056
1057 return TRUE;
1058}
1059
1060WINPR_ATTR_NODISCARD
1061static int hook_peer_write_pdu(rdpTransport* transport, wStream* s)
1062{
1063 UINT64 ts = 0;
1064 wStream* ls = nullptr;
1065 UINT64 last_ts = 0;
1066 size_t offset = 0;
1067 UINT32 flags = 0;
1068 rdpContext* context = transport_get_context(transport);
1069
1070 WINPR_ASSERT(context);
1071 WINPR_ASSERT(s);
1072
1073 freerdp_peer* client = context->peer;
1074 WINPR_ASSERT(client);
1075
1076 testPeerContext* peerCtx = (testPeerContext*)client->context;
1077 WINPR_ASSERT(peerCtx);
1078 WINPR_ASSERT(peerCtx->io.WritePdu);
1079
1080 /* Let the client authenticate.
1081 * After that is done, we stop the normal operation and send
1082 * a previously recorded session PDU by PDU to the client.
1083 *
1084 * This is fragile and the connecting client needs to use the same
1085 * configuration as the one that recorded the session!
1086 */
1087 CONNECTION_STATE state = freerdp_get_state(context);
1088 if (state < CONNECTION_STATE_NEGO)
1089 return peerCtx->io.WritePdu(transport, s);
1090
1091 ls = Stream_New(nullptr, 4096);
1092 if (!ls)
1093 goto fail;
1094
1095 while (stream_dump_get(context, &flags, ls, &offset, &ts) > 0)
1096 {
1097 int rc = 0;
1098 /* Skip messages from client. */
1099 if (flags & STREAM_MSG_SRV_TX)
1100 {
1101 if ((last_ts > 0) && (ts > last_ts))
1102 {
1103 UINT64 diff = ts - last_ts;
1104 while (diff > 0)
1105 {
1106 UINT32 d = diff > UINT32_MAX ? UINT32_MAX : (UINT32)diff;
1107 diff -= d;
1108 Sleep(d);
1109 }
1110 }
1111 last_ts = ts;
1112 rc = peerCtx->io.WritePdu(transport, ls);
1113 if (rc < 0)
1114 goto fail;
1115 }
1116 Stream_ResetPosition(ls);
1117 }
1118
1119fail:
1120 Stream_Free(ls, TRUE);
1121 return -1;
1122}
1123
1124WINPR_ATTR_NODISCARD
1125static DWORD WINAPI test_peer_mainloop(LPVOID arg)
1126{
1127 BOOL rc = 0;
1128 DWORD error = CHANNEL_RC_OK;
1129 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
1130 DWORD count = 0;
1131 DWORD status = 0;
1132 testPeerContext* context = nullptr;
1133 rdpSettings* settings = nullptr;
1134 rdpInput* input = nullptr;
1135 rdpUpdate* update = nullptr;
1136 freerdp_peer* client = (freerdp_peer*)arg;
1137
1138 WINPR_ASSERT(client);
1139
1140 struct server_info* info = client->ContextExtra;
1141 WINPR_ASSERT(info);
1142
1143 if (!test_peer_init(client))
1144 {
1145 freerdp_peer_free(client);
1146 return 0;
1147 }
1148
1149 /* Initialize the real server settings here */
1150 WINPR_ASSERT(client->context);
1151 settings = client->context->settings;
1152 WINPR_ASSERT(settings);
1153 if (info->replay_dump)
1154 {
1155 if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDumpReplay, TRUE) ||
1156 !freerdp_settings_set_string(settings, FreeRDP_TransportDumpFile, info->replay_dump))
1157 goto fail;
1158 }
1159
1160 {
1161 rdpPrivateKey* key = freerdp_key_new_from_file_enc(info->key, nullptr);
1162 if (!key)
1163 goto fail;
1164 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))
1165 goto fail;
1166 }
1167 {
1168 rdpCertificate* cert = freerdp_certificate_new_from_file(info->cert);
1169 if (!cert)
1170 goto fail;
1171 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerCertificate, cert, 1))
1172 goto fail;
1173 }
1174
1175 if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, TRUE))
1176 goto fail;
1177 if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE))
1178 goto fail;
1179 if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
1180 goto fail;
1181 if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, FALSE))
1182 goto fail;
1183 if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1184 ENCRYPTION_LEVEL_CLIENT_COMPATIBLE))
1185 goto fail;
1186 /* ENCRYPTION_LEVEL_HIGH; */
1187 /* ENCRYPTION_LEVEL_LOW; */
1188 /* ENCRYPTION_LEVEL_FIPS; */
1189 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE))
1190 goto fail;
1191 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, TRUE) ||
1192 !freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32))
1193 goto fail;
1194
1195 if (!freerdp_settings_set_bool(settings, FreeRDP_SuppressOutput, TRUE))
1196 goto fail;
1197 if (!freerdp_settings_set_bool(settings, FreeRDP_RefreshRect, TRUE))
1198 goto fail;
1199 if (!freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent, TRUE))
1200 goto fail;
1201
1202 client->PostConnect = tf_peer_post_connect;
1203 client->Activate = tf_peer_activate;
1204
1205 WINPR_ASSERT(client->context);
1206 input = client->context->input;
1207 WINPR_ASSERT(input);
1208
1209 input->SynchronizeEvent = tf_peer_synchronize_event;
1210 input->KeyboardEvent = tf_peer_keyboard_event;
1211 input->UnicodeKeyboardEvent = tf_peer_unicode_keyboard_event;
1212 input->MouseEvent = tf_peer_mouse_event;
1213 input->RelMouseEvent = tf_peer_rel_mouse_event;
1214 input->ExtendedMouseEvent = tf_peer_extended_mouse_event;
1215
1216 update = client->context->update;
1217 WINPR_ASSERT(update);
1218
1219 update->RefreshRect = tf_peer_refresh_rect;
1220 update->SuppressOutput = tf_peer_suppress_output;
1221 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
1222 0xFFFFFF /* FIXME */))
1223 goto fail;
1224
1225 WINPR_ASSERT(client->Initialize);
1226 rc = client->Initialize(client);
1227 if (!rc)
1228 goto fail;
1229
1230 context = (testPeerContext*)client->context;
1231 WINPR_ASSERT(context);
1232
1233 if (info->replay_dump)
1234 {
1235 const rdpTransportIo* cb = freerdp_get_io_callbacks(client->context);
1236 rdpTransportIo replay;
1237
1238 WINPR_ASSERT(cb);
1239 replay = *cb;
1240 context->io = *cb;
1241 replay.WritePdu = hook_peer_write_pdu;
1242 if (!freerdp_set_io_callbacks(client->context, &replay))
1243 goto fail;
1244 }
1245
1246 WLog_INFO(TAG, "We've got a client %s", client->local ? "(local)" : client->hostname);
1247
1248 while (error == CHANNEL_RC_OK)
1249 {
1250 count = 0;
1251 {
1252 WINPR_ASSERT(client->GetEventHandles);
1253 DWORD tmp = client->GetEventHandles(client, &handles[count], 32 - count);
1254
1255 if (tmp == 0)
1256 {
1257 WLog_ERR(TAG, "Failed to get FreeRDP transport event handles");
1258 break;
1259 }
1260
1261 count += tmp;
1262 }
1263
1264 HANDLE channelHandle = WTSVirtualChannelManagerGetEventHandle(context->vcm);
1265 handles[count++] = channelHandle;
1266 status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
1267
1268 if (status == WAIT_FAILED)
1269 {
1270 WLog_ERR(TAG, "WaitForMultipleObjects failed (errno: %d)", errno);
1271 break;
1272 }
1273
1274 WINPR_ASSERT(client->CheckFileDescriptor);
1275 if (client->CheckFileDescriptor(client) != TRUE)
1276 break;
1277
1278 if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
1279 break;
1280
1281 /* Handle dynamic virtual channel initializations */
1282 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, DRDYNVC_SVC_CHANNEL_NAME))
1283 {
1284 switch (WTSVirtualChannelManagerGetDrdynvcState(context->vcm))
1285 {
1286 case DRDYNVC_STATE_NONE:
1287 break;
1288
1289 case DRDYNVC_STATE_INITIALIZED:
1290 break;
1291
1292 case DRDYNVC_STATE_READY:
1293
1294 /* Here is the correct state to start dynamic virtual channels */
1295 if (sf_peer_audin_running(context) != context->audin_open)
1296 {
1297 if (!sf_peer_audin_running(context))
1298 sf_peer_audin_start(context);
1299 else
1300 sf_peer_audin_stop(context);
1301 }
1302
1303#if defined(CHANNEL_AINPUT_SERVER)
1304 if (sf_peer_ainput_running(context) != context->ainput_open)
1305 {
1306 if (!sf_peer_ainput_running(context))
1307 sf_peer_ainput_start(context);
1308 else
1309 sf_peer_ainput_stop(context);
1310 }
1311#endif
1312
1313 break;
1314
1315 case DRDYNVC_STATE_FAILED:
1316 default:
1317 break;
1318 }
1319 }
1320 }
1321
1322 WLog_INFO(TAG, "Client %s disconnected.", client->local ? "(local)" : client->hostname);
1323
1324 WINPR_ASSERT(client->Disconnect);
1325 client->Disconnect(client);
1326fail:
1327 freerdp_peer_context_free(client);
1328 freerdp_peer_free(client);
1329 return error;
1330}
1331
1332WINPR_ATTR_NODISCARD
1333static BOOL test_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
1334{
1335 HANDLE hThread = nullptr;
1336
1337 WINPR_UNUSED(instance);
1338
1339 WINPR_ASSERT(instance);
1340 WINPR_ASSERT(client);
1341
1342 struct server_info* info = instance->info;
1343 client->ContextExtra = info;
1344
1345 if (!(hThread = CreateThread(nullptr, 0, test_peer_mainloop, (void*)client, 0, nullptr)))
1346 return FALSE;
1347
1348 (void)CloseHandle(hThread);
1349 return TRUE;
1350}
1351
1352static void test_server_mainloop(freerdp_listener* instance)
1353{
1354 HANDLE handles[32] = WINPR_C_ARRAY_INIT;
1355 DWORD count = 0;
1356 DWORD status = 0;
1357
1358 WINPR_ASSERT(instance);
1359 while (1)
1360 {
1361 WINPR_ASSERT(instance->GetEventHandles);
1362 count = instance->GetEventHandles(instance, handles, 32);
1363
1364 if (0 == count)
1365 {
1366 WLog_ERR(TAG, "Failed to get FreeRDP event handles");
1367 break;
1368 }
1369
1370 status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
1371
1372 if (WAIT_FAILED == status)
1373 {
1374 WLog_ERR(TAG, "select failed");
1375 break;
1376 }
1377
1378 WINPR_ASSERT(instance->CheckFileDescriptor);
1379 if (instance->CheckFileDescriptor(instance) != TRUE)
1380 {
1381 WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
1382 break;
1383 }
1384 }
1385
1386 WINPR_ASSERT(instance->Close);
1387 instance->Close(instance);
1388}
1389
1390static const struct
1391{
1392 const char spcap[7];
1393 const char sfast[7];
1394 const char sport[7];
1395 const char slocal_only[13];
1396 const char scert[7];
1397 const char skey[6];
1398} options = { { '-', '-', 'p', 'c', 'a', 'p', '=' },
1399 { '-', '-', 'f', 'a', 's', 't' },
1400 { '-', '-', 'p', 'o', 'r', 't', '=' },
1401 { '-', '-', 'l', 'o', 'c', 'a', 'l', '-', 'o', 'n', 'l', 'y' },
1402 { '-', '-', 'c', 'e', 'r', 't', '=' },
1403 { '-', '-', 'k', 'e', 'y', '=' } };
1404
1405WINPR_PRAGMA_DIAG_PUSH
1406WINPR_PRAGMA_DIAG_IGNORED_FORMAT_NONLITERAL
1407WINPR_ATTR_FORMAT_ARG(2, 0)
1408static void print_entry(FILE* fp, WINPR_FORMAT_ARG const char* fmt, const char* what, size_t size)
1409{
1410 char buffer[32] = WINPR_C_ARRAY_INIT;
1411 strncpy(buffer, what, MIN(size, sizeof(buffer) - 1));
1412 (void)fprintf(fp, fmt, buffer);
1413}
1414WINPR_PRAGMA_DIAG_POP
1415
1416WINPR_ATTR_NODISCARD
1417static int usage(const char* app, const char* invalid)
1418{
1419 FILE* fp = stdout;
1420
1421 (void)fprintf(fp, "Invalid argument '%s'\n", invalid);
1422 (void)fprintf(fp, "Usage: %s <arg>[ <arg> ...]\n", app);
1423 (void)fprintf(fp, "Arguments:\n");
1424 print_entry(fp, "\t%s<pcap file>\n", options.spcap, sizeof(options.spcap));
1425 print_entry(fp, "\t%s<cert file>\n", options.scert, sizeof(options.scert));
1426 print_entry(fp, "\t%s<key file>\n", options.skey, sizeof(options.skey));
1427 print_entry(fp, "\t%s\n", options.sfast, sizeof(options.sfast));
1428 print_entry(fp, "\t%s<port>\n", options.sport, sizeof(options.sport));
1429 print_entry(fp, "\t%s\n", options.slocal_only, sizeof(options.slocal_only));
1430 return -1;
1431}
1432
1433int main(int argc, char* argv[])
1434{
1435 int rc = -1;
1436 BOOL started = FALSE;
1437 WSADATA wsaData = WINPR_C_ARRAY_INIT;
1438 freerdp_listener* instance = nullptr;
1439 char* file = nullptr;
1440 char name[MAX_PATH] = WINPR_C_ARRAY_INIT;
1441 long port = 3389;
1442 BOOL localOnly = FALSE;
1443 struct server_info info = WINPR_C_ARRAY_INIT;
1444 const char* app = argv[0];
1445
1446 info.test_dump_rfx_realtime = TRUE;
1447
1448 /*
1449 * Set custom application details at first thing in main.
1450 * This will initialize a new namespace within FreeRDP and WinPR.
1451 * As a result all configuration files will be searched in different locations.
1452 *
1453 * The location is <prefix>/<vendor>/<product> or <prefix>/<vendor>/<product><version> for
1454 * config file search directories. An example for a system wide configuration file would be
1455 * /etc/FreeRDP/TFreeRDP3/ or ~/.config//FreeRDP/TFreeRDP3/ for user config files.
1456 *
1457 * Consult \ref GetKnownPath for <prefix> locations on different operating systems
1458 */
1459 if (!freerdp_setApplicationDetails(FREERDP_VENDOR_STRING, "TFreeRDP", FREERDP_VERSION_MAJOR))
1460 return -1;
1461
1462 errno = 0;
1463
1464 for (int i = 1; i < argc; i++)
1465 {
1466 char* arg = argv[i];
1467
1468 if (strncmp(arg, options.sfast, sizeof(options.sfast)) == 0)
1469 info.test_dump_rfx_realtime = FALSE;
1470 else if (strncmp(arg, options.sport, sizeof(options.sport)) == 0)
1471 {
1472 const char* sport = &arg[sizeof(options.sport)];
1473 port = strtol(sport, nullptr, 10);
1474
1475 if ((port < 1) || (port > UINT16_MAX) || (errno != 0))
1476 return usage(app, arg);
1477 }
1478 else if (strncmp(arg, options.slocal_only, sizeof(options.slocal_only)) == 0)
1479 localOnly = TRUE;
1480 else if (strncmp(arg, options.spcap, sizeof(options.spcap)) == 0)
1481 {
1482 info.test_pcap_file = &arg[sizeof(options.spcap)];
1483 if (!winpr_PathFileExists(info.test_pcap_file))
1484 return usage(app, arg);
1485 }
1486 else if (strncmp(arg, options.scert, sizeof(options.scert)) == 0)
1487 {
1488 info.cert = &arg[sizeof(options.scert)];
1489 if (!winpr_PathFileExists(info.cert))
1490 return usage(app, arg);
1491 }
1492 else if (strncmp(arg, options.skey, sizeof(options.skey)) == 0)
1493 {
1494 info.key = &arg[sizeof(options.skey)];
1495 if (!winpr_PathFileExists(info.key))
1496 return usage(app, arg);
1497 }
1498 else
1499 return usage(app, arg);
1500 }
1501
1502 if (!WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi()))
1503 return -1;
1504
1505 if (!winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT))
1506 return -1;
1507
1508 instance = freerdp_listener_new();
1509
1510 if (!instance)
1511 return -1;
1512
1513 if (!info.cert)
1514 info.cert = "server.crt";
1515 if (!info.key)
1516 info.key = "server.key";
1517
1518 instance->info = (void*)&info;
1519 instance->PeerAccepted = test_peer_accepted;
1520
1521 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
1522 goto fail;
1523
1524 /* Open the server socket and start listening. */
1525 (void)sprintf_s(name, sizeof(name), "tfreerdp-server.%ld", port);
1526 file = GetKnownSubPath(KNOWN_PATH_TEMP, name);
1527
1528 if (!file)
1529 goto fail;
1530
1531 if (localOnly)
1532 {
1533 WINPR_ASSERT(instance->OpenLocal);
1534 started = instance->OpenLocal(instance, file);
1535 }
1536 else
1537 {
1538 WINPR_ASSERT(instance->Open);
1539 started = instance->Open(instance, nullptr, (UINT16)port);
1540 }
1541
1542 if (started)
1543 {
1544 /* Entering the server main loop. In a real server the listener can be run in its own
1545 * thread. */
1546 test_server_mainloop(instance);
1547 }
1548
1549 rc = 0;
1550fail:
1551 free(file);
1552 freerdp_listener_free(instance);
1553 WSACleanup();
1554 return rc;
1555}
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
Definition rfx.h:44