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