22#include <freerdp/config.h>
27#include <winpr/winpr.h>
29#include <winpr/cast.h>
30#include <winpr/assert.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>
39#include <freerdp/streamdump.h>
40#include <freerdp/transport_io.h>
42#include <freerdp/channels/wtsvc.h>
43#include <freerdp/channels/channels.h>
44#include <freerdp/channels/drdynvc.h>
46#include <freerdp/freerdp.h>
47#include <freerdp/constants.h>
48#include <freerdp/server/rdpsnd.h>
49#include <freerdp/settings.h>
54#include "sf_encomsp.h"
58#include <freerdp/log.h>
59#define TAG SERVER_TAG("sample")
61#define SAMPLE_SERVER_USE_CLIENT_RESOLUTION 1
62#define SAMPLE_SERVER_DEFAULT_WIDTH 1024
63#define SAMPLE_SERVER_DEFAULT_HEIGHT 768
67 BOOL test_dump_rfx_realtime;
68 const char* test_pcap_file;
69 const char* replay_dump;
74static void test_peer_context_free(freerdp_peer* client, rdpContext* ctx)
76 testPeerContext* context = (testPeerContext*)ctx;
82 winpr_image_free(context->image, TRUE);
83 if (context->debug_channel_thread)
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);
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);
96 if (context->debug_channel)
97 (void)WTSVirtualChannelClose(context->debug_channel);
99 sf_peer_audin_uninit(context);
101#if defined(CHANNEL_AINPUT_SERVER)
102 sf_peer_ainput_uninit(context);
105 rdpsnd_server_context_free(context->rdpsnd);
106 encomsp_server_context_free(context->encomsp);
108 WTSCloseServer(context->vcm);
112static BOOL test_peer_context_new(freerdp_peer* client, rdpContext* ctx)
114 testPeerContext* context = (testPeerContext*)ctx;
116 WINPR_ASSERT(client);
117 WINPR_ASSERT(context);
118 WINPR_ASSERT(ctx->settings);
120 context->image = winpr_image_new();
123 if (!(context->rfx_context = rfx_context_new_ex(
127 if (!rfx_context_reset(context->rfx_context, SAMPLE_SERVER_DEFAULT_WIDTH,
128 SAMPLE_SERVER_DEFAULT_HEIGHT))
133 rfx_context_set_mode(context->rfx_context, rlgr);
136 if (!(context->nsc_context = nsc_context_new()))
139 if (!(context->s = Stream_New(NULL, 65536)))
142 context->icon_x = UINT32_MAX;
143 context->icon_y = UINT32_MAX;
144 context->vcm = WTSOpenServerA((LPSTR)client->context);
146 if (!context->vcm || context->vcm == INVALID_HANDLE_VALUE)
151 test_peer_context_free(client, ctx);
155static BOOL test_peer_init(freerdp_peer* client)
157 WINPR_ASSERT(client);
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);
165static wStream* test_peer_stream_init(testPeerContext* context)
167 WINPR_ASSERT(context);
168 WINPR_ASSERT(context->s);
170 Stream_Clear(context->s);
171 Stream_SetPosition(context->s, 0);
175static void test_peer_begin_frame(freerdp_peer* client)
177 rdpUpdate* update = NULL;
179 testPeerContext* context = NULL;
181 WINPR_ASSERT(client);
182 WINPR_ASSERT(client->context);
184 update = client->context->update;
185 WINPR_ASSERT(update);
187 context = (testPeerContext*)client->context;
188 WINPR_ASSERT(context);
190 fm.frameAction = SURFACECMD_FRAMEACTION_BEGIN;
191 fm.frameId = context->frame_id;
192 WINPR_ASSERT(update->SurfaceFrameMarker);
193 update->SurfaceFrameMarker(update->context, &fm);
196static void test_peer_end_frame(freerdp_peer* client)
198 rdpUpdate* update = NULL;
200 testPeerContext* context = NULL;
202 WINPR_ASSERT(client);
204 context = (testPeerContext*)client->context;
205 WINPR_ASSERT(context);
207 update = client->context->update;
208 WINPR_ASSERT(update);
210 fm.frameAction = SURFACECMD_FRAMEACTION_END;
211 fm.frameId = context->frame_id;
212 WINPR_ASSERT(update->SurfaceFrameMarker);
213 update->SurfaceFrameMarker(update->context, &fm);
217static BOOL stream_surface_bits_supported(
const rdpSettings* settings)
219 const UINT32 supported =
221 return ((supported & SURFCMDS_STREAM_SURFACE_BITS) != 0);
224static BOOL test_peer_draw_background(freerdp_peer* client,
const RFX_RECT* rect)
228 const UINT32 colorFormat = PIXEL_FORMAT_RGB24;
229 const size_t bpp = FreeRDPGetBytesPerPixel(colorFormat);
231 WINPR_ASSERT(client);
233 testPeerContext* context = (testPeerContext*)client->context;
234 WINPR_ASSERT(context);
236 rdpSettings* settings = client->context->settings;
237 WINPR_ASSERT(settings);
239 rdpUpdate* update = client->context->update;
240 WINPR_ASSERT(update);
249 wStream* s = test_peer_stream_init(context);
250 const size_t size = bpp * rect->width * rect->height;
254 BYTE* rgb_data = malloc(size);
257 WLog_ERR(TAG,
"Problem allocating memory");
261 memset(rgb_data, 0xA0, size);
263 if (RemoteFxCodec && stream_surface_bits_supported(settings))
265 WLog_DBG(TAG,
"Using RemoteFX codec");
266 rfx_context_set_pixel_format(context->rfx_context, colorFormat);
268 WINPR_ASSERT(bpp <= UINT16_MAX);
269 RFX_RECT rrect = { .x = 0, .y = 0, .width = rect->width, .height = rect->height };
271 if (!rfx_compose_message(context->rfx_context, s, &rrect, 1, rgb_data, rect->width,
272 rect->height, (UINT32)(bpp * rect->width)))
277 const UINT32 RemoteFxCodecId =
279 WINPR_ASSERT(RemoteFxCodecId <= UINT16_MAX);
280 cmd.bmp.codecID = (UINT16)RemoteFxCodecId;
281 cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
285 WLog_DBG(TAG,
"Using NSCodec");
286 nsc_context_set_parameters(context->nsc_context, NSC_COLOR_FORMAT, colorFormat);
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));
292 WINPR_ASSERT(NSCodecId <= UINT16_MAX);
293 cmd.bmp.codecID = (UINT16)NSCodecId;
294 cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
297 cmd.destLeft = rect->x;
298 cmd.destTop = rect->y;
299 cmd.destRight = rect->x + rect->width;
300 cmd.destBottom = rect->y + rect->height;
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);
309 update->SurfaceBits(update->context, &cmd);
316static int open_icon(
wImage* img)
318 char* paths[] = { SAMPLE_RESOURCE_ROOT,
"." };
319 const char* names[] = {
"test_icon.webp",
"test_icon.png",
"test_icon.jpg",
"test_icon.bmp" };
321 for (
size_t x = 0; x < ARRAYSIZE(paths); x++)
323 const char* path = paths[x];
324 if (!winpr_PathFileExists(path))
327 for (
size_t y = 0; y < ARRAYSIZE(names); y++)
329 const char* name = names[y];
330 char* file = GetCombinedPath(path, name);
331 int rc = winpr_image_read(img, file);
337 WLog_ERR(TAG,
"Unable to open test icon");
341static BOOL test_peer_load_icon(freerdp_peer* client)
343 testPeerContext* context = NULL;
344 rdpSettings* settings = NULL;
346 WINPR_ASSERT(client);
348 context = (testPeerContext*)client->context;
349 WINPR_ASSERT(context);
351 settings = client->context->settings;
352 WINPR_ASSERT(settings);
357 WLog_ERR(TAG,
"Client doesn't support RemoteFX or NSCodec");
361 int rc = open_icon(context->image);
366 if (!(context->bg_data = calloc(context->image->height, 3ULL * context->image->width)))
369 memset(context->bg_data, 0xA0, 3ULL * context->image->height * context->image->width);
372 context->bg_data = NULL;
376static void test_send_cursor_update(freerdp_peer* client, UINT32 x, UINT32 y)
378 WINPR_ASSERT(client);
380 testPeerContext* context = (testPeerContext*)client->context;
381 WINPR_ASSERT(context);
383 rdpSettings* settings = client->context->settings;
387 if (context->image->width < 1 || !context->activated)
392 .width = WINPR_ASSERTING_INT_CAST(UINT16, context->image->width),
393 .height = WINPR_ASSERTING_INT_CAST(UINT16, context->image->height) };
397 if (context->icon_x + context->image->width > w)
399 if (context->icon_y + context->image->height > h)
401 if (x + context->image->width > w)
403 if (y + context->image->height > h)
407 if (RemoteFxCodec && stream_surface_bits_supported(settings))
409 const UINT32 RemoteFxCodecId =
411 WINPR_ASSERT(RemoteFxCodecId <= UINT16_MAX);
412 cmd.bmp.codecID = (UINT16)RemoteFxCodecId;
413 cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
418 WINPR_ASSERT(NSCodecId <= UINT16_MAX);
419 cmd.bmp.codecID = (UINT16)NSCodecId;
420 cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
423 wStream* s = test_peer_stream_init(context);
426 const UINT32 colorFormat =
427 context->image->bitsPerPixel > 24 ? PIXEL_FORMAT_BGRA32 : PIXEL_FORMAT_BGR24;
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);
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);
445 cmd.destRight = x + rect.width;
446 cmd.destBottom = y + rect.height;
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);
453 rdpUpdate* update = client->context->update;
454 WINPR_ASSERT(update);
455 WINPR_ASSERT(update->SurfaceBits);
456 update->SurfaceBits(update->context, &cmd);
461static void test_peer_draw_icon(freerdp_peer* client, UINT32 x, UINT32 y)
463 WINPR_ASSERT(client);
465 rdpSettings* settings = client->context->settings;
466 WINPR_ASSERT(settings);
471 test_peer_begin_frame(client);
473 testPeerContext* context = (testPeerContext*)client->context;
474 if ((context->icon_x != UINT32_MAX) && (context->icon_y != UINT32_MAX))
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) };
481 test_peer_draw_background(client, &rect);
483 test_send_cursor_update(client, x, y);
484 test_peer_end_frame(client);
487static BOOL test_sleep_tsdiff(UINT32* old_sec, UINT32* old_usec, UINT32 new_sec, UINT32 new_usec)
492 WINPR_ASSERT(old_sec);
493 WINPR_ASSERT(old_usec);
495 if ((*old_sec == 0) && (*old_usec == 0))
498 *old_usec = new_usec;
502 sec = new_sec - *old_sec;
503 usec = new_usec - *old_usec;
505 if ((sec < 0) || ((sec == 0) && (usec < 0)))
507 WLog_ERR(TAG,
"Invalid time stamp detected.");
512 *old_usec = new_usec;
521 Sleep((DWORD)sec * 1000);
529static BOOL tf_peer_dump_rfx(freerdp_peer* client)
533 UINT32 prev_seconds = 0;
534 UINT32 prev_useconds = 0;
535 rdpUpdate* update = NULL;
536 rdpPcap* pcap_rfx = NULL;
537 pcap_record record = { 0 };
539 WINPR_ASSERT(client);
540 WINPR_ASSERT(client->context);
542 struct server_info* info = client->ContextExtra;
545 s = Stream_New(NULL, 512);
550 update = client->context->update;
551 WINPR_ASSERT(update);
553 pcap_rfx = pcap_open(info->test_pcap_file, FALSE);
557 prev_seconds = prev_useconds = 0;
559 while (pcap_has_next_record(pcap_rfx))
561 if (!pcap_get_next_record_header(pcap_rfx, &record))
564 if (!Stream_EnsureCapacity(s, record.length))
567 record.data = Stream_Buffer(s);
568 pcap_get_next_record_content(pcap_rfx, &record);
569 Stream_SetPosition(s, Stream_Capacity(s));
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)
576 WINPR_ASSERT(update->SurfaceCommand);
577 update->SurfaceCommand(update->context, s);
579 WINPR_ASSERT(client->CheckFileDescriptor);
580 if (client->CheckFileDescriptor(client) != TRUE)
586 Stream_Free(s, TRUE);
587 pcap_close(pcap_rfx);
591static DWORD WINAPI tf_debug_channel_thread_func(LPVOID arg)
595 DWORD BytesReturned = 0;
597 testPeerContext* context = (testPeerContext*)arg;
599 WINPR_ASSERT(context);
600 if (WTSVirtualChannelQuery(context->debug_channel, WTSVirtualFileHandle, &buffer,
601 &BytesReturned) == TRUE)
603 fd = *((
void**)buffer);
604 WTSFreeMemory(buffer);
606 if (!(context->event = CreateWaitObjectEvent(NULL, TRUE, FALSE, fd)))
610 wStream* s = Stream_New(NULL, 4096);
614 if (!WTSVirtualChannelWrite(context->debug_channel, (PCHAR)
"test1", 5, &written))
621 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
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);
635 Stream_SetPosition(s, 0);
637 if (WTSVirtualChannelRead(context->debug_channel, 0, Stream_BufferAs(s,
char),
638 (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
640 if (BytesReturned == 0)
643 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
646 if (WTSVirtualChannelRead(context->debug_channel, 0, Stream_BufferAs(s,
char),
647 (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
654 Stream_SetPosition(s, BytesReturned);
655 WLog_DBG(TAG,
"got %" PRIu32
" bytes", BytesReturned);
658 Stream_Free(s, TRUE);
662static BOOL tf_peer_post_connect(freerdp_peer* client)
664 testPeerContext* context = NULL;
665 rdpSettings* settings = NULL;
667 WINPR_ASSERT(client);
669 context = (testPeerContext*)client->context;
670 WINPR_ASSERT(context);
672 settings = client->context->settings;
673 WINPR_ASSERT(settings);
681 WLog_DBG(TAG,
"Client %s is activated (osMajorType %" PRIu32
" osMinorType %" PRIu32
")",
682 client->local ?
"(local)" : client->hostname,
690 WLog_DBG(TAG,
" and wants to login automatically as %s\\%s", Domain ? Domain :
"",
696 WLog_DBG(TAG,
"Client requested desktop: %" PRIu32
"x%" PRIu32
"x%" PRIu32
"",
700#if (SAMPLE_SERVER_USE_CLIENT_RESOLUTION == 1)
702 if (!rfx_context_reset(context->rfx_context,
707 WLog_DBG(TAG,
"Using resolution requested by client.");
709 client->freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) =
710 context->rfx_context->width;
711 client->freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) =
712 context->rfx_context->height;
713 WLog_DBG(TAG,
"Resizing client to %" PRIu32
"x%" PRIu32
"",
714 client->freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
715 client->freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
716 client->update->DesktopResize(client->update->context);
721 if (!test_peer_load_icon(client))
723 WLog_DBG(TAG,
"Unable to load icon");
727 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm,
"rdpdbg"))
729 context->debug_channel = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION,
"rdpdbg");
731 if (context->debug_channel != NULL)
733 WLog_DBG(TAG,
"Open channel rdpdbg.");
735 if (!(context->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
737 WLog_ERR(TAG,
"Failed to create stop event");
741 if (!(context->debug_channel_thread =
742 CreateThread(NULL, 0, tf_debug_channel_thread_func, (
void*)context, 0, NULL)))
744 WLog_ERR(TAG,
"Failed to create debug channel thread");
745 (void)CloseHandle(context->stopEvent);
746 context->stopEvent = NULL;
752 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, RDPSND_CHANNEL_NAME))
754 sf_peer_rdpsnd_init(context);
757 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, ENCOMSP_SVC_CHANNEL_NAME))
759 sf_peer_encomsp_init(context);
763 sf_peer_audin_init(context);
765#if defined(CHANNEL_AINPUT_SERVER)
766 sf_peer_ainput_init(context);
773static BOOL tf_peer_activate(freerdp_peer* client)
775 testPeerContext* context = NULL;
776 rdpSettings* settings = NULL;
778 WINPR_ASSERT(client);
780 context = (testPeerContext*)client->context;
781 WINPR_ASSERT(context);
783 settings = client->context->settings;
784 WINPR_ASSERT(settings);
786 struct server_info* info = client->ContextExtra;
789 context->activated = TRUE;
796 if (info->test_pcap_file != NULL)
801 if (!tf_peer_dump_rfx(client))
812 test_peer_begin_frame(client);
813 test_peer_draw_background(client, &rect);
814 test_peer_end_frame(client);
820static BOOL tf_peer_synchronize_event(rdpInput* input, UINT32 flags)
824 WLog_DBG(TAG,
"Client sent a synchronize event (flags:0x%" PRIX32
")", flags);
828static BOOL tf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
830 freerdp_peer* client = NULL;
831 rdpUpdate* update = NULL;
832 rdpContext* context = NULL;
833 testPeerContext* tcontext = NULL;
834 rdpSettings* settings = NULL;
838 context = input->context;
839 WINPR_ASSERT(context);
841 client = context->peer;
842 WINPR_ASSERT(client);
844 settings = context->settings;
845 WINPR_ASSERT(settings);
847 update = context->update;
848 WINPR_ASSERT(update);
850 tcontext = (testPeerContext*)context;
851 WINPR_ASSERT(tcontext);
853 WLog_DBG(TAG,
"Client sent a keyboard event (flags:0x%04" PRIX16
" code:0x%04" PRIX8
")", flags,
856 if (((flags & KBD_FLAGS_RELEASE) == 0) && (code == RDP_SCANCODE_KEY_G))
868 SAMPLE_SERVER_DEFAULT_WIDTH))
871 SAMPLE_SERVER_DEFAULT_HEIGHT))
875 if (!rfx_context_reset(tcontext->rfx_context,
880 WINPR_ASSERT(update->DesktopResize);
881 update->DesktopResize(update->context);
882 tcontext->activated = FALSE;
884 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_C)
886 if (tcontext->debug_channel)
889 if (!WTSVirtualChannelWrite(tcontext->debug_channel, (PCHAR)
"test2", 5, &written))
893 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_X)
895 WINPR_ASSERT(client->Close);
896 client->Close(client);
898 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_R)
900 tcontext->audin_open = !tcontext->audin_open;
902#if defined(CHANNEL_AINPUT_SERVER)
903 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_I)
905 tcontext->ainput_open = !tcontext->ainput_open;
908 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_S)
915static BOOL tf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
921 "Client sent a unicode keyboard event (flags:0x%04" PRIX16
" code:0x%04" PRIX16
")",
926static BOOL tf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
930 WINPR_ASSERT(input->context);
932 WLog_DBG(TAG,
"Client sent a mouse event (flags:0x%04" PRIX16
" pos:%" PRIu16
",%" PRIu16
")",
934 test_peer_draw_icon(input->context->peer, x + 10, y);
938static UINT32 add(UINT32 old, UINT32 max, INT16 diff)
946 return WINPR_ASSERTING_INT_CAST(uint32_t, val);
949static BOOL tf_peer_rel_mouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, INT16 yDelta)
953 WINPR_ASSERT(input->context);
958 static UINT32 xpos = 0;
959 static UINT32 ypos = 0;
961 xpos = add(xpos, w, xDelta);
962 ypos = add(ypos, h, yDelta);
965 "Client sent a relative mouse event (flags:0x%04" PRIX16
" pos:%" PRId16
",%" PRId16
967 flags, xDelta, yDelta);
968 test_peer_draw_icon(input->context->peer, xpos + 10, ypos);
972static BOOL tf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
976 WINPR_ASSERT(input->context);
979 "Client sent an extended mouse event (flags:0x%04" PRIX16
" pos:%" PRIu16
",%" PRIu16
982 test_peer_draw_icon(input->context->peer, x + 10, y);
986static BOOL tf_peer_refresh_rect(rdpContext* context, BYTE count,
const RECTANGLE_16* areas)
988 WINPR_UNUSED(context);
989 WINPR_ASSERT(context);
990 WINPR_ASSERT(areas || (count == 0));
992 WLog_DBG(TAG,
"Client requested to refresh:");
994 for (BYTE i = 0; i < count; i++)
996 WLog_DBG(TAG,
" (%" PRIu16
", %" PRIu16
") (%" PRIu16
", %" PRIu16
")", areas[i].left,
997 areas[i].top, areas[i].right, areas[i].bottom);
1003static BOOL tf_peer_suppress_output(rdpContext* context, BYTE allow,
const RECTANGLE_16* area)
1005 WINPR_UNUSED(context);
1011 "Client restore output (%" PRIu16
", %" PRIu16
") (%" PRIu16
", %" PRIu16
").",
1012 area->left, area->top, area->right, area->bottom);
1016 WLog_DBG(TAG,
"Client minimized and suppress output.");
1022static int hook_peer_write_pdu(rdpTransport* transport,
wStream* s)
1029 rdpContext* context = transport_get_context(transport);
1031 WINPR_ASSERT(context);
1034 freerdp_peer* client = context->peer;
1035 WINPR_ASSERT(client);
1037 testPeerContext* peerCtx = (testPeerContext*)client->context;
1038 WINPR_ASSERT(peerCtx);
1039 WINPR_ASSERT(peerCtx->io.WritePdu);
1048 CONNECTION_STATE state = freerdp_get_state(context);
1049 if (state < CONNECTION_STATE_NEGO)
1050 return peerCtx->io.WritePdu(transport, s);
1052 ls = Stream_New(NULL, 4096);
1056 while (stream_dump_get(context, &flags, ls, &offset, &ts) > 0)
1060 if (flags & STREAM_MSG_SRV_TX)
1062 if ((last_ts > 0) && (ts > last_ts))
1064 UINT64 diff = ts - last_ts;
1067 UINT32 d = diff > UINT32_MAX ? UINT32_MAX : (UINT32)diff;
1073 rc = peerCtx->io.WritePdu(transport, ls);
1077 Stream_SetPosition(ls, 0);
1081 Stream_Free(ls, TRUE);
1085static DWORD WINAPI test_peer_mainloop(LPVOID arg)
1088 DWORD error = CHANNEL_RC_OK;
1089 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
1092 testPeerContext* context = NULL;
1093 rdpSettings* settings = NULL;
1094 rdpInput* input = NULL;
1095 rdpUpdate* update = NULL;
1096 freerdp_peer* client = (freerdp_peer*)arg;
1098 WINPR_ASSERT(client);
1100 struct server_info* info = client->ContextExtra;
1103 if (!test_peer_init(client))
1105 freerdp_peer_free(client);
1110 WINPR_ASSERT(client->context);
1111 settings = client->context->settings;
1112 WINPR_ASSERT(settings);
1113 if (info->replay_dump)
1121 rdpPrivateKey* key = freerdp_key_new_from_file_enc(info->key, NULL);
1128 rdpCertificate* cert = freerdp_certificate_new_from_file(info->cert);
1142 ENCRYPTION_LEVEL_CLIENT_COMPATIBLE))
1160 client->PostConnect = tf_peer_post_connect;
1161 client->Activate = tf_peer_activate;
1163 WINPR_ASSERT(client->context);
1164 input = client->context->input;
1165 WINPR_ASSERT(input);
1167 input->SynchronizeEvent = tf_peer_synchronize_event;
1168 input->KeyboardEvent = tf_peer_keyboard_event;
1169 input->UnicodeKeyboardEvent = tf_peer_unicode_keyboard_event;
1170 input->MouseEvent = tf_peer_mouse_event;
1171 input->RelMouseEvent = tf_peer_rel_mouse_event;
1172 input->ExtendedMouseEvent = tf_peer_extended_mouse_event;
1174 update = client->context->update;
1175 WINPR_ASSERT(update);
1177 update->RefreshRect = tf_peer_refresh_rect;
1178 update->SuppressOutput = tf_peer_suppress_output;
1183 WINPR_ASSERT(client->Initialize);
1184 rc = client->Initialize(client);
1188 context = (testPeerContext*)client->context;
1189 WINPR_ASSERT(context);
1191 if (info->replay_dump)
1193 const rdpTransportIo* cb = freerdp_get_io_callbacks(client->context);
1194 rdpTransportIo replay;
1199 replay.WritePdu = hook_peer_write_pdu;
1200 freerdp_set_io_callbacks(client->context, &replay);
1203 WLog_INFO(TAG,
"We've got a client %s", client->local ?
"(local)" : client->hostname);
1205 while (error == CHANNEL_RC_OK)
1209 WINPR_ASSERT(client->GetEventHandles);
1210 DWORD tmp = client->GetEventHandles(client, &handles[count], 32 - count);
1214 WLog_ERR(TAG,
"Failed to get FreeRDP transport event handles");
1221 HANDLE channelHandle = WTSVirtualChannelManagerGetEventHandle(context->vcm);
1222 handles[count++] = channelHandle;
1223 status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
1225 if (status == WAIT_FAILED)
1227 WLog_ERR(TAG,
"WaitForMultipleObjects failed (errno: %d)", errno);
1231 WINPR_ASSERT(client->CheckFileDescriptor);
1232 if (client->CheckFileDescriptor(client) != TRUE)
1235 if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
1239 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, DRDYNVC_SVC_CHANNEL_NAME))
1241 switch (WTSVirtualChannelManagerGetDrdynvcState(context->vcm))
1243 case DRDYNVC_STATE_NONE:
1246 case DRDYNVC_STATE_INITIALIZED:
1249 case DRDYNVC_STATE_READY:
1252 if (sf_peer_audin_running(context) != context->audin_open)
1254 if (!sf_peer_audin_running(context))
1255 sf_peer_audin_start(context);
1257 sf_peer_audin_stop(context);
1260#if defined(CHANNEL_AINPUT_SERVER)
1261 if (sf_peer_ainput_running(context) != context->ainput_open)
1263 if (!sf_peer_ainput_running(context))
1264 sf_peer_ainput_start(context);
1266 sf_peer_ainput_stop(context);
1272 case DRDYNVC_STATE_FAILED:
1279 WLog_INFO(TAG,
"Client %s disconnected.", client->local ?
"(local)" : client->hostname);
1281 WINPR_ASSERT(client->Disconnect);
1282 client->Disconnect(client);
1284 freerdp_peer_context_free(client);
1285 freerdp_peer_free(client);
1289static BOOL test_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
1291 HANDLE hThread = NULL;
1293 WINPR_UNUSED(instance);
1295 WINPR_ASSERT(instance);
1296 WINPR_ASSERT(client);
1298 struct server_info* info = instance->info;
1299 client->ContextExtra = info;
1301 if (!(hThread = CreateThread(NULL, 0, test_peer_mainloop, (
void*)client, 0, NULL)))
1304 (void)CloseHandle(hThread);
1308static void test_server_mainloop(freerdp_listener* instance)
1310 HANDLE handles[32] = { 0 };
1314 WINPR_ASSERT(instance);
1317 WINPR_ASSERT(instance->GetEventHandles);
1318 count = instance->GetEventHandles(instance, handles, 32);
1322 WLog_ERR(TAG,
"Failed to get FreeRDP event handles");
1326 status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
1328 if (WAIT_FAILED == status)
1330 WLog_ERR(TAG,
"select failed");
1334 WINPR_ASSERT(instance->CheckFileDescriptor);
1335 if (instance->CheckFileDescriptor(instance) != TRUE)
1337 WLog_ERR(TAG,
"Failed to check FreeRDP file descriptor");
1342 WINPR_ASSERT(instance->Close);
1343 instance->Close(instance);
1348 const char spcap[7];
1349 const char sfast[7];
1350 const char sport[7];
1351 const char slocal_only[13];
1352 const char scert[7];
1354} options = { {
'-',
'-',
'p',
'c',
'a',
'p',
'=' },
1355 {
'-',
'-',
'f',
'a',
's',
't' },
1356 {
'-',
'-',
'p',
'o',
'r',
't',
'=' },
1357 {
'-',
'-',
'l',
'o',
'c',
'a',
'l',
'-',
'o',
'n',
'l',
'y' },
1358 {
'-',
'-',
'c',
'e',
'r',
't',
'=' },
1359 {
'-',
'-',
'k',
'e',
'y',
'=' } };
1361WINPR_PRAGMA_DIAG_PUSH
1362WINPR_PRAGMA_DIAG_IGNORED_FORMAT_NONLITERAL
1363WINPR_ATTR_FORMAT_ARG(2, 0)
1364static
void print_entry(FILE* fp, WINPR_FORMAT_ARG const
char* fmt, const
char* what,
size_t size)
1366 char buffer[32] = { 0 };
1367 strncpy(buffer, what, MIN(size,
sizeof(buffer) - 1));
1368 (void)fprintf(fp, fmt, buffer);
1370WINPR_PRAGMA_DIAG_POP
1372static int usage(
const char* app,
const char* invalid)
1376 (void)fprintf(fp,
"Invalid argument '%s'\n", invalid);
1377 (void)fprintf(fp,
"Usage: %s <arg>[ <arg> ...]\n", app);
1378 (void)fprintf(fp,
"Arguments:\n");
1379 print_entry(fp,
"\t%s<pcap file>\n", options.spcap,
sizeof(options.spcap));
1380 print_entry(fp,
"\t%s<cert file>\n", options.scert,
sizeof(options.scert));
1381 print_entry(fp,
"\t%s<key file>\n", options.skey,
sizeof(options.skey));
1382 print_entry(fp,
"\t%s\n", options.sfast,
sizeof(options.sfast));
1383 print_entry(fp,
"\t%s<port>\n", options.sport,
sizeof(options.sport));
1384 print_entry(fp,
"\t%s\n", options.slocal_only,
sizeof(options.slocal_only));
1388int main(
int argc,
char* argv[])
1391 BOOL started = FALSE;
1393 freerdp_listener* instance = NULL;
1395 char name[MAX_PATH] = { 0 };
1397 BOOL localOnly = FALSE;
1398 struct server_info info = { 0 };
1399 const char* app = argv[0];
1401 info.test_dump_rfx_realtime = TRUE;
1405 for (
int i = 1; i < argc; i++)
1407 char* arg = argv[i];
1409 if (strncmp(arg, options.sfast,
sizeof(options.sfast)) == 0)
1410 info.test_dump_rfx_realtime = FALSE;
1411 else if (strncmp(arg, options.sport,
sizeof(options.sport)) == 0)
1413 const char* sport = &arg[
sizeof(options.sport)];
1414 port = strtol(sport, NULL, 10);
1416 if ((port < 1) || (port > UINT16_MAX) || (errno != 0))
1417 return usage(app, arg);
1419 else if (strncmp(arg, options.slocal_only,
sizeof(options.slocal_only)) == 0)
1421 else if (strncmp(arg, options.spcap,
sizeof(options.spcap)) == 0)
1423 info.test_pcap_file = &arg[
sizeof(options.spcap)];
1424 if (!winpr_PathFileExists(info.test_pcap_file))
1425 return usage(app, arg);
1427 else if (strncmp(arg, options.scert,
sizeof(options.scert)) == 0)
1429 info.cert = &arg[
sizeof(options.scert)];
1430 if (!winpr_PathFileExists(info.cert))
1431 return usage(app, arg);
1433 else if (strncmp(arg, options.skey,
sizeof(options.skey)) == 0)
1435 info.key = &arg[
sizeof(options.skey)];
1436 if (!winpr_PathFileExists(info.key))
1437 return usage(app, arg);
1440 return usage(app, arg);
1443 WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
1444 winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
1445 instance = freerdp_listener_new();
1451 info.cert =
"server.crt";
1453 info.key =
"server.key";
1455 instance->info = (
void*)&info;
1456 instance->PeerAccepted = test_peer_accepted;
1458 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
1462 (void)sprintf_s(name,
sizeof(name),
"tfreerdp-server.%ld", port);
1463 file = GetKnownSubPath(KNOWN_PATH_TEMP, name);
1470 WINPR_ASSERT(instance->OpenLocal);
1471 started = instance->OpenLocal(instance, file);
1475 WINPR_ASSERT(instance->Open);
1476 started = instance->Open(instance, NULL, (UINT16)port);
1483 test_server_mainloop(instance);
1489 freerdp_listener_free(instance);
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.