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