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