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