22 #include <freerdp/config.h>
27 #include <winpr/winpr.h>
28 #include <winpr/crt.h>
29 #include <winpr/assert.h>
30 #include <winpr/ssl.h>
31 #include <winpr/synch.h>
32 #include <winpr/file.h>
33 #include <winpr/string.h>
34 #include <winpr/path.h>
35 #include <winpr/image.h>
36 #include <winpr/winsock.h>
38 #include <freerdp/streamdump.h>
39 #include <freerdp/transport_io.h>
41 #include <freerdp/channels/wtsvc.h>
42 #include <freerdp/channels/channels.h>
43 #include <freerdp/channels/drdynvc.h>
45 #include <freerdp/freerdp.h>
46 #include <freerdp/constants.h>
47 #include <freerdp/server/rdpsnd.h>
48 #include <freerdp/settings.h>
50 #include "sf_ainput.h"
52 #include "sf_rdpsnd.h"
53 #include "sf_encomsp.h"
57 #include <freerdp/log.h>
58 #define TAG SERVER_TAG("sample")
60 #define SAMPLE_SERVER_USE_CLIENT_RESOLUTION 1
61 #define SAMPLE_SERVER_DEFAULT_WIDTH 1024
62 #define SAMPLE_SERVER_DEFAULT_HEIGHT 768
66 BOOL test_dump_rfx_realtime;
67 const char* test_pcap_file;
68 const char* replay_dump;
73 static void test_peer_context_free(freerdp_peer* client, rdpContext* ctx)
75 testPeerContext* context = (testPeerContext*)ctx;
81 winpr_image_free(context->image, TRUE);
82 if (context->debug_channel_thread)
84 WINPR_ASSERT(context->stopEvent);
85 (void)SetEvent(context->stopEvent);
86 (void)WaitForSingleObject(context->debug_channel_thread, INFINITE);
87 (void)CloseHandle(context->debug_channel_thread);
90 Stream_Free(context->s, TRUE);
91 free(context->bg_data);
92 rfx_context_free(context->rfx_context);
93 nsc_context_free(context->nsc_context);
95 if (context->debug_channel)
96 (void)WTSVirtualChannelClose(context->debug_channel);
98 sf_peer_audin_uninit(context);
100 #if defined(CHANNEL_AINPUT_SERVER)
101 sf_peer_ainput_uninit(context);
104 rdpsnd_server_context_free(context->rdpsnd);
105 encomsp_server_context_free(context->encomsp);
107 WTSCloseServer(context->vcm);
111 static BOOL test_peer_context_new(freerdp_peer* client, rdpContext* ctx)
113 testPeerContext* context = (testPeerContext*)ctx;
115 WINPR_ASSERT(client);
116 WINPR_ASSERT(context);
117 WINPR_ASSERT(ctx->settings);
119 context->image = winpr_image_new();
122 if (!(context->rfx_context = rfx_context_new_ex(
126 if (!rfx_context_reset(context->rfx_context, SAMPLE_SERVER_DEFAULT_WIDTH,
127 SAMPLE_SERVER_DEFAULT_HEIGHT))
131 rfx_context_set_mode(context->rfx_context, rlgr);
133 if (!(context->nsc_context = nsc_context_new()))
136 if (!(context->s = Stream_New(NULL, 65536)))
139 context->icon_x = UINT32_MAX;
140 context->icon_y = UINT32_MAX;
141 context->vcm = WTSOpenServerA((LPSTR)client->context);
143 if (!context->vcm || context->vcm == INVALID_HANDLE_VALUE)
148 test_peer_context_free(client, ctx);
152 static BOOL test_peer_init(freerdp_peer* client)
154 WINPR_ASSERT(client);
156 client->ContextSize =
sizeof(testPeerContext);
157 client->ContextNew = test_peer_context_new;
158 client->ContextFree = test_peer_context_free;
159 return freerdp_peer_context_new(client);
162 static wStream* test_peer_stream_init(testPeerContext* context)
164 WINPR_ASSERT(context);
165 WINPR_ASSERT(context->s);
167 Stream_Clear(context->s);
168 Stream_SetPosition(context->s, 0);
172 static void test_peer_begin_frame(freerdp_peer* client)
174 rdpUpdate* update = NULL;
176 testPeerContext* context = NULL;
178 WINPR_ASSERT(client);
179 WINPR_ASSERT(client->context);
181 update = client->context->update;
182 WINPR_ASSERT(update);
184 context = (testPeerContext*)client->context;
185 WINPR_ASSERT(context);
187 fm.frameAction = SURFACECMD_FRAMEACTION_BEGIN;
188 fm.frameId = context->frame_id;
189 WINPR_ASSERT(update->SurfaceFrameMarker);
190 update->SurfaceFrameMarker(update->context, &fm);
193 static void test_peer_end_frame(freerdp_peer* client)
195 rdpUpdate* update = NULL;
197 testPeerContext* context = NULL;
199 WINPR_ASSERT(client);
201 context = (testPeerContext*)client->context;
202 WINPR_ASSERT(context);
204 update = client->context->update;
205 WINPR_ASSERT(update);
207 fm.frameAction = SURFACECMD_FRAMEACTION_END;
208 fm.frameId = context->frame_id;
209 WINPR_ASSERT(update->SurfaceFrameMarker);
210 update->SurfaceFrameMarker(update->context, &fm);
214 static BOOL stream_surface_bits_supported(
const rdpSettings* settings)
216 const UINT32 supported =
218 return ((supported & SURFCMDS_STREAM_SURFACE_BITS) != 0);
221 static BOOL test_peer_draw_background(freerdp_peer* client)
226 BYTE* rgb_data = NULL;
227 const rdpSettings* settings = NULL;
228 rdpUpdate* update = NULL;
230 testPeerContext* context = NULL;
232 const UINT32 colorFormat = PIXEL_FORMAT_RGB24;
233 const size_t bpp = FreeRDPGetBytesPerPixel(colorFormat);
235 WINPR_ASSERT(client);
236 context = (testPeerContext*)client->context;
237 WINPR_ASSERT(context);
239 settings = client->context->settings;
240 WINPR_ASSERT(settings);
242 update = client->context->update;
243 WINPR_ASSERT(update);
252 s = test_peer_stream_init(context);
257 size = bpp * rect.width * rect.height;
259 if (!(rgb_data = malloc(size)))
261 WLog_ERR(TAG,
"Problem allocating memory");
265 memset(rgb_data, 0xA0, size);
267 if (RemoteFxCodec && stream_surface_bits_supported(settings))
269 WLog_DBG(TAG,
"Using RemoteFX codec");
270 rfx_context_set_pixel_format(context->rfx_context, colorFormat);
272 WINPR_ASSERT(bpp <= UINT16_MAX);
273 if (!rfx_compose_message(context->rfx_context, s, &rect, 1, rgb_data, rect.width,
274 rect.height, (UINT32)(bpp * rect.width)))
279 const UINT32 RemoteFxCodecId =
281 WINPR_ASSERT(RemoteFxCodecId <= UINT16_MAX);
282 cmd.bmp.codecID = (UINT16)RemoteFxCodecId;
283 cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
287 WLog_DBG(TAG,
"Using NSCodec");
288 nsc_context_set_parameters(context->nsc_context, NSC_COLOR_FORMAT, colorFormat);
290 WINPR_ASSERT(bpp <= UINT16_MAX);
291 nsc_compose_message(context->nsc_context, s, rgb_data, rect.width, rect.height,
292 (UINT32)(bpp * rect.width));
294 WINPR_ASSERT(NSCodecId <= UINT16_MAX);
295 cmd.bmp.codecID = (UINT16)NSCodecId;
296 cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
301 cmd.destRight = rect.width;
302 cmd.destBottom = rect.height;
305 cmd.bmp.width = rect.width;
306 cmd.bmp.height = rect.height;
307 WINPR_ASSERT(Stream_GetPosition(s) <= UINT32_MAX);
308 cmd.bmp.bitmapDataLength = (UINT32)Stream_GetPosition(s);
309 cmd.bmp.bitmapData = Stream_Buffer(s);
310 test_peer_begin_frame(client);
311 update->SurfaceBits(update->context, &cmd);
312 test_peer_end_frame(client);
319 static int open_icon(
wImage* img)
321 char* paths[] = { SAMPLE_RESOURCE_ROOT,
"." };
322 const char* names[] = {
"test_icon.webp",
"test_icon.png",
"test_icon.jpg",
"test_icon.bmp" };
324 for (
size_t x = 0; x < ARRAYSIZE(paths); x++)
326 const char* path = paths[x];
327 if (!winpr_PathFileExists(path))
330 for (
size_t y = 0; y < ARRAYSIZE(names); y++)
332 const char* name = names[y];
333 char* file = GetCombinedPath(path, name);
334 int rc = winpr_image_read(img, file);
340 WLog_ERR(TAG,
"Unable to open test icon");
344 static BOOL test_peer_load_icon(freerdp_peer* client)
346 testPeerContext* context = NULL;
347 rdpSettings* settings = NULL;
349 WINPR_ASSERT(client);
351 context = (testPeerContext*)client->context;
352 WINPR_ASSERT(context);
354 settings = client->context->settings;
355 WINPR_ASSERT(settings);
360 WLog_ERR(TAG,
"Client doesn't support RemoteFX or NSCodec");
364 int rc = open_icon(context->image);
369 if (!(context->bg_data = calloc(context->image->height, 3ULL * context->image->width)))
372 memset(context->bg_data, 0xA0, 3ULL * context->image->height * context->image->width);
375 context->bg_data = NULL;
379 static void test_peer_draw_icon(freerdp_peer* client, UINT32 x, UINT32 y)
383 rdpUpdate* update = NULL;
384 rdpSettings* settings = NULL;
386 testPeerContext* context = NULL;
388 WINPR_ASSERT(client);
390 context = (testPeerContext*)client->context;
391 WINPR_ASSERT(context);
393 update = client->context->update;
394 WINPR_ASSERT(update);
396 settings = client->context->settings;
397 WINPR_ASSERT(settings);
402 if (context->image->width < 1 || !context->activated)
407 rect.width = context->image->width;
408 rect.height = context->image->height;
412 if (context->icon_x + context->image->width > w)
414 if (context->icon_y + context->image->height > h)
416 if (x + context->image->width > w)
418 if (y + context->image->height > h)
421 test_peer_begin_frame(client);
424 if (RemoteFxCodec && stream_surface_bits_supported(settings))
426 const UINT32 RemoteFxCodecId =
428 WINPR_ASSERT(RemoteFxCodecId <= UINT16_MAX);
429 cmd.bmp.codecID = (UINT16)RemoteFxCodecId;
430 cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
435 WINPR_ASSERT(NSCodecId <= UINT16_MAX);
436 cmd.bmp.codecID = (UINT16)NSCodecId;
437 cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
440 if (context->icon_x != UINT32_MAX)
442 const UINT32 colorFormat = PIXEL_FORMAT_RGB24;
443 const UINT32 bpp = FreeRDPGetBytesPerPixel(colorFormat);
444 s = test_peer_stream_init(context);
448 rfx_context_set_pixel_format(context->rfx_context, colorFormat);
449 rfx_compose_message(context->rfx_context, s, &rect, 1, context->bg_data, rect.width,
450 rect.height, rect.width * bpp);
454 nsc_context_set_parameters(context->nsc_context, NSC_COLOR_FORMAT, colorFormat);
455 nsc_compose_message(context->nsc_context, s, context->bg_data, rect.width, rect.height,
459 cmd.destLeft = context->icon_x;
460 cmd.destTop = context->icon_y;
461 cmd.destRight = context->icon_x + rect.width;
462 cmd.destBottom = context->icon_y + rect.height;
465 cmd.bmp.width = rect.width;
466 cmd.bmp.height = rect.height;
467 cmd.bmp.bitmapDataLength = (UINT32)Stream_GetPosition(s);
468 cmd.bmp.bitmapData = Stream_Buffer(s);
469 WINPR_ASSERT(update->SurfaceBits);
470 update->SurfaceBits(update->context, &cmd);
473 s = test_peer_stream_init(context);
476 const UINT32 colorFormat =
477 context->image->bitsPerPixel > 24 ? PIXEL_FORMAT_BGRA32 : PIXEL_FORMAT_BGR24;
481 rfx_context_set_pixel_format(context->rfx_context, colorFormat);
482 rfx_compose_message(context->rfx_context, s, &rect, 1, context->image->data, rect.width,
483 rect.height, context->image->scanline);
487 nsc_context_set_parameters(context->nsc_context, NSC_COLOR_FORMAT, colorFormat);
488 nsc_compose_message(context->nsc_context, s, context->image->data, rect.width,
489 rect.height, context->image->scanline);
495 cmd.destRight = x + rect.width;
496 cmd.destBottom = y + rect.height;
498 cmd.bmp.width = rect.width;
499 cmd.bmp.height = rect.height;
500 cmd.bmp.bitmapDataLength = (UINT32)Stream_GetPosition(s);
501 cmd.bmp.bitmapData = Stream_Buffer(s);
502 WINPR_ASSERT(update->SurfaceBits);
503 update->SurfaceBits(update->context, &cmd);
506 test_peer_end_frame(client);
509 static BOOL test_sleep_tsdiff(UINT32* old_sec, UINT32* old_usec, UINT32 new_sec, UINT32 new_usec)
514 WINPR_ASSERT(old_sec);
515 WINPR_ASSERT(old_usec);
517 if ((*old_sec == 0) && (*old_usec == 0))
520 *old_usec = new_usec;
524 sec = new_sec - *old_sec;
525 usec = new_usec - *old_usec;
527 if ((sec < 0) || ((sec == 0) && (usec < 0)))
529 WLog_ERR(TAG,
"Invalid time stamp detected.");
534 *old_usec = new_usec;
543 Sleep((DWORD)sec * 1000);
551 static BOOL tf_peer_dump_rfx(freerdp_peer* client)
555 UINT32 prev_seconds = 0;
556 UINT32 prev_useconds = 0;
557 rdpUpdate* update = NULL;
558 rdpPcap* pcap_rfx = NULL;
559 pcap_record record = { 0 };
560 struct server_info* info = NULL;
562 WINPR_ASSERT(client);
563 WINPR_ASSERT(client->context);
565 info = client->ContextExtra;
568 s = Stream_New(NULL, 512);
573 update = client->context->update;
574 WINPR_ASSERT(update);
576 pcap_rfx = pcap_open(info->test_pcap_file, FALSE);
580 prev_seconds = prev_useconds = 0;
582 while (pcap_has_next_record(pcap_rfx))
584 if (!pcap_get_next_record_header(pcap_rfx, &record))
587 if (!Stream_EnsureCapacity(s, record.length))
590 record.data = Stream_Buffer(s);
591 pcap_get_next_record_content(pcap_rfx, &record);
592 Stream_SetPosition(s, Stream_Capacity(s));
594 if (info->test_dump_rfx_realtime &&
595 test_sleep_tsdiff(&prev_seconds, &prev_useconds, record.header.ts_sec,
596 record.header.ts_usec) == FALSE)
599 WINPR_ASSERT(update->SurfaceCommand);
600 update->SurfaceCommand(update->context, s);
602 WINPR_ASSERT(client->CheckFileDescriptor);
603 if (client->CheckFileDescriptor(client) != TRUE)
609 Stream_Free(s, TRUE);
610 pcap_close(pcap_rfx);
614 static DWORD WINAPI tf_debug_channel_thread_func(LPVOID arg)
618 DWORD BytesReturned = 0;
620 testPeerContext* context = (testPeerContext*)arg;
622 WINPR_ASSERT(context);
623 if (WTSVirtualChannelQuery(context->debug_channel, WTSVirtualFileHandle, &buffer,
624 &BytesReturned) == TRUE)
626 fd = *((
void**)buffer);
627 WTSFreeMemory(buffer);
629 if (!(context->event = CreateWaitObjectEvent(NULL, TRUE, FALSE, fd)))
633 wStream* s = Stream_New(NULL, 4096);
637 if (!WTSVirtualChannelWrite(context->debug_channel, (PCHAR)
"test1", 5, &written))
644 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
646 handles[nCount++] = context->event;
647 handles[nCount++] = freerdp_abort_event(&context->_p);
648 handles[nCount++] = context->stopEvent;
649 status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
658 Stream_SetPosition(s, 0);
660 if (WTSVirtualChannelRead(context->debug_channel, 0, Stream_BufferAs(s,
char),
661 (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
663 if (BytesReturned == 0)
666 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
669 if (WTSVirtualChannelRead(context->debug_channel, 0, Stream_BufferAs(s,
char),
670 (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
677 Stream_SetPosition(s, BytesReturned);
678 WLog_DBG(TAG,
"got %" PRIu32
" bytes", BytesReturned);
681 Stream_Free(s, TRUE);
685 static BOOL tf_peer_post_connect(freerdp_peer* client)
687 testPeerContext* context = NULL;
688 rdpSettings* settings = NULL;
690 WINPR_ASSERT(client);
692 context = (testPeerContext*)client->context;
693 WINPR_ASSERT(context);
695 settings = client->context->settings;
696 WINPR_ASSERT(settings);
704 WLog_DBG(TAG,
"Client %s is activated (osMajorType %" PRIu32
" osMinorType %" PRIu32
")",
705 client->local ?
"(local)" : client->hostname,
713 WLog_DBG(TAG,
" and wants to login automatically as %s\\%s", Domain ? Domain :
"",
719 WLog_DBG(TAG,
"Client requested desktop: %" PRIu32
"x%" PRIu32
"x%" PRIu32
"",
723 #if (SAMPLE_SERVER_USE_CLIENT_RESOLUTION == 1)
725 if (!rfx_context_reset(context->rfx_context,
730 WLog_DBG(TAG,
"Using resolution requested by client.");
732 client->freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) =
733 context->rfx_context->width;
734 client->freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) =
735 context->rfx_context->height;
736 WLog_DBG(TAG,
"Resizing client to %" PRIu32
"x%" PRIu32
"",
737 client->freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
738 client->freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
739 client->update->DesktopResize(client->update->context);
744 if (!test_peer_load_icon(client))
746 WLog_DBG(TAG,
"Unable to load icon");
750 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm,
"rdpdbg"))
752 context->debug_channel = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION,
"rdpdbg");
754 if (context->debug_channel != NULL)
756 WLog_DBG(TAG,
"Open channel rdpdbg.");
758 if (!(context->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
760 WLog_ERR(TAG,
"Failed to create stop event");
764 if (!(context->debug_channel_thread =
765 CreateThread(NULL, 0, tf_debug_channel_thread_func, (
void*)context, 0, NULL)))
767 WLog_ERR(TAG,
"Failed to create debug channel thread");
768 (void)CloseHandle(context->stopEvent);
769 context->stopEvent = NULL;
775 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, RDPSND_CHANNEL_NAME))
777 sf_peer_rdpsnd_init(context);
780 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, ENCOMSP_SVC_CHANNEL_NAME))
782 sf_peer_encomsp_init(context);
786 sf_peer_audin_init(context);
788 #if defined(CHANNEL_AINPUT_SERVER)
789 sf_peer_ainput_init(context);
796 static BOOL tf_peer_activate(freerdp_peer* client)
798 testPeerContext* context = NULL;
799 struct server_info* info = NULL;
800 rdpSettings* settings = NULL;
802 WINPR_ASSERT(client);
804 context = (testPeerContext*)client->context;
805 WINPR_ASSERT(context);
807 settings = client->context->settings;
808 WINPR_ASSERT(settings);
810 info = client->ContextExtra;
813 context->activated = TRUE;
820 if (info->test_pcap_file != NULL)
825 if (!tf_peer_dump_rfx(client))
829 test_peer_draw_background(client);
834 static BOOL tf_peer_synchronize_event(rdpInput* input, UINT32 flags)
838 WLog_DBG(TAG,
"Client sent a synchronize event (flags:0x%" PRIX32
")", flags);
842 static BOOL tf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
844 freerdp_peer* client = NULL;
845 rdpUpdate* update = NULL;
846 rdpContext* context = NULL;
847 testPeerContext* tcontext = NULL;
848 rdpSettings* settings = NULL;
852 context = input->context;
853 WINPR_ASSERT(context);
855 client = context->peer;
856 WINPR_ASSERT(client);
858 settings = context->settings;
859 WINPR_ASSERT(settings);
861 update = context->update;
862 WINPR_ASSERT(update);
864 tcontext = (testPeerContext*)context;
865 WINPR_ASSERT(tcontext);
867 WLog_DBG(TAG,
"Client sent a keyboard event (flags:0x%04" PRIX16
" code:0x%04" PRIX8
")", flags,
870 if (((flags & KBD_FLAGS_RELEASE) == 0) && (code == RDP_SCANCODE_KEY_G))
882 SAMPLE_SERVER_DEFAULT_WIDTH))
885 SAMPLE_SERVER_DEFAULT_HEIGHT))
889 if (!rfx_context_reset(tcontext->rfx_context,
894 WINPR_ASSERT(update->DesktopResize);
895 update->DesktopResize(update->context);
896 tcontext->activated = FALSE;
898 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_C)
900 if (tcontext->debug_channel)
903 if (!WTSVirtualChannelWrite(tcontext->debug_channel, (PCHAR)
"test2", 5, &written))
907 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_X)
909 WINPR_ASSERT(client->Close);
910 client->Close(client);
912 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_R)
914 tcontext->audin_open = !tcontext->audin_open;
916 #if defined(CHANNEL_AINPUT_SERVER)
917 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_I)
919 tcontext->ainput_open = !tcontext->ainput_open;
922 else if (((flags & KBD_FLAGS_RELEASE) == 0) && code == RDP_SCANCODE_KEY_S)
929 static BOOL tf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
935 "Client sent a unicode keyboard event (flags:0x%04" PRIX16
" code:0x%04" PRIX16
")",
940 static BOOL tf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
944 WINPR_ASSERT(input->context);
948 test_peer_draw_icon(input->context->peer, x + 10, y);
952 static BOOL tf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
956 WINPR_ASSERT(input->context);
960 test_peer_draw_icon(input->context->peer, x + 10, y);
964 static BOOL tf_peer_refresh_rect(rdpContext* context, BYTE count,
const RECTANGLE_16* areas)
966 WINPR_UNUSED(context);
967 WINPR_ASSERT(context);
968 WINPR_ASSERT(areas || (count == 0));
970 WLog_DBG(TAG,
"Client requested to refresh:");
972 for (BYTE i = 0; i < count; i++)
974 WLog_DBG(TAG,
" (%" PRIu16
", %" PRIu16
") (%" PRIu16
", %" PRIu16
")", areas[i].left,
975 areas[i].top, areas[i].right, areas[i].bottom);
981 static BOOL tf_peer_suppress_output(rdpContext* context, BYTE allow,
const RECTANGLE_16* area)
983 WINPR_UNUSED(context);
989 "Client restore output (%" PRIu16
", %" PRIu16
") (%" PRIu16
", %" PRIu16
").",
990 area->left, area->top, area->right, area->bottom);
994 WLog_DBG(TAG,
"Client minimized and suppress output.");
1000 static int hook_peer_write_pdu(rdpTransport* transport,
wStream* s)
1005 const struct server_info* info = NULL;
1006 freerdp_peer* client = NULL;
1007 testPeerContext* peerCtx = NULL;
1010 rdpContext* context = transport_get_context(transport);
1012 WINPR_ASSERT(context);
1015 client = context->peer;
1016 WINPR_ASSERT(client);
1018 peerCtx = (testPeerContext*)client->context;
1019 WINPR_ASSERT(peerCtx);
1020 WINPR_ASSERT(peerCtx->io.WritePdu);
1022 info = client->ContextExtra;
1033 CONNECTION_STATE state = freerdp_get_state(context);
1034 if (state < CONNECTION_STATE_NEGO)
1035 return peerCtx->io.WritePdu(transport, s);
1037 ls = Stream_New(NULL, 4096);
1041 while (stream_dump_get(context, &flags, ls, &offset, &ts) > 0)
1045 if (flags & STREAM_MSG_SRV_TX)
1047 if ((last_ts > 0) && (ts > last_ts))
1049 UINT64 diff = ts - last_ts;
1052 UINT32 d = diff > UINT32_MAX ? UINT32_MAX : (UINT32)diff;
1058 rc = peerCtx->io.WritePdu(transport, ls);
1062 Stream_SetPosition(ls, 0);
1066 Stream_Free(ls, TRUE);
1070 static DWORD WINAPI test_peer_mainloop(LPVOID arg)
1073 DWORD error = CHANNEL_RC_OK;
1074 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
1077 testPeerContext* context = NULL;
1078 struct server_info* info = NULL;
1079 rdpSettings* settings = NULL;
1080 rdpInput* input = NULL;
1081 rdpUpdate* update = NULL;
1082 freerdp_peer* client = (freerdp_peer*)arg;
1084 WINPR_ASSERT(client);
1086 info = client->ContextExtra;
1089 if (!test_peer_init(client))
1091 freerdp_peer_free(client);
1096 WINPR_ASSERT(client->context);
1097 settings = client->context->settings;
1098 WINPR_ASSERT(settings);
1099 if (info->replay_dump)
1106 rdpPrivateKey* key = freerdp_key_new_from_file(info->key);
1111 rdpCertificate* cert = freerdp_certificate_new_from_file(info->cert);
1124 ENCRYPTION_LEVEL_CLIENT_COMPATIBLE))
1140 client->PostConnect = tf_peer_post_connect;
1141 client->Activate = tf_peer_activate;
1143 WINPR_ASSERT(client->context);
1144 input = client->context->input;
1145 WINPR_ASSERT(input);
1147 input->SynchronizeEvent = tf_peer_synchronize_event;
1148 input->KeyboardEvent = tf_peer_keyboard_event;
1149 input->UnicodeKeyboardEvent = tf_peer_unicode_keyboard_event;
1150 input->MouseEvent = tf_peer_mouse_event;
1151 input->ExtendedMouseEvent = tf_peer_extended_mouse_event;
1153 update = client->context->update;
1154 WINPR_ASSERT(update);
1156 update->RefreshRect = tf_peer_refresh_rect;
1157 update->SuppressOutput = tf_peer_suppress_output;
1162 WINPR_ASSERT(client->Initialize);
1163 rc = client->Initialize(client);
1167 context = (testPeerContext*)client->context;
1168 WINPR_ASSERT(context);
1170 if (info->replay_dump)
1172 const rdpTransportIo* cb = freerdp_get_io_callbacks(client->context);
1173 rdpTransportIo replay;
1178 replay.WritePdu = hook_peer_write_pdu;
1179 freerdp_set_io_callbacks(client->context, &replay);
1182 WLog_INFO(TAG,
"We've got a client %s", client->local ?
"(local)" : client->hostname);
1184 while (error == CHANNEL_RC_OK)
1188 WINPR_ASSERT(client->GetEventHandles);
1189 DWORD tmp = client->GetEventHandles(client, &handles[count], 32 - count);
1193 WLog_ERR(TAG,
"Failed to get FreeRDP transport event handles");
1200 HANDLE channelHandle = WTSVirtualChannelManagerGetEventHandle(context->vcm);
1201 handles[count++] = channelHandle;
1202 status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
1204 if (status == WAIT_FAILED)
1206 WLog_ERR(TAG,
"WaitForMultipleObjects failed (errno: %d)", errno);
1210 WINPR_ASSERT(client->CheckFileDescriptor);
1211 if (client->CheckFileDescriptor(client) != TRUE)
1214 if (WaitForSingleObject(channelHandle, 0) != WAIT_OBJECT_0)
1217 if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
1221 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, DRDYNVC_SVC_CHANNEL_NAME))
1223 switch (WTSVirtualChannelManagerGetDrdynvcState(context->vcm))
1225 case DRDYNVC_STATE_NONE:
1228 case DRDYNVC_STATE_INITIALIZED:
1231 case DRDYNVC_STATE_READY:
1234 if (sf_peer_audin_running(context) != context->audin_open)
1236 if (!sf_peer_audin_running(context))
1237 sf_peer_audin_start(context);
1239 sf_peer_audin_stop(context);
1242 #if defined(CHANNEL_AINPUT_SERVER)
1243 if (sf_peer_ainput_running(context) != context->ainput_open)
1245 if (!sf_peer_ainput_running(context))
1246 sf_peer_ainput_start(context);
1248 sf_peer_ainput_stop(context);
1254 case DRDYNVC_STATE_FAILED:
1261 WLog_INFO(TAG,
"Client %s disconnected.", client->local ?
"(local)" : client->hostname);
1263 WINPR_ASSERT(client->Disconnect);
1264 client->Disconnect(client);
1266 freerdp_peer_context_free(client);
1267 freerdp_peer_free(client);
1271 static BOOL test_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
1273 HANDLE hThread = NULL;
1274 struct server_info* info = NULL;
1276 WINPR_UNUSED(instance);
1278 WINPR_ASSERT(instance);
1279 WINPR_ASSERT(client);
1281 info = instance->info;
1282 client->ContextExtra = info;
1284 if (!(hThread = CreateThread(NULL, 0, test_peer_mainloop, (
void*)client, 0, NULL)))
1287 (void)CloseHandle(hThread);
1291 static void test_server_mainloop(freerdp_listener* instance)
1293 HANDLE handles[32] = { 0 };
1297 WINPR_ASSERT(instance);
1300 WINPR_ASSERT(instance->GetEventHandles);
1301 count = instance->GetEventHandles(instance, handles, 32);
1305 WLog_ERR(TAG,
"Failed to get FreeRDP event handles");
1309 status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
1311 if (WAIT_FAILED == status)
1313 WLog_ERR(TAG,
"select failed");
1317 WINPR_ASSERT(instance->CheckFileDescriptor);
1318 if (instance->CheckFileDescriptor(instance) != TRUE)
1320 WLog_ERR(TAG,
"Failed to check FreeRDP file descriptor");
1325 WINPR_ASSERT(instance->Close);
1326 instance->Close(instance);
1331 const char spcap[7];
1332 const char sfast[7];
1333 const char sport[7];
1334 const char slocal_only[13];
1335 const char scert[7];
1337 } options = {
"--pcap=",
"--fast",
"--port=",
"--local-only",
"--cert=",
"--key=" };
1339 WINPR_PRAGMA_DIAG_PUSH
1340 WINPR_PRAGMA_DIAG_IGNORED_FORMAT_NONLITERAL
1341 WINPR_ATTR_FORMAT_ARG(2, 0)
1342 static
void print_entry(FILE* fp, WINPR_FORMAT_ARG const
char* fmt, const
char* what,
size_t size)
1344 char buffer[32] = { 0 };
1345 strncpy(buffer, what, MIN(size,
sizeof(buffer) - 1));
1346 (void)fprintf(fp, fmt, buffer);
1348 WINPR_PRAGMA_DIAG_POP
1350 static WINPR_NORETURN(
void usage(
const char* app,
const char* invalid))
1354 (void)fprintf(fp,
"Invalid argument '%s'\n", invalid);
1355 (void)fprintf(fp,
"Usage: %s <arg>[ <arg> ...]\n", app);
1356 (void)fprintf(fp,
"Arguments:\n");
1357 print_entry(fp,
"\t%s<pcap file>\n", options.spcap,
sizeof(options.spcap));
1358 print_entry(fp,
"\t%s<cert file>\n", options.scert,
sizeof(options.scert));
1359 print_entry(fp,
"\t%s<key file>\n", options.skey,
sizeof(options.skey));
1360 print_entry(fp,
"\t%s\n", options.sfast,
sizeof(options.sfast));
1361 print_entry(fp,
"\t%s<port>\n", options.sport,
sizeof(options.sport));
1362 print_entry(fp,
"\t%s\n", options.slocal_only,
sizeof(options.slocal_only));
1366 int main(
int argc,
char* argv[])
1369 BOOL started = FALSE;
1371 freerdp_listener* instance = NULL;
1373 char name[MAX_PATH] = { 0 };
1375 BOOL localOnly = FALSE;
1376 struct server_info info = { 0 };
1377 const char* app = argv[0];
1379 info.test_dump_rfx_realtime = TRUE;
1383 for (
int i = 1; i < argc; i++)
1385 char* arg = argv[i];
1387 if (strncmp(arg, options.sfast,
sizeof(options.sfast)) == 0)
1388 info.test_dump_rfx_realtime = FALSE;
1389 else if (strncmp(arg, options.sport,
sizeof(options.sport)) == 0)
1391 const char* sport = &arg[
sizeof(options.sport)];
1392 port = strtol(sport, NULL, 10);
1394 if ((port < 1) || (port > UINT16_MAX) || (errno != 0))
1397 else if (strncmp(arg, options.slocal_only,
sizeof(options.slocal_only)) == 0)
1399 else if (strncmp(arg, options.spcap,
sizeof(options.spcap)) == 0)
1401 info.test_pcap_file = &arg[
sizeof(options.spcap)];
1402 if (!winpr_PathFileExists(info.test_pcap_file))
1405 else if (strncmp(arg, options.scert,
sizeof(options.scert)) == 0)
1407 info.cert = &arg[
sizeof(options.scert)];
1408 if (!winpr_PathFileExists(info.cert))
1411 else if (strncmp(arg, options.skey,
sizeof(options.skey)) == 0)
1413 info.key = &arg[
sizeof(options.skey)];
1414 if (!winpr_PathFileExists(info.key))
1421 WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
1422 winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
1423 instance = freerdp_listener_new();
1429 info.cert =
"server.crt";
1431 info.key =
"server.key";
1433 instance->info = (
void*)&info;
1434 instance->PeerAccepted = test_peer_accepted;
1436 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
1440 (void)sprintf_s(name,
sizeof(name),
"tfreerdp-server.%ld", port);
1441 file = GetKnownSubPath(KNOWN_PATH_TEMP, name);
1448 WINPR_ASSERT(instance->OpenLocal);
1449 started = instance->OpenLocal(instance, file);
1453 WINPR_ASSERT(instance->Open);
1454 started = instance->Open(instance, NULL, (UINT16)port);
1461 test_server_mainloop(instance);
1467 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 const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.