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