FreeRDP
shadow_client.c
1 
21 #include <freerdp/config.h>
22 
23 #include <winpr/crt.h>
24 #include <winpr/assert.h>
25 #include <winpr/cast.h>
26 #include <winpr/file.h>
27 #include <winpr/path.h>
28 #include <winpr/synch.h>
29 #include <winpr/thread.h>
30 #include <winpr/sysinfo.h>
31 #include <winpr/interlocked.h>
32 
33 #include <freerdp/log.h>
34 #include <freerdp/channels/drdynvc.h>
35 
36 #include "shadow.h"
37 
38 #define TAG CLIENT_TAG("shadow")
39 
40 typedef struct
41 {
42  BOOL gfxOpened;
43  BOOL gfxSurfaceCreated;
44 } SHADOW_GFX_STATUS;
45 
46 /* See https://github.com/FreeRDP/FreeRDP/issues/10413
47  *
48  * Microsoft ditched support for RFX and multiple rectangles in BitmapUpdate for
49  * windows 11 24H2.
50  *
51  * So send all updates only with a single rectangle.
52  */
53 #define BitmapUpdateProxy(update, context, bitmap) \
54  BitmapUpdateProxyEx((update), (context), (bitmap), __FILE__, __LINE__, __func__)
55 static BOOL BitmapUpdateProxyEx(rdpUpdate* update, rdpContext* context, const BITMAP_UPDATE* bitmap,
56  const char* file, size_t line, const char* fkt)
57 {
58  WINPR_ASSERT(update);
59  WINPR_ASSERT(context);
60  WINPR_ASSERT(bitmap);
61 
62  for (UINT32 x = 0; x < bitmap->number; x++)
63  {
64  BITMAP_UPDATE cur = { 0 };
65  BITMAP_DATA* bmp = &bitmap->rectangles[x];
66  cur.rectangles = bmp;
67  cur.number = 1;
68  cur.skipCompression = bitmap->skipCompression;
69  const BOOL rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, &cur);
70  if (!rc)
71  {
72  const DWORD log_level = WLOG_ERROR;
73  wLog* log = WLog_Get(TAG);
74  if (WLog_IsLevelActive(log, log_level))
75  {
76  WLog_PrintMessage(log, WLOG_MESSAGE_TEXT, log_level, line, file, fkt,
77  "BitmapUpdate[%" PRIu32 "] failed", x);
78  }
79  return FALSE;
80  }
81  }
82 
83  return TRUE;
84 }
85 
86 static INLINE BOOL shadow_client_rdpgfx_new_surface(rdpShadowClient* client)
87 {
88  UINT error = CHANNEL_RC_OK;
89  RDPGFX_CREATE_SURFACE_PDU createSurface;
90  RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU surfaceToOutput;
91  RdpgfxServerContext* context = NULL;
92  rdpSettings* settings = NULL;
93 
94  WINPR_ASSERT(client);
95  context = client->rdpgfx;
96  WINPR_ASSERT(context);
97  settings = ((rdpContext*)client)->settings;
98  WINPR_ASSERT(settings);
99 
100  WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) <= UINT16_MAX);
101  WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) <= UINT16_MAX);
102  createSurface.width = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
103  createSurface.height = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
104  createSurface.pixelFormat = GFX_PIXEL_FORMAT_XRGB_8888;
105  createSurface.surfaceId = client->surfaceId;
106  surfaceToOutput.outputOriginX = 0;
107  surfaceToOutput.outputOriginY = 0;
108  surfaceToOutput.surfaceId = client->surfaceId;
109  surfaceToOutput.reserved = 0;
110  IFCALLRET(context->CreateSurface, error, context, &createSurface);
111 
112  if (error)
113  {
114  WLog_ERR(TAG, "CreateSurface failed with error %" PRIu32 "", error);
115  return FALSE;
116  }
117 
118  IFCALLRET(context->MapSurfaceToOutput, error, context, &surfaceToOutput);
119 
120  if (error)
121  {
122  WLog_ERR(TAG, "MapSurfaceToOutput failed with error %" PRIu32 "", error);
123  return FALSE;
124  }
125 
126  return TRUE;
127 }
128 
129 static INLINE BOOL shadow_client_rdpgfx_release_surface(rdpShadowClient* client)
130 {
131  UINT error = CHANNEL_RC_OK;
133  RdpgfxServerContext* context = NULL;
134 
135  WINPR_ASSERT(client);
136 
137  context = client->rdpgfx;
138  WINPR_ASSERT(context);
139 
140  pdu.surfaceId = client->surfaceId++;
141  IFCALLRET(context->DeleteSurface, error, context, &pdu);
142 
143  if (error)
144  {
145  WLog_ERR(TAG, "DeleteSurface failed with error %" PRIu32 "", error);
146  return FALSE;
147  }
148 
149  return TRUE;
150 }
151 
152 static INLINE BOOL shadow_client_rdpgfx_reset_graphic(rdpShadowClient* client)
153 {
154  UINT error = CHANNEL_RC_OK;
155  RDPGFX_RESET_GRAPHICS_PDU pdu = { 0 };
156  RdpgfxServerContext* context = NULL;
157  rdpSettings* settings = NULL;
158 
159  WINPR_ASSERT(client);
160  WINPR_ASSERT(client->rdpgfx);
161 
162  context = client->rdpgfx;
163  WINPR_ASSERT(context);
164 
165  settings = client->context.settings;
166  WINPR_ASSERT(settings);
167 
168  pdu.width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
169  pdu.height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
170  pdu.monitorCount = client->subsystem->numMonitors;
171  pdu.monitorDefArray = client->subsystem->monitors;
172  IFCALLRET(context->ResetGraphics, error, context, &pdu);
173 
174  if (error)
175  {
176  WLog_ERR(TAG, "ResetGraphics failed with error %" PRIu32 "", error);
177  return FALSE;
178  }
179 
180  client->first_frame = TRUE;
181  return TRUE;
182 }
183 
184 static INLINE void shadow_client_free_queued_message(void* obj)
185 {
186  wMessage* message = (wMessage*)obj;
187 
188  WINPR_ASSERT(message);
189  if (message->Free)
190  {
191  message->Free(message);
192  message->Free = NULL;
193  }
194 }
195 
196 static void shadow_client_context_free(freerdp_peer* peer, rdpContext* context)
197 {
198  rdpShadowClient* client = (rdpShadowClient*)context;
199  rdpShadowServer* server = NULL;
200 
201  WINPR_UNUSED(peer);
202  if (!client)
203  return;
204 
205  server = client->server;
206  if (server && server->clients)
207  ArrayList_Remove(server->clients, (void*)client);
208 
209  shadow_encoder_free(client->encoder);
210 
211  /* Clear queued messages and free resource */
212  MessageQueue_Free(client->MsgQueue);
213  WTSCloseServer(client->vcm);
214  region16_uninit(&(client->invalidRegion));
215  DeleteCriticalSection(&(client->lock));
216 
217  client->MsgQueue = NULL;
218  client->encoder = NULL;
219  client->vcm = NULL;
220 }
221 
222 static BOOL shadow_client_context_new(freerdp_peer* peer, rdpContext* context)
223 {
224  BOOL NSCodec = 0;
225  const char bind_address[] = "bind-address,";
226  rdpShadowClient* client = (rdpShadowClient*)context;
227  rdpSettings* settings = NULL;
228  const rdpSettings* srvSettings = NULL;
229  rdpShadowServer* server = NULL;
230  const wObject cb = { NULL, NULL, NULL, shadow_client_free_queued_message, NULL };
231 
232  WINPR_ASSERT(client);
233  WINPR_ASSERT(peer);
234  WINPR_ASSERT(peer->context);
235 
236  server = (rdpShadowServer*)peer->ContextExtra;
237  WINPR_ASSERT(server);
238 
239  srvSettings = server->settings;
240  WINPR_ASSERT(srvSettings);
241 
242  client->surfaceId = 1;
243  client->server = server;
244  client->subsystem = server->subsystem;
245  WINPR_ASSERT(client->subsystem);
246 
247  settings = peer->context->settings;
248  WINPR_ASSERT(settings);
249 
250  if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth,
251  freerdp_settings_get_uint32(srvSettings, FreeRDP_ColorDepth)))
252  return FALSE;
253  NSCodec = freerdp_settings_get_bool(srvSettings, FreeRDP_NSCodec);
254  if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, NSCodec))
255  return FALSE;
256  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec,
257  freerdp_settings_get_bool(srvSettings, FreeRDP_RemoteFxCodec)))
258  return FALSE;
260  settings, FreeRDP_RemoteFxRlgrMode,
261  freerdp_settings_get_uint32(srvSettings, FreeRDP_RemoteFxRlgrMode)))
262  return FALSE;
263  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheV3Enabled, TRUE))
264  return FALSE;
265  if (!freerdp_settings_set_bool(settings, FreeRDP_FrameMarkerCommandEnabled, TRUE))
266  return FALSE;
267  if (!freerdp_settings_set_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled, TRUE))
268  return FALSE;
270  settings, FreeRDP_SupportGraphicsPipeline,
271  freerdp_settings_get_bool(srvSettings, FreeRDP_SupportGraphicsPipeline)))
272  return FALSE;
273  if (!freerdp_settings_set_bool(settings, FreeRDP_GfxH264,
274  freerdp_settings_get_bool(srvSettings, FreeRDP_GfxH264)))
275  return FALSE;
276  if (!freerdp_settings_set_bool(settings, FreeRDP_DrawAllowSkipAlpha, TRUE))
277  return FALSE;
278  if (!freerdp_settings_set_bool(settings, FreeRDP_DrawAllowColorSubsampling, TRUE))
279  return FALSE;
280  if (!freerdp_settings_set_bool(settings, FreeRDP_DrawAllowDynamicColorFidelity, TRUE))
281  return FALSE;
282  if (!freerdp_settings_set_uint32(settings, FreeRDP_CompressionLevel, PACKET_COMPR_TYPE_RDP8))
283  return FALSE;
284 
285  if (server->ipcSocket && (strncmp(bind_address, server->ipcSocket,
286  strnlen(bind_address, sizeof(bind_address))) != 0))
287  {
288  if (!freerdp_settings_set_bool(settings, FreeRDP_LyncRdpMode, TRUE))
289  return FALSE;
290  if (!freerdp_settings_set_bool(settings, FreeRDP_CompressionEnabled, FALSE))
291  return FALSE;
292  }
293 
294  client->inLobby = TRUE;
295  client->mayView = server->mayView;
296  client->mayInteract = server->mayInteract;
297 
298  if (!InitializeCriticalSectionAndSpinCount(&(client->lock), 4000))
299  goto fail;
300 
301  region16_init(&(client->invalidRegion));
302  client->vcm = WTSOpenServerA((LPSTR)peer->context);
303 
304  if (!client->vcm || client->vcm == INVALID_HANDLE_VALUE)
305  goto fail;
306 
307  if (!(client->MsgQueue = MessageQueue_New(&cb)))
308  goto fail;
309 
310  if (!(client->encoder = shadow_encoder_new(client)))
311  goto fail;
312 
313  if (!ArrayList_Append(server->clients, (void*)client))
314  goto fail;
315 
316  return TRUE;
317 
318 fail:
319  shadow_client_context_free(peer, context);
320  return FALSE;
321 }
322 
323 static INLINE void shadow_client_mark_invalid(rdpShadowClient* client, UINT32 numRects,
324  const RECTANGLE_16* rects)
325 {
326  RECTANGLE_16 screenRegion;
327  rdpSettings* settings = NULL;
328 
329  WINPR_ASSERT(client);
330  WINPR_ASSERT(rects || (numRects == 0));
331 
332  settings = client->context.settings;
333  WINPR_ASSERT(settings);
334 
335  EnterCriticalSection(&(client->lock));
336 
337  /* Mark client invalid region. No rectangle means full screen */
338  if (numRects > 0)
339  {
340  for (UINT32 index = 0; index < numRects; index++)
341  {
342  region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
343  }
344  }
345  else
346  {
347  screenRegion.left = 0;
348  screenRegion.top = 0;
349  WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) <= UINT16_MAX);
350  WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) <= UINT16_MAX);
351  screenRegion.right = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
352  screenRegion.bottom = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
353  region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &screenRegion);
354  }
355 
356  LeaveCriticalSection(&(client->lock));
357 }
358 
365 static INLINE BOOL shadow_client_recalc_desktop_size(rdpShadowClient* client)
366 {
367  INT32 width = 0;
368  INT32 height = 0;
369  rdpShadowServer* server = NULL;
370  rdpSettings* settings = NULL;
371  RECTANGLE_16 viewport = { 0 };
372 
373  WINPR_ASSERT(client);
374  server = client->server;
375  settings = client->context.settings;
376 
377  WINPR_ASSERT(server);
378  WINPR_ASSERT(server->surface);
379  WINPR_ASSERT(settings);
380 
381  WINPR_ASSERT(server->surface->width <= UINT16_MAX);
382  WINPR_ASSERT(server->surface->height <= UINT16_MAX);
383  viewport.right = (UINT16)server->surface->width;
384  viewport.bottom = (UINT16)server->surface->height;
385 
386  if (server->shareSubRect)
387  {
388  rectangles_intersection(&viewport, &(server->subRect), &viewport);
389  }
390 
391  width = viewport.right - viewport.left;
392  height = viewport.bottom - viewport.top;
393 
394  WINPR_ASSERT(width >= 0);
395  WINPR_ASSERT(width <= UINT16_MAX);
396  WINPR_ASSERT(height >= 0);
397  WINPR_ASSERT(height <= UINT16_MAX);
398  if (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) != (UINT32)width ||
399  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) != (UINT32)height)
400  return TRUE;
401 
402  return FALSE;
403 }
404 
405 static BOOL shadow_client_capabilities(freerdp_peer* peer)
406 {
407  rdpShadowSubsystem* subsystem = NULL;
408  rdpShadowClient* client = NULL;
409  BOOL ret = TRUE;
410 
411  WINPR_ASSERT(peer);
412 
413  client = (rdpShadowClient*)peer->context;
414  WINPR_ASSERT(client);
415  WINPR_ASSERT(client->server);
416 
417  subsystem = client->server->subsystem;
418  WINPR_ASSERT(subsystem);
419 
420  IFCALLRET(subsystem->ClientCapabilities, ret, subsystem, client);
421 
422  if (!ret)
423  WLog_WARN(TAG, "subsystem->ClientCapabilities failed");
424 
425  return ret;
426 }
427 
428 static void shadow_reset_desktop_resize(rdpShadowClient* client)
429 {
430  WINPR_ASSERT(client);
431  client->resizeRequested = FALSE;
432 }
433 
434 static BOOL shadow_send_desktop_resize(rdpShadowClient* client)
435 {
436  BOOL rc = 0;
437  rdpUpdate* update = NULL;
438  rdpSettings* settings = NULL;
439  const freerdp_peer* peer = NULL;
440 
441  WINPR_ASSERT(client);
442 
443  settings = client->context.settings;
444  peer = client->context.peer;
445  WINPR_ASSERT(peer);
446  WINPR_ASSERT(client->server);
447  WINPR_ASSERT(client->server->surface);
448 
449  const UINT32 resizeWidth = client->server->surface->width;
450  const UINT32 resizeHeight = client->server->surface->height;
451 
452  if (client->resizeRequested)
453  {
454  if ((resizeWidth == client->resizeWidth) && (resizeHeight == client->resizeHeight))
455  {
456  const UINT32 w = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
457  const UINT32 h = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
458  WLog_WARN(TAG,
459  "detected previous resize request for resolution %" PRIu32 "x%" PRIu32
460  ", still have %" PRIu32 "x%" PRIu32 ", disconnecting peer",
461  resizeWidth, resizeHeight, w, h);
462  return FALSE;
463  }
464  }
465 
466  update = client->context.update;
467  WINPR_ASSERT(update);
468  WINPR_ASSERT(update->DesktopResize);
469 
470  // Update peer resolution, required so that during disconnect/reconnect the correct resolution
471  // is sent to the client.
472  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, resizeWidth))
473  return FALSE;
474  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, resizeHeight))
475  return FALSE;
476  rc = update->DesktopResize(update->context);
477  WLog_INFO(TAG, "Client %s resize requested (%" PRIu32 "x%" PRIu32 "@%" PRIu32 ")",
478  peer->hostname, resizeWidth, resizeHeight,
479  freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth));
480  client->resizeRequested = TRUE;
481  client->resizeWidth = resizeWidth;
482  client->resizeHeight = resizeHeight;
483 
484  return rc;
485 }
486 
487 static BOOL shadow_client_post_connect(freerdp_peer* peer)
488 {
489  int authStatus = 0;
490  rdpSettings* settings = NULL;
491  rdpShadowClient* client = NULL;
492  rdpShadowServer* server = NULL;
493  rdpShadowSubsystem* subsystem = NULL;
494 
495  WINPR_ASSERT(peer);
496 
497  client = (rdpShadowClient*)peer->context;
498  WINPR_ASSERT(client);
499 
500  settings = peer->context->settings;
501  WINPR_ASSERT(settings);
502 
503  server = client->server;
504  WINPR_ASSERT(server);
505 
506  subsystem = server->subsystem;
507  WINPR_ASSERT(subsystem);
508 
509  if (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) == 24)
510  {
511  if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 16)) /* disable 24bpp */
512  return FALSE;
513  }
514 
515  const UINT32 MultifragMaxRequestSize =
516  freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize);
517  if (MultifragMaxRequestSize < 0x3F0000)
518  {
519  BOOL rc = freerdp_settings_set_bool(
520  settings, FreeRDP_NSCodec,
521  FALSE); /* NSCodec compressor does not support fragmentation yet */
522  if (!rc)
523  return FALSE;
524  }
525 
526  WLog_INFO(TAG, "Client from %s is activated (%" PRIu32 "x%" PRIu32 "@%" PRIu32 ")",
527  peer->hostname, freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
528  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight),
529  freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth));
530 
531  if (shadow_client_channels_post_connect(client) != CHANNEL_RC_OK)
532  return FALSE;
533 
534  shadow_client_mark_invalid(client, 0, NULL);
535  authStatus = -1;
536 
537  const char* Username = freerdp_settings_get_string(settings, FreeRDP_Username);
538  const char* Domain = freerdp_settings_get_string(settings, FreeRDP_Domain);
539  const char* Password = freerdp_settings_get_string(settings, FreeRDP_Password);
540 
541  if (Username && Password)
542  {
543  if (!freerdp_settings_set_bool(settings, FreeRDP_AutoLogonEnabled, TRUE))
544  return FALSE;
545  }
546 
547  if (server->authentication && !freerdp_settings_get_bool(settings, FreeRDP_NlaSecurity))
548  {
549  if (subsystem->Authenticate)
550  {
551  authStatus = subsystem->Authenticate(subsystem, client, Username, Domain, Password);
552  }
553 
554  if (authStatus < 0)
555  {
556  WLog_ERR(TAG, "client authentication failure: %d", authStatus);
557  return FALSE;
558  }
559  }
560 
561  if (subsystem->ClientConnect)
562  {
563  return subsystem->ClientConnect(subsystem, client);
564  }
565 
566  return TRUE;
567 }
568 
569 /* Convert rects in sub rect coordinate to client/surface coordinate */
570 static INLINE void shadow_client_convert_rects(rdpShadowClient* client, RECTANGLE_16* dst,
571  const RECTANGLE_16* src, UINT32 numRects)
572 {
573  WINPR_ASSERT(client);
574  WINPR_ASSERT(client->server);
575  WINPR_ASSERT(dst);
576  WINPR_ASSERT(src || (numRects == 0));
577 
578  if (client->server->shareSubRect)
579  {
580  UINT16 offsetX = client->server->subRect.left;
581  UINT16 offsetY = client->server->subRect.top;
582 
583  for (UINT32 i = 0; i < numRects; i++)
584  {
585  const RECTANGLE_16* s = &src[i];
586  RECTANGLE_16* d = &dst[i];
587 
588  d->left = s->left + offsetX;
589  d->right = s->right + offsetX;
590  d->top = s->top + offsetY;
591  d->bottom = s->bottom + offsetY;
592  }
593  }
594  else
595  {
596  if (src != dst)
597  {
598  CopyMemory(dst, src, numRects * sizeof(RECTANGLE_16));
599  }
600  }
601 }
602 
603 static BOOL shadow_client_refresh_request(rdpShadowClient* client)
604 {
605  wMessage message = { 0 };
606  wMessagePipe* MsgPipe = NULL;
607 
608  WINPR_ASSERT(client);
609  WINPR_ASSERT(client->subsystem);
610 
611  MsgPipe = client->subsystem->MsgPipe;
612  WINPR_ASSERT(MsgPipe);
613 
614  message.id = SHADOW_MSG_IN_REFRESH_REQUEST_ID;
615  message.wParam = NULL;
616  message.lParam = NULL;
617  message.context = (void*)client;
618  message.Free = NULL;
619  return MessageQueue_Dispatch(MsgPipe->In, &message);
620 }
621 
622 static BOOL shadow_client_refresh_rect(rdpContext* context, BYTE count, const RECTANGLE_16* areas)
623 {
624  rdpShadowClient* client = (rdpShadowClient*)context;
625  RECTANGLE_16* rects = NULL;
626 
627  /* It is invalid if we have area count but no actual area */
628  if (count && !areas)
629  return FALSE;
630 
631  if (count)
632  {
633  rects = (RECTANGLE_16*)calloc(count, sizeof(RECTANGLE_16));
634 
635  if (!rects)
636  {
637  return FALSE;
638  }
639 
640  shadow_client_convert_rects(client, rects, areas, count);
641  shadow_client_mark_invalid(client, count, rects);
642  free(rects);
643  }
644  else
645  {
646  shadow_client_mark_invalid(client, 0, NULL);
647  }
648 
649  return shadow_client_refresh_request(client);
650 }
651 
652 static BOOL shadow_client_suppress_output(rdpContext* context, BYTE allow, const RECTANGLE_16* area)
653 {
654  rdpShadowClient* client = (rdpShadowClient*)context;
655  RECTANGLE_16 region;
656 
657  WINPR_ASSERT(client);
658 
659  client->suppressOutput = allow ? FALSE : TRUE;
660 
661  if (allow)
662  {
663  if (area)
664  {
665  shadow_client_convert_rects(client, &region, area, 1);
666  shadow_client_mark_invalid(client, 1, &region);
667  }
668  else
669  {
670  shadow_client_mark_invalid(client, 0, NULL);
671  }
672  }
673 
674  return shadow_client_refresh_request(client);
675 }
676 
677 static BOOL shadow_client_activate(freerdp_peer* peer)
678 {
679  rdpSettings* settings = NULL;
680  rdpShadowClient* client = NULL;
681 
682  WINPR_ASSERT(peer);
683 
684  client = (rdpShadowClient*)peer->context;
685  WINPR_ASSERT(client);
686 
687  settings = peer->context->settings;
688  WINPR_ASSERT(settings);
689 
690  /* Resize client if necessary */
691  if (shadow_client_recalc_desktop_size(client))
692  return shadow_send_desktop_resize(client);
693 
694  shadow_reset_desktop_resize(client);
695  client->activated = TRUE;
696  client->inLobby = client->mayView ? FALSE : TRUE;
697 
698  if (shadow_encoder_reset(client->encoder) < 0)
699  {
700  WLog_ERR(TAG, "Failed to reset encoder");
701  return FALSE;
702  }
703 
704  /* Update full screen in next update */
705  return shadow_client_refresh_rect(&client->context, 0, NULL);
706 }
707 
708 static BOOL shadow_client_logon(freerdp_peer* peer, const SEC_WINNT_AUTH_IDENTITY* identity,
709  BOOL automatic)
710 {
711  BOOL rc = FALSE;
712  char* user = NULL;
713  char* domain = NULL;
714  char* password = NULL;
715  rdpSettings* settings = NULL;
716 
717  WINPR_UNUSED(automatic);
718 
719  WINPR_ASSERT(peer);
720  WINPR_ASSERT(identity);
721 
722  WINPR_ASSERT(peer->context);
723 
724  settings = peer->context->settings;
725  WINPR_ASSERT(settings);
726 
727  if (identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
728  {
729  if (identity->User)
730  user = ConvertWCharNToUtf8Alloc(identity->User, identity->UserLength, NULL);
731 
732  if (identity->Domain)
733  domain = ConvertWCharNToUtf8Alloc(identity->Domain, identity->DomainLength, NULL);
734 
735  if (identity->Password)
736  password = ConvertWCharNToUtf8Alloc(identity->Password, identity->PasswordLength, NULL);
737  }
738  else
739  {
740  if (identity->User)
741  user = _strdup((char*)identity->User);
742 
743  if (identity->Domain)
744  domain = _strdup((char*)identity->Domain);
745 
746  if (identity->Password)
747  password = _strdup((char*)identity->Password);
748  }
749 
750  if ((identity->User && !user) || (identity->Domain && !domain) ||
751  (identity->Password && !password))
752  goto fail;
753 
754  if (user)
755  {
756  if (!freerdp_settings_set_string(settings, FreeRDP_Username, user))
757  goto fail;
758  }
759 
760  if (domain)
761  {
762  if (!freerdp_settings_set_string(settings, FreeRDP_Domain, domain))
763  goto fail;
764  }
765  if (password)
766  {
767  if (!freerdp_settings_set_string(settings, FreeRDP_Password, password))
768  goto fail;
769  }
770  rc = TRUE;
771 fail:
772  free(user);
773  free(domain);
774  free(password);
775  return rc;
776 }
777 
778 static INLINE void shadow_client_common_frame_acknowledge(rdpShadowClient* client, UINT32 frameId)
779 {
780  /*
781  * Record the last client acknowledged frame id to
782  * calculate how much frames are in progress.
783  * Some rdp clients (win7 mstsc) skips frame ACK if it is
784  * inactive, we should not expect ACK for each frame.
785  * So it is OK to calculate in-flight frame count according to
786  * a latest acknowledged frame id.
787  */
788  WINPR_ASSERT(client);
789  WINPR_ASSERT(client->encoder);
790  client->encoder->lastAckframeId = frameId;
791 }
792 
793 static BOOL shadow_client_surface_frame_acknowledge(rdpContext* context, UINT32 frameId)
794 {
795  rdpShadowClient* client = (rdpShadowClient*)context;
796  shadow_client_common_frame_acknowledge(client, frameId);
797  /*
798  * Reset queueDepth for legacy none RDPGFX acknowledge
799  */
800  WINPR_ASSERT(client);
801  WINPR_ASSERT(client->encoder);
802  client->encoder->queueDepth = QUEUE_DEPTH_UNAVAILABLE;
803  return TRUE;
804 }
805 
806 static UINT
807 shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context,
808  const RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge)
809 {
810  rdpShadowClient* client = NULL;
811 
812  WINPR_ASSERT(context);
813  WINPR_ASSERT(frameAcknowledge);
814 
815  client = (rdpShadowClient*)context->custom;
816  shadow_client_common_frame_acknowledge(client, frameAcknowledge->frameId);
817 
818  WINPR_ASSERT(client);
819  WINPR_ASSERT(client->encoder);
820  client->encoder->queueDepth = frameAcknowledge->queueDepth;
821  return CHANNEL_RC_OK;
822 }
823 
824 static BOOL shadow_are_caps_filtered(const rdpSettings* settings, UINT32 caps)
825 {
826  const UINT32 capList[] = { RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81,
827  RDPGFX_CAPVERSION_10, RDPGFX_CAPVERSION_101,
828  RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103,
829  RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105,
830  RDPGFX_CAPVERSION_106, RDPGFX_CAPVERSION_106_ERR,
831  RDPGFX_CAPVERSION_107 };
832 
833  WINPR_ASSERT(settings);
834  const UINT32 filter = freerdp_settings_get_uint32(settings, FreeRDP_GfxCapsFilter);
835 
836  for (UINT32 x = 0; x < ARRAYSIZE(capList); x++)
837  {
838  if (caps == capList[x])
839  return (filter & (1 << x)) != 0;
840  }
841 
842  return TRUE;
843 }
844 
845 static UINT shadow_client_send_caps_confirm(RdpgfxServerContext* context, rdpShadowClient* client,
846  const RDPGFX_CAPS_CONFIRM_PDU* pdu)
847 {
848  WINPR_ASSERT(context);
849  WINPR_ASSERT(client);
850  WINPR_ASSERT(pdu);
851 
852  WINPR_ASSERT(context->CapsConfirm);
853  UINT rc = context->CapsConfirm(context, pdu);
854  client->areGfxCapsReady = (rc == CHANNEL_RC_OK);
855  return rc;
856 }
857 
858 static BOOL shadow_client_caps_test_version(RdpgfxServerContext* context, rdpShadowClient* client,
859  BOOL h264, const RDPGFX_CAPSET* capsSets,
860  UINT32 capsSetCount, UINT32 capsVersion, UINT* rc)
861 {
862  const rdpSettings* srvSettings = NULL;
863  rdpSettings* clientSettings = NULL;
864 
865  WINPR_ASSERT(context);
866  WINPR_ASSERT(client);
867  WINPR_ASSERT(capsSets || (capsSetCount == 0));
868  WINPR_ASSERT(rc);
869 
870  WINPR_ASSERT(context->rdpcontext);
871  srvSettings = context->rdpcontext->settings;
872  WINPR_ASSERT(srvSettings);
873 
874  clientSettings = client->context.settings;
875  WINPR_ASSERT(clientSettings);
876 
877  if (shadow_are_caps_filtered(srvSettings, capsVersion))
878  return FALSE;
879 
880  for (UINT32 index = 0; index < capsSetCount; index++)
881  {
882  const RDPGFX_CAPSET* currentCaps = &capsSets[index];
883 
884  if (currentCaps->version == capsVersion)
885  {
886  UINT32 flags = 0;
887  BOOL planar = FALSE;
888  BOOL rfx = FALSE;
889  BOOL avc444v2 = FALSE;
890  BOOL avc444 = FALSE;
891  BOOL avc420 = FALSE;
892  BOOL progressive = FALSE;
893  RDPGFX_CAPSET caps = *currentCaps;
894  RDPGFX_CAPS_CONFIRM_PDU pdu = { 0 };
895  pdu.capsSet = &caps;
896 
897  flags = pdu.capsSet->flags;
898 
899  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxSmallCache,
900  (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) ? TRUE : FALSE))
901  return FALSE;
902 
903  avc444v2 = avc444 = !(flags & RDPGFX_CAPS_FLAG_AVC_DISABLED);
904  if (!freerdp_settings_get_bool(srvSettings, FreeRDP_GfxAVC444v2) || !h264)
905  avc444v2 = FALSE;
906  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, avc444v2))
907  return FALSE;
908  if (!freerdp_settings_get_bool(srvSettings, FreeRDP_GfxAVC444) || !h264)
909  avc444 = FALSE;
910  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, avc444))
911  return FALSE;
912  if (!freerdp_settings_get_bool(srvSettings, FreeRDP_GfxH264) || !h264)
913  avc420 = FALSE;
914  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, avc420))
915  return FALSE;
916 
917  progressive = freerdp_settings_get_bool(srvSettings, FreeRDP_GfxProgressive);
918  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxProgressive, progressive))
919  return FALSE;
920  progressive = freerdp_settings_get_bool(srvSettings, FreeRDP_GfxProgressiveV2);
921  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxProgressiveV2, progressive))
922  return FALSE;
923 
924  rfx = freerdp_settings_get_bool(srvSettings, FreeRDP_RemoteFxCodec);
925  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_RemoteFxCodec, rfx))
926  return FALSE;
927 
928  planar = freerdp_settings_get_bool(srvSettings, FreeRDP_GfxPlanar);
929  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxPlanar, planar))
930  return FALSE;
931 
932  if (!avc444v2 && !avc444 && !avc420)
933  pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
934 
935  *rc = shadow_client_send_caps_confirm(context, client, &pdu);
936  return TRUE;
937  }
938  }
939 
940  return FALSE;
941 }
942 
948 static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context,
949  const RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise)
950 {
951  UINT rc = ERROR_INTERNAL_ERROR;
952  const rdpSettings* srvSettings = NULL;
953  rdpSettings* clientSettings = NULL;
954  BOOL h264 = FALSE;
955 
956  UINT32 flags = 0;
957 
958  WINPR_ASSERT(context);
959  WINPR_ASSERT(capsAdvertise);
960 
961  rdpShadowClient* client = (rdpShadowClient*)context->custom;
962  WINPR_ASSERT(client);
963  WINPR_ASSERT(context->rdpcontext);
964 
965  srvSettings = context->rdpcontext->settings;
966  WINPR_ASSERT(srvSettings);
967 
968  clientSettings = client->context.settings;
969  WINPR_ASSERT(clientSettings);
970 
971 #ifdef WITH_GFX_H264
972  h264 =
973  (shadow_encoder_prepare(client->encoder, FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444) >= 0);
974 #else
975  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, FALSE))
976  return rc;
977  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, FALSE))
978  return rc;
979  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE))
980  return rc;
981 #endif
982 
983  /* Request full screen update for new gfx channel */
984  if (!shadow_client_refresh_rect(&client->context, 0, NULL))
985  return rc;
986 
987  if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets,
988  capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_107, &rc))
989  return rc;
990 
991  if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets,
992  capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_106, &rc))
993  return rc;
994 
995  if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets,
996  capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_106_ERR,
997  &rc))
998  return rc;
999 
1000  if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets,
1001  capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_105, &rc))
1002  return rc;
1003 
1004  if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets,
1005  capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_104, &rc))
1006  return rc;
1007 
1008  if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets,
1009  capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_103, &rc))
1010  return rc;
1011 
1012  if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets,
1013  capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_102, &rc))
1014  return rc;
1015 
1016  if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets,
1017  capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_101, &rc))
1018  return rc;
1019 
1020  if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets,
1021  capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_10, &rc))
1022  return rc;
1023 
1024  if (!shadow_are_caps_filtered(srvSettings, RDPGFX_CAPVERSION_81))
1025  {
1026  for (UINT32 index = 0; index < capsAdvertise->capsSetCount; index++)
1027  {
1028  const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
1029 
1030  if (currentCaps->version == RDPGFX_CAPVERSION_81)
1031  {
1032  RDPGFX_CAPSET caps = *currentCaps;
1034  pdu.capsSet = &caps;
1035 
1036  flags = pdu.capsSet->flags;
1037 
1038  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, FALSE))
1039  return rc;
1040  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, FALSE))
1041  return rc;
1042 
1043  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxThinClient,
1044  (flags & RDPGFX_CAPS_FLAG_THINCLIENT) ? TRUE
1045  : FALSE))
1046  return rc;
1047  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxSmallCache,
1048  (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) ? TRUE
1049  : FALSE))
1050  return rc;
1051 
1052 #ifndef WITH_GFX_H264
1053  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE))
1054  return rc;
1055  pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED;
1056 #else
1057 
1058  if (h264)
1059  {
1061  clientSettings, FreeRDP_GfxH264,
1062  (flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED) ? TRUE : FALSE))
1063  return rc;
1064  }
1065  else
1066  {
1067  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE))
1068  return rc;
1069  }
1070 #endif
1071 
1072  return shadow_client_send_caps_confirm(context, client, &pdu);
1073  }
1074  }
1075  }
1076 
1077  if (!shadow_are_caps_filtered(srvSettings, RDPGFX_CAPVERSION_8))
1078  {
1079  for (UINT32 index = 0; index < capsAdvertise->capsSetCount; index++)
1080  {
1081  const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
1082 
1083  if (currentCaps->version == RDPGFX_CAPVERSION_8)
1084  {
1085  RDPGFX_CAPSET caps = *currentCaps;
1087  pdu.capsSet = &caps;
1088  flags = pdu.capsSet->flags;
1089 
1090  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, FALSE))
1091  return rc;
1092  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, FALSE))
1093  return rc;
1094  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE))
1095  return rc;
1096 
1097  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxThinClient,
1098  (flags & RDPGFX_CAPS_FLAG_THINCLIENT) ? TRUE
1099  : FALSE))
1100  return rc;
1101  if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxSmallCache,
1102  (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) ? TRUE
1103  : FALSE))
1104  return rc;
1105 
1106  return shadow_client_send_caps_confirm(context, client, &pdu);
1107  }
1108  }
1109  }
1110 
1111  return CHANNEL_RC_UNSUPPORTED_VERSION;
1112 }
1113 
1114 static INLINE UINT32 rdpgfx_estimate_h264_avc420(RDPGFX_AVC420_BITMAP_STREAM* havc420)
1115 {
1116  /* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */
1117  WINPR_ASSERT(havc420);
1118  return sizeof(UINT32) /* numRegionRects */
1119  + 10ULL /* regionRects + quantQualityVals */
1120  * havc420->meta.numRegionRects +
1121  havc420->length;
1122 }
1123 
1129 static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, const BYTE* pSrcData,
1130  UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nXSrc,
1131  UINT16 nYSrc, UINT16 nWidth, UINT16 nHeight)
1132 {
1133  UINT32 id = 0;
1134  UINT error = CHANNEL_RC_OK;
1135  const rdpContext* context = (const rdpContext*)client;
1136  const rdpSettings* settings = NULL;
1137  rdpShadowEncoder* encoder = NULL;
1138  RDPGFX_SURFACE_COMMAND cmd = { 0 };
1139  RDPGFX_START_FRAME_PDU cmdstart = { 0 };
1140  RDPGFX_END_FRAME_PDU cmdend = { 0 };
1141  SYSTEMTIME sTime = { 0 };
1142 
1143  if (!context || !pSrcData)
1144  return FALSE;
1145 
1146  settings = context->settings;
1147  encoder = client->encoder;
1148 
1149  if (!settings || !encoder)
1150  return FALSE;
1151 
1152  if (client->first_frame)
1153  {
1154  rfx_context_reset(encoder->rfx, nWidth, nHeight);
1155  client->first_frame = FALSE;
1156  }
1157 
1158  cmdstart.frameId = shadow_encoder_create_frame_id(encoder);
1159  GetSystemTime(&sTime);
1160  cmdstart.timestamp = (UINT32)(sTime.wHour << 22U | sTime.wMinute << 16U | sTime.wSecond << 10U |
1161  sTime.wMilliseconds);
1162  cmdend.frameId = cmdstart.frameId;
1163  cmd.surfaceId = client->surfaceId;
1164  cmd.format = PIXEL_FORMAT_BGRX32;
1165  cmd.left = nXSrc;
1166  cmd.top = nYSrc;
1167  cmd.right = cmd.left + nWidth;
1168  cmd.bottom = cmd.top + nHeight;
1169  cmd.width = nWidth;
1170  cmd.height = nHeight;
1171 
1172  id = freerdp_settings_get_uint32(settings, FreeRDP_RemoteFxCodecId);
1173 #ifdef WITH_GFX_H264
1174  const BOOL GfxH264 = freerdp_settings_get_bool(settings, FreeRDP_GfxH264);
1175  const BOOL GfxAVC444 = freerdp_settings_get_bool(settings, FreeRDP_GfxAVC444);
1176  const BOOL GfxAVC444v2 = freerdp_settings_get_bool(settings, FreeRDP_GfxAVC444v2);
1177  if (GfxAVC444 || GfxAVC444v2)
1178  {
1179  INT32 rc = 0;
1180  RDPGFX_AVC444_BITMAP_STREAM avc444 = { 0 };
1181  RECTANGLE_16 regionRect = { 0 };
1182  BYTE version = GfxAVC444v2 ? 2 : 1;
1183 
1184  if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC444) < 0)
1185  {
1186  WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AVC444");
1187  return FALSE;
1188  }
1189 
1190  WINPR_ASSERT(cmd.left <= UINT16_MAX);
1191  WINPR_ASSERT(cmd.top <= UINT16_MAX);
1192  WINPR_ASSERT(cmd.right <= UINT16_MAX);
1193  WINPR_ASSERT(cmd.bottom <= UINT16_MAX);
1194  regionRect.left = (UINT16)cmd.left;
1195  regionRect.top = (UINT16)cmd.top;
1196  regionRect.right = (UINT16)cmd.right;
1197  regionRect.bottom = (UINT16)cmd.bottom;
1198  rc = avc444_compress(encoder->h264, pSrcData, cmd.format, nSrcStep, nWidth, nHeight,
1199  version, &regionRect, &avc444.LC, &avc444.bitstream[0].data,
1200  &avc444.bitstream[0].length, &avc444.bitstream[1].data,
1201  &avc444.bitstream[1].length, &avc444.bitstream[0].meta,
1202  &avc444.bitstream[1].meta);
1203  if (rc < 0)
1204  {
1205  WLog_ERR(TAG, "avc420_compress failed for avc444");
1206  return FALSE;
1207  }
1208 
1209  /* rc > 0 means new data */
1210  if (rc > 0)
1211  {
1212  avc444.cbAvc420EncodedBitstream1 = rdpgfx_estimate_h264_avc420(&avc444.bitstream[0]);
1213  cmd.codecId = GfxAVC444v2 ? RDPGFX_CODECID_AVC444v2 : RDPGFX_CODECID_AVC444;
1214  cmd.extra = (void*)&avc444;
1215  IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart,
1216  &cmdend);
1217  }
1218 
1219  free_h264_metablock(&avc444.bitstream[0].meta);
1220  free_h264_metablock(&avc444.bitstream[1].meta);
1221  if (error)
1222  {
1223  WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1224  return FALSE;
1225  }
1226  }
1227  else if (GfxH264)
1228  {
1229  INT32 rc = 0;
1230  RDPGFX_AVC420_BITMAP_STREAM avc420 = { 0 };
1231  RECTANGLE_16 regionRect;
1232 
1233  if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC420) < 0)
1234  {
1235  WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AVC420");
1236  return FALSE;
1237  }
1238 
1239  WINPR_ASSERT(cmd.left <= UINT16_MAX);
1240  WINPR_ASSERT(cmd.top <= UINT16_MAX);
1241  WINPR_ASSERT(cmd.right <= UINT16_MAX);
1242  WINPR_ASSERT(cmd.bottom <= UINT16_MAX);
1243  regionRect.left = (UINT16)cmd.left;
1244  regionRect.top = (UINT16)cmd.top;
1245  regionRect.right = (UINT16)cmd.right;
1246  regionRect.bottom = (UINT16)cmd.bottom;
1247  rc = avc420_compress(encoder->h264, pSrcData, cmd.format, nSrcStep, nWidth, nHeight,
1248  &regionRect, &avc420.data, &avc420.length, &avc420.meta);
1249  if (rc < 0)
1250  {
1251  WLog_ERR(TAG, "avc420_compress failed");
1252  return FALSE;
1253  }
1254 
1255  /* rc > 0 means new data */
1256  if (rc > 0)
1257  {
1258  cmd.codecId = RDPGFX_CODECID_AVC420;
1259  cmd.extra = (void*)&avc420;
1260 
1261  IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart,
1262  &cmdend);
1263  }
1264  free_h264_metablock(&avc420.meta);
1265 
1266  if (error)
1267  {
1268  WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1269  return FALSE;
1270  }
1271  }
1272  else
1273 #endif
1274  if (freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec) && (id != 0))
1275  {
1276  BOOL rc = 0;
1277  wStream* s = NULL;
1278  RFX_RECT rect;
1279 
1280  if (shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX) < 0)
1281  {
1282  WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_REMOTEFX");
1283  return FALSE;
1284  }
1285 
1286  s = Stream_New(NULL, 1024);
1287  WINPR_ASSERT(s);
1288 
1289  WINPR_ASSERT(cmd.left <= UINT16_MAX);
1290  WINPR_ASSERT(cmd.top <= UINT16_MAX);
1291  WINPR_ASSERT(cmd.right <= UINT16_MAX);
1292  WINPR_ASSERT(cmd.bottom <= UINT16_MAX);
1293  rect.x = (UINT16)cmd.left;
1294  rect.y = (UINT16)cmd.top;
1295  rect.width = WINPR_ASSERTING_INT_CAST(UINT16, cmd.right - cmd.left);
1296  rect.height = WINPR_ASSERTING_INT_CAST(UINT16, cmd.bottom - cmd.top);
1297 
1298  rc = rfx_compose_message(encoder->rfx, s, &rect, 1, pSrcData, nWidth, nHeight, nSrcStep);
1299 
1300  if (!rc)
1301  {
1302  WLog_ERR(TAG, "rfx_compose_message failed");
1303  Stream_Free(s, TRUE);
1304  return FALSE;
1305  }
1306 
1307  /* rc > 0 means new data */
1308  if (rc > 0)
1309  {
1310  const size_t pos = Stream_GetPosition(s);
1311  WINPR_ASSERT(pos <= UINT32_MAX);
1312 
1313  cmd.codecId = RDPGFX_CODECID_CAVIDEO;
1314  cmd.data = Stream_Buffer(s);
1315  cmd.length = (UINT32)pos;
1316 
1317  IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart,
1318  &cmdend);
1319  }
1320 
1321  Stream_Free(s, TRUE);
1322  if (error)
1323  {
1324  WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1325  return FALSE;
1326  }
1327  }
1328  else if (freerdp_settings_get_bool(settings, FreeRDP_GfxProgressive))
1329  {
1330  INT32 rc = 0;
1331  REGION16 region;
1332  RECTANGLE_16 regionRect;
1333 
1334  if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PROGRESSIVE) < 0)
1335  {
1336  WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_PROGRESSIVE");
1337  return FALSE;
1338  }
1339 
1340  WINPR_ASSERT(cmd.left <= UINT16_MAX);
1341  WINPR_ASSERT(cmd.top <= UINT16_MAX);
1342  WINPR_ASSERT(cmd.right <= UINT16_MAX);
1343  WINPR_ASSERT(cmd.bottom <= UINT16_MAX);
1344  regionRect.left = (UINT16)cmd.left;
1345  regionRect.top = (UINT16)cmd.top;
1346  regionRect.right = (UINT16)cmd.right;
1347  regionRect.bottom = (UINT16)cmd.bottom;
1348  region16_init(&region);
1349  region16_union_rect(&region, &region, &regionRect);
1350  rc = progressive_compress(encoder->progressive, pSrcData, nSrcStep * nHeight, cmd.format,
1351  nWidth, nHeight, nSrcStep, &region, &cmd.data, &cmd.length);
1352  region16_uninit(&region);
1353  if (rc < 0)
1354  {
1355  WLog_ERR(TAG, "progressive_compress failed");
1356  return FALSE;
1357  }
1358 
1359  /* rc > 0 means new data */
1360  if (rc > 0)
1361  {
1362  cmd.codecId = RDPGFX_CODECID_CAPROGRESSIVE;
1363 
1364  IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart,
1365  &cmdend);
1366  }
1367 
1368  if (error)
1369  {
1370  WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1371  return FALSE;
1372  }
1373  }
1374  else if (freerdp_settings_get_bool(settings, FreeRDP_GfxPlanar))
1375  {
1376  BOOL rc = 0;
1377  const UINT32 w = cmd.right - cmd.left;
1378  const UINT32 h = cmd.bottom - cmd.top;
1379  const BYTE* src =
1380  &pSrcData[cmd.top * nSrcStep + cmd.left * FreeRDPGetBytesPerPixel(SrcFormat)];
1381  if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR) < 0)
1382  {
1383  WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_PLANAR");
1384  return FALSE;
1385  }
1386 
1387  rc = freerdp_bitmap_planar_context_reset(encoder->planar, w, h);
1388  WINPR_ASSERT(rc);
1389  freerdp_planar_topdown_image(encoder->planar, TRUE);
1390 
1391  cmd.data = freerdp_bitmap_compress_planar(encoder->planar, src, SrcFormat, w, h, nSrcStep,
1392  NULL, &cmd.length);
1393  WINPR_ASSERT(cmd.data || (cmd.length == 0));
1394 
1395  cmd.codecId = RDPGFX_CODECID_PLANAR;
1396 
1397  IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart,
1398  &cmdend);
1399  free(cmd.data);
1400  if (error)
1401  {
1402  WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1403  return FALSE;
1404  }
1405  }
1406  else
1407  {
1408  BOOL rc = 0;
1409  const UINT32 w = cmd.right - cmd.left;
1410  const UINT32 h = cmd.bottom - cmd.top;
1411  const UINT32 length = w * 4 * h;
1412  BYTE* data = malloc(length);
1413 
1414  WINPR_ASSERT(data);
1415 
1416  rc = freerdp_image_copy_no_overlap(data, PIXEL_FORMAT_BGRA32, 0, 0, 0, w, h, pSrcData,
1417  SrcFormat, nSrcStep, cmd.left, cmd.top, NULL, 0);
1418  WINPR_ASSERT(rc);
1419 
1420  cmd.data = data;
1421  cmd.length = length;
1422  cmd.codecId = RDPGFX_CODECID_UNCOMPRESSED;
1423 
1424  IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart,
1425  &cmdend);
1426  free(data);
1427  if (error)
1428  {
1429  WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1430  return FALSE;
1431  }
1432  }
1433  return TRUE;
1434 }
1435 
1436 static BOOL stream_surface_bits_supported(const rdpSettings* settings)
1437 {
1438  const UINT32 supported =
1439  freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
1440  return ((supported & SURFCMDS_STREAM_SURFACE_BITS) != 0);
1441 }
1442 
1443 static BOOL set_surface_bits_supported(const rdpSettings* settings)
1444 {
1445  const UINT32 supported =
1446  freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
1447  return ((supported & SURFCMDS_SET_SURFACE_BITS) != 0);
1448 }
1449 
1450 static BOOL is_surface_command_supported(const rdpSettings* settings)
1451 {
1452  if (stream_surface_bits_supported(settings))
1453  {
1454  const UINT32 rfxID = freerdp_settings_get_uint32(settings, FreeRDP_RemoteFxCodecId);
1455  const BOOL supported = freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec);
1456  if (supported && (rfxID != 0))
1457  return TRUE;
1458  }
1459  if (set_surface_bits_supported(settings))
1460  {
1461  const UINT32 nsID = freerdp_settings_get_uint32(settings, FreeRDP_NSCodecId);
1462  const BOOL supported = freerdp_settings_get_bool(settings, FreeRDP_NSCodec);
1463  if (supported && (nsID != 0))
1464  return TRUE;
1465  }
1466  return FALSE;
1467 }
1468 
1474 static BOOL shadow_client_send_surface_bits(rdpShadowClient* client, BYTE* pSrcData,
1475  UINT32 nSrcStep, UINT16 nXSrc, UINT16 nYSrc,
1476  UINT16 nWidth, UINT16 nHeight)
1477 {
1478  BOOL ret = TRUE;
1479  BOOL first = 0;
1480  BOOL last = 0;
1481  wStream* s = NULL;
1482  size_t numMessages = 0;
1483  UINT32 frameId = 0;
1484  rdpUpdate* update = NULL;
1485  rdpContext* context = (rdpContext*)client;
1486  rdpSettings* settings = NULL;
1487  rdpShadowEncoder* encoder = NULL;
1488  SURFACE_BITS_COMMAND cmd = { 0 };
1489 
1490  if (!context || !pSrcData)
1491  return FALSE;
1492 
1493  update = context->update;
1494  settings = context->settings;
1495  encoder = client->encoder;
1496 
1497  if (!update || !settings || !encoder)
1498  return FALSE;
1499 
1500  if (encoder->frameAck)
1501  frameId = shadow_encoder_create_frame_id(encoder);
1502 
1503  // TODO: Check FreeRDP_RemoteFxCodecMode if we should send RFX IMAGE or VIDEO data
1504  const UINT32 nsID = freerdp_settings_get_uint32(settings, FreeRDP_NSCodecId);
1505  const UINT32 rfxID = freerdp_settings_get_uint32(settings, FreeRDP_RemoteFxCodecId);
1506  if (stream_surface_bits_supported(settings) &&
1507  freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec) && (rfxID != 0))
1508  {
1509  RFX_RECT rect = { 0 };
1510 
1511  if (shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX) < 0)
1512  {
1513  WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_REMOTEFX");
1514  return FALSE;
1515  }
1516 
1517  s = encoder->bs;
1518  rect.x = nXSrc;
1519  rect.y = nYSrc;
1520  rect.width = nWidth;
1521  rect.height = nHeight;
1522 
1523  const UINT32 MultifragMaxRequestSize =
1524  freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize);
1525  RFX_MESSAGE_LIST* messages =
1526  rfx_encode_messages(encoder->rfx, &rect, 1, pSrcData,
1527  freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
1528  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight),
1529  nSrcStep, &numMessages, MultifragMaxRequestSize);
1530  if (!messages)
1531  {
1532  WLog_ERR(TAG, "rfx_encode_messages failed");
1533  return FALSE;
1534  }
1535 
1536  cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
1537  WINPR_ASSERT(rfxID <= UINT16_MAX);
1538  cmd.bmp.codecID = (UINT16)rfxID;
1539  cmd.destLeft = 0;
1540  cmd.destTop = 0;
1541  cmd.destRight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1542  cmd.destBottom = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1543  cmd.bmp.bpp = 32;
1544  cmd.bmp.flags = 0;
1545  WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) <= UINT16_MAX);
1546  WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) <= UINT16_MAX);
1547  cmd.bmp.width = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1548  cmd.bmp.height = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1549  cmd.skipCompression = TRUE;
1550 
1551  for (size_t i = 0; i < numMessages; i++)
1552  {
1553  Stream_SetPosition(s, 0);
1554 
1555  const RFX_MESSAGE* msg = rfx_message_list_get(messages, i);
1556  if (!rfx_write_message(encoder->rfx, s, msg))
1557  {
1558  WLog_ERR(TAG, "rfx_write_message failed");
1559  ret = FALSE;
1560  break;
1561  }
1562 
1563  WINPR_ASSERT(Stream_GetPosition(s) <= UINT32_MAX);
1564  cmd.bmp.bitmapDataLength = (UINT32)Stream_GetPosition(s);
1565  cmd.bmp.bitmapData = Stream_Buffer(s);
1566  first = (i == 0) ? TRUE : FALSE;
1567  last = ((i + 1) == numMessages) ? TRUE : FALSE;
1568 
1569  if (!encoder->frameAck)
1570  IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
1571  else
1572  IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last,
1573  frameId);
1574 
1575  if (!ret)
1576  {
1577  WLog_ERR(TAG, "Send surface bits(RemoteFxCodec) failed");
1578  break;
1579  }
1580  }
1581 
1582  rfx_message_list_free(messages);
1583  }
1584  else if (set_surface_bits_supported(settings) &&
1585  freerdp_settings_get_bool(settings, FreeRDP_NSCodec) && (nsID != 0))
1586  {
1587  if (shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC) < 0)
1588  {
1589  WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_NSCODEC");
1590  return FALSE;
1591  }
1592 
1593  s = encoder->bs;
1594  Stream_SetPosition(s, 0);
1595  pSrcData = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
1596  nsc_compose_message(encoder->nsc, s, pSrcData, nWidth, nHeight, nSrcStep);
1597  cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
1598  cmd.bmp.bpp = 32;
1599  WINPR_ASSERT(nsID <= UINT16_MAX);
1600  cmd.bmp.codecID = (UINT16)nsID;
1601  cmd.destLeft = nXSrc;
1602  cmd.destTop = nYSrc;
1603  cmd.destRight = cmd.destLeft + nWidth;
1604  cmd.destBottom = cmd.destTop + nHeight;
1605  cmd.bmp.width = nWidth;
1606  cmd.bmp.height = nHeight;
1607  WINPR_ASSERT(Stream_GetPosition(s) <= UINT32_MAX);
1608  cmd.bmp.bitmapDataLength = (UINT32)Stream_GetPosition(s);
1609  cmd.bmp.bitmapData = Stream_Buffer(s);
1610  first = TRUE;
1611  last = TRUE;
1612 
1613  if (!encoder->frameAck)
1614  IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
1615  else
1616  IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last, frameId);
1617 
1618  if (!ret)
1619  {
1620  WLog_ERR(TAG, "Send surface bits(NSCodec) failed");
1621  }
1622  }
1623 
1624  return ret;
1625 }
1626 
1632 static BOOL shadow_client_send_bitmap_update(rdpShadowClient* client, BYTE* pSrcData,
1633  UINT32 nSrcStep, UINT16 nXSrc, UINT16 nYSrc,
1634  UINT16 nWidth, UINT16 nHeight)
1635 {
1636  BOOL ret = TRUE;
1637  BYTE* data = NULL;
1638  BYTE* buffer = NULL;
1639  UINT32 k = 0;
1640  UINT32 yIdx = 0;
1641  UINT32 xIdx = 0;
1642  UINT32 rows = 0;
1643  UINT32 cols = 0;
1644  UINT32 DstSize = 0;
1645  UINT32 SrcFormat = 0;
1646  BITMAP_DATA* bitmap = NULL;
1647  rdpContext* context = (rdpContext*)client;
1648  UINT32 totalBitmapSize = 0;
1649  UINT32 updateSizeEstimate = 0;
1650  BITMAP_DATA* bitmapData = NULL;
1651  BITMAP_UPDATE bitmapUpdate = { 0 };
1652 
1653  if (!context || !pSrcData)
1654  return FALSE;
1655 
1656  rdpUpdate* update = context->update;
1657  rdpSettings* settings = context->settings;
1658  rdpShadowEncoder* encoder = client->encoder;
1659 
1660  if (!update || !settings || !encoder)
1661  return FALSE;
1662 
1663  const UINT32 maxUpdateSize =
1664  freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize);
1665  if (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) < 32)
1666  {
1667  if (shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED) < 0)
1668  {
1669  WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_INTERLEAVED");
1670  return FALSE;
1671  }
1672  }
1673  else
1674  {
1675  if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR) < 0)
1676  {
1677  WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_PLANAR");
1678  return FALSE;
1679  }
1680  }
1681 
1682  SrcFormat = PIXEL_FORMAT_BGRX32;
1683 
1684  if ((nXSrc % 4) != 0)
1685  {
1686  nWidth += (nXSrc % 4);
1687  nXSrc -= (nXSrc % 4);
1688  }
1689 
1690  if ((nYSrc % 4) != 0)
1691  {
1692  nHeight += (nYSrc % 4);
1693  nYSrc -= (nYSrc % 4);
1694  }
1695 
1696  rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0);
1697  cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0);
1698  k = 0;
1699  totalBitmapSize = 0;
1700  bitmapUpdate.number = rows * cols;
1701 
1702  if (!(bitmapData = (BITMAP_DATA*)calloc(bitmapUpdate.number, sizeof(BITMAP_DATA))))
1703  return FALSE;
1704 
1705  bitmapUpdate.rectangles = bitmapData;
1706 
1707  if ((nWidth % 4) != 0)
1708  {
1709  nWidth += (4 - (nWidth % 4));
1710  }
1711 
1712  if ((nHeight % 4) != 0)
1713  {
1714  nHeight += (4 - (nHeight % 4));
1715  }
1716 
1717  for (yIdx = 0; yIdx < rows; yIdx++)
1718  {
1719  for (xIdx = 0; xIdx < cols; xIdx++)
1720  {
1721  bitmap = &bitmapData[k];
1722  bitmap->width = 64;
1723  bitmap->height = 64;
1724  bitmap->destLeft = nXSrc + (xIdx * 64);
1725  bitmap->destTop = nYSrc + (yIdx * 64);
1726 
1727  if (((INT64)bitmap->destLeft + bitmap->width) > (nXSrc + nWidth))
1728  bitmap->width = (UINT32)(nXSrc + nWidth) - bitmap->destLeft;
1729 
1730  if (((INT64)bitmap->destTop + bitmap->height) > (nYSrc + nHeight))
1731  bitmap->height = (UINT32)(nYSrc + nHeight) - bitmap->destTop;
1732 
1733  bitmap->destRight = bitmap->destLeft + bitmap->width - 1;
1734  bitmap->destBottom = bitmap->destTop + bitmap->height - 1;
1735  bitmap->compressed = TRUE;
1736 
1737  if ((bitmap->width < 4) || (bitmap->height < 4))
1738  continue;
1739 
1740  if (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) < 32)
1741  {
1742  UINT32 bitsPerPixel = freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
1743  UINT32 bytesPerPixel = (bitsPerPixel + 7) / 8;
1744  DstSize = 64 * 64 * 4;
1745  buffer = encoder->grid[k];
1746  interleaved_compress(encoder->interleaved, buffer, &DstSize, bitmap->width,
1747  bitmap->height, pSrcData, SrcFormat, nSrcStep,
1748  bitmap->destLeft, bitmap->destTop, NULL, bitsPerPixel);
1749  bitmap->bitmapDataStream = buffer;
1750  bitmap->bitmapLength = DstSize;
1751  bitmap->bitsPerPixel = bitsPerPixel;
1752  bitmap->cbScanWidth = bitmap->width * bytesPerPixel;
1753  bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel;
1754  }
1755  else
1756  {
1757  UINT32 dstSize = 0;
1758  buffer = encoder->grid[k];
1759  data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)];
1760 
1761  buffer =
1762  freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat, bitmap->width,
1763  bitmap->height, nSrcStep, buffer, &dstSize);
1764  bitmap->bitmapDataStream = buffer;
1765  bitmap->bitmapLength = dstSize;
1766  bitmap->bitsPerPixel = 32;
1767  bitmap->cbScanWidth = bitmap->width * 4;
1768  bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4;
1769  }
1770 
1771  bitmap->cbCompFirstRowSize = 0;
1772  bitmap->cbCompMainBodySize = bitmap->bitmapLength;
1773  totalBitmapSize += bitmap->bitmapLength;
1774  k++;
1775  }
1776  }
1777 
1778  bitmapUpdate.number = k;
1779  updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.number) + 16;
1780 
1781  if (updateSizeEstimate > maxUpdateSize)
1782  {
1783  UINT32 i = 0;
1784  UINT32 j = 0;
1785  UINT32 updateSize = 0;
1786  UINT32 newUpdateSize = 0;
1787  BITMAP_DATA* fragBitmapData = NULL;
1788 
1789  if (k > 0)
1790  fragBitmapData = (BITMAP_DATA*)calloc(k, sizeof(BITMAP_DATA));
1791 
1792  if (!fragBitmapData)
1793  {
1794  WLog_ERR(TAG, "Failed to allocate memory for fragBitmapData");
1795  ret = FALSE;
1796  goto out;
1797  }
1798 
1799  bitmapUpdate.rectangles = fragBitmapData;
1800  i = j = 0;
1801  updateSize = 1024;
1802 
1803  while (i < k)
1804  {
1805  newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16);
1806 
1807  if (newUpdateSize < maxUpdateSize)
1808  {
1809  CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA));
1810  updateSize = newUpdateSize;
1811  }
1812 
1813  if ((newUpdateSize >= maxUpdateSize) || (i + 1) >= k)
1814  {
1815  bitmapUpdate.number = j;
1816  ret = BitmapUpdateProxy(update, context, &bitmapUpdate);
1817 
1818  if (!ret)
1819  break;
1820 
1821  updateSize = 1024;
1822  j = 0;
1823  }
1824  }
1825 
1826  free(fragBitmapData);
1827  }
1828  else
1829  {
1830  ret = BitmapUpdateProxy(update, context, &bitmapUpdate);
1831  }
1832 
1833 out:
1834  free(bitmapData);
1835  return ret;
1836 }
1837 
1843 static BOOL shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
1844 {
1845  BOOL ret = TRUE;
1846  INT64 nXSrc = 0;
1847  INT64 nYSrc = 0;
1848  INT64 nWidth = 0;
1849  INT64 nHeight = 0;
1850  rdpContext* context = (rdpContext*)client;
1851  rdpSettings* settings = NULL;
1852  rdpShadowServer* server = NULL;
1853  rdpShadowSurface* surface = NULL;
1854  REGION16 invalidRegion;
1855  RECTANGLE_16 surfaceRect;
1856  const RECTANGLE_16* extents = NULL;
1857  BYTE* pSrcData = NULL;
1858  UINT32 nSrcStep = 0;
1859  UINT32 SrcFormat = 0;
1860  UINT32 numRects = 0;
1861  const RECTANGLE_16* rects = NULL;
1862 
1863  if (!context || !pStatus)
1864  return FALSE;
1865 
1866  settings = context->settings;
1867  server = client->server;
1868 
1869  if (!settings || !server)
1870  return FALSE;
1871 
1872  surface = client->inLobby ? server->lobby : server->surface;
1873 
1874  if (!surface)
1875  return FALSE;
1876 
1877  EnterCriticalSection(&(client->lock));
1878  region16_init(&invalidRegion);
1879  region16_copy(&invalidRegion, &(client->invalidRegion));
1880  region16_clear(&(client->invalidRegion));
1881  LeaveCriticalSection(&(client->lock));
1882 
1883  EnterCriticalSection(&surface->lock);
1884  rects = region16_rects(&(surface->invalidRegion), &numRects);
1885 
1886  for (UINT32 index = 0; index < numRects; index++)
1887  region16_union_rect(&invalidRegion, &invalidRegion, &rects[index]);
1888 
1889  surfaceRect.left = 0;
1890  surfaceRect.top = 0;
1891  WINPR_ASSERT(surface->width <= UINT16_MAX);
1892  WINPR_ASSERT(surface->height <= UINT16_MAX);
1893  surfaceRect.right = (UINT16)surface->width;
1894  surfaceRect.bottom = (UINT16)surface->height;
1895  region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect);
1896 
1897  if (server->shareSubRect)
1898  {
1899  region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect));
1900  }
1901 
1902  if (region16_is_empty(&invalidRegion))
1903  {
1904  /* No image region need to be updated. Success */
1905  goto out;
1906  }
1907 
1908  extents = region16_extents(&invalidRegion);
1909  nXSrc = extents->left;
1910  nYSrc = extents->top;
1911  nWidth = extents->right - extents->left;
1912  nHeight = extents->bottom - extents->top;
1913  pSrcData = surface->data;
1914  nSrcStep = surface->scanline;
1915  SrcFormat = surface->format;
1916 
1917  /* Move to new pSrcData / nXSrc / nYSrc according to sub rect */
1918  if (server->shareSubRect)
1919  {
1920  INT32 subX = 0;
1921  INT32 subY = 0;
1922  subX = server->subRect.left;
1923  subY = server->subRect.top;
1924  nXSrc -= subX;
1925  nYSrc -= subY;
1926  WINPR_ASSERT(nXSrc >= 0);
1927  WINPR_ASSERT(nXSrc <= UINT16_MAX);
1928  WINPR_ASSERT(nYSrc >= 0);
1929  WINPR_ASSERT(nYSrc <= UINT16_MAX);
1930  pSrcData = &pSrcData[((UINT16)subY * nSrcStep) + ((UINT16)subX * 4U)];
1931  }
1932 
1933  // WLog_INFO(TAG, "shadow_client_send_surface_update: x: %" PRId64 " y: %" PRId64 " width: %"
1934  // PRId64 " height: %" PRId64 " right: %" PRId64 " bottom: %" PRId64, nXSrc, nYSrc, nWidth,
1935  // nHeight, nXSrc + nWidth, nYSrc + nHeight);
1936 
1937  if (freerdp_settings_get_bool(settings, FreeRDP_SupportGraphicsPipeline))
1938  {
1939  if (pStatus->gfxOpened && client->areGfxCapsReady)
1940  {
1941  /* GFX/h264 always full screen encoded */
1942  nWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1943  nHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1944 
1945  /* Create primary surface if have not */
1946  if (!pStatus->gfxSurfaceCreated)
1947  {
1948  /* Only init surface when we have h264 supported */
1949  if (!(ret = shadow_client_rdpgfx_reset_graphic(client)))
1950  goto out;
1951 
1952  if (!(ret = shadow_client_rdpgfx_new_surface(client)))
1953  goto out;
1954 
1955  pStatus->gfxSurfaceCreated = TRUE;
1956  }
1957 
1958  WINPR_ASSERT(nWidth >= 0);
1959  WINPR_ASSERT(nWidth <= UINT16_MAX);
1960  WINPR_ASSERT(nHeight >= 0);
1961  WINPR_ASSERT(nHeight <= UINT16_MAX);
1962  ret = shadow_client_send_surface_gfx(client, pSrcData, nSrcStep, SrcFormat, 0, 0,
1963  (UINT16)nWidth, (UINT16)nHeight);
1964  }
1965  else
1966  {
1967  ret = TRUE;
1968  }
1969  }
1970  else if (is_surface_command_supported(settings))
1971  {
1972  WINPR_ASSERT(nXSrc >= 0);
1973  WINPR_ASSERT(nXSrc <= UINT16_MAX);
1974  WINPR_ASSERT(nYSrc >= 0);
1975  WINPR_ASSERT(nYSrc <= UINT16_MAX);
1976  WINPR_ASSERT(nWidth >= 0);
1977  WINPR_ASSERT(nWidth <= UINT16_MAX);
1978  WINPR_ASSERT(nHeight >= 0);
1979  WINPR_ASSERT(nHeight <= UINT16_MAX);
1980  ret = shadow_client_send_surface_bits(client, pSrcData, nSrcStep, (UINT16)nXSrc,
1981  (UINT16)nYSrc, (UINT16)nWidth, (UINT16)nHeight);
1982  }
1983  else
1984  {
1985  WINPR_ASSERT(nXSrc >= 0);
1986  WINPR_ASSERT(nXSrc <= UINT16_MAX);
1987  WINPR_ASSERT(nYSrc >= 0);
1988  WINPR_ASSERT(nYSrc <= UINT16_MAX);
1989  WINPR_ASSERT(nWidth >= 0);
1990  WINPR_ASSERT(nWidth <= UINT16_MAX);
1991  WINPR_ASSERT(nHeight >= 0);
1992  WINPR_ASSERT(nHeight <= UINT16_MAX);
1993  ret = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, (UINT16)nXSrc,
1994  (UINT16)nYSrc, (UINT16)nWidth, (UINT16)nHeight);
1995  }
1996 
1997 out:
1998  LeaveCriticalSection(&surface->lock);
1999  region16_uninit(&invalidRegion);
2000  return ret;
2001 }
2002 
2010 static BOOL shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
2011 {
2012  rdpContext* context = (rdpContext*)client;
2013  rdpSettings* settings = NULL;
2014  freerdp_peer* peer = NULL;
2015 
2016  if (!context || !pStatus)
2017  return FALSE;
2018 
2019  peer = context->peer;
2020  settings = context->settings;
2021 
2022  if (!peer || !settings)
2023  return FALSE;
2024 
2030  client->activated = FALSE;
2031 
2032  /* Close Gfx surfaces */
2033  if (pStatus->gfxSurfaceCreated)
2034  {
2035  if (!shadow_client_rdpgfx_release_surface(client))
2036  return FALSE;
2037 
2038  pStatus->gfxSurfaceCreated = FALSE;
2039  }
2040 
2041  /* Send Resize */
2042  if (!shadow_send_desktop_resize(client))
2043  return FALSE;
2044  shadow_reset_desktop_resize(client);
2045 
2046  /* Clear my invalidRegion. shadow_client_activate refreshes fullscreen */
2047  EnterCriticalSection(&(client->lock));
2048  region16_clear(&(client->invalidRegion));
2049  LeaveCriticalSection(&(client->lock));
2050  return TRUE;
2051 }
2052 
2059 static BOOL shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
2060 {
2061  UINT32 numRects = 0;
2062  const RECTANGLE_16* rects = NULL;
2063  rects = region16_rects(region, &numRects);
2064  shadow_client_mark_invalid(client, numRects, rects);
2065  return TRUE;
2066 }
2067 
2074 static INLINE BOOL shadow_client_no_surface_update(rdpShadowClient* client,
2075  SHADOW_GFX_STATUS* pStatus)
2076 {
2077  rdpShadowServer* server = NULL;
2078  rdpShadowSurface* surface = NULL;
2079  WINPR_UNUSED(pStatus);
2080  WINPR_ASSERT(client);
2081  server = client->server;
2082  WINPR_ASSERT(server);
2083  surface = client->inLobby ? server->lobby : server->surface;
2084  EnterCriticalSection(&surface->lock);
2085  const BOOL rc = shadow_client_surface_update(client, &(surface->invalidRegion));
2086  LeaveCriticalSection(&surface->lock);
2087  return rc;
2088 }
2089 
2090 static int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message)
2091 {
2092  rdpContext* context = (rdpContext*)client;
2093  rdpUpdate* update = NULL;
2094 
2095  WINPR_ASSERT(message);
2096  WINPR_ASSERT(context);
2097  update = context->update;
2098  WINPR_ASSERT(update);
2099 
2100  /* FIXME: the pointer updates appear to be broken when used with bulk compression and mstsc */
2101 
2102  switch (message->id)
2103  {
2104  case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
2105  {
2106  POINTER_POSITION_UPDATE pointerPosition;
2108  (const SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*)message->wParam;
2109  pointerPosition.xPos = msg->xPos;
2110  pointerPosition.yPos = msg->yPos;
2111 
2112  WINPR_ASSERT(client->server);
2113  if (client->server->shareSubRect)
2114  {
2115  pointerPosition.xPos -= client->server->subRect.left;
2116  pointerPosition.yPos -= client->server->subRect.top;
2117  }
2118 
2119  if (client->activated)
2120  {
2121  if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
2122  {
2123  WINPR_ASSERT(update->pointer);
2124  IFCALL(update->pointer->PointerPosition, context, &pointerPosition);
2125  client->pointerX = msg->xPos;
2126  client->pointerY = msg->yPos;
2127  }
2128  }
2129 
2130  break;
2131  }
2132 
2133  case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
2134  {
2135  POINTER_NEW_UPDATE pointerNew = { 0 };
2136  POINTER_COLOR_UPDATE* pointerColor = { 0 };
2137  POINTER_CACHED_UPDATE pointerCached = { 0 };
2139  (const SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)message->wParam;
2140 
2141  WINPR_ASSERT(msg);
2142  pointerNew.xorBpp = 24;
2143  pointerColor = &(pointerNew.colorPtrAttr);
2144  pointerColor->cacheIndex = 0;
2145  pointerColor->hotSpotX = WINPR_ASSERTING_INT_CAST(UINT16, msg->xHot);
2146  pointerColor->hotSpotY = WINPR_ASSERTING_INT_CAST(UINT16, msg->yHot);
2147  pointerColor->width = WINPR_ASSERTING_INT_CAST(UINT16, msg->width);
2148  pointerColor->height = WINPR_ASSERTING_INT_CAST(UINT16, msg->height);
2149  pointerColor->lengthAndMask = WINPR_ASSERTING_INT_CAST(UINT16, msg->lengthAndMask);
2150  pointerColor->lengthXorMask = WINPR_ASSERTING_INT_CAST(UINT16, msg->lengthXorMask);
2151  pointerColor->xorMaskData = msg->xorMaskData;
2152  pointerColor->andMaskData = msg->andMaskData;
2153  pointerCached.cacheIndex = pointerColor->cacheIndex;
2154 
2155  if (client->activated)
2156  {
2157  IFCALL(update->pointer->PointerNew, context, &pointerNew);
2158  IFCALL(update->pointer->PointerCached, context, &pointerCached);
2159  }
2160 
2161  break;
2162  }
2163 
2164  case SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID:
2165  {
2167  (const SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES*)message->wParam;
2168 
2169  WINPR_ASSERT(msg);
2170 
2171  if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
2172  {
2173  client->rdpsnd->src_format = msg->audio_format;
2174  IFCALL(client->rdpsnd->SendSamples, client->rdpsnd, msg->buf, msg->nFrames,
2175  msg->wTimestamp);
2176  }
2177 
2178  break;
2179  }
2180 
2181  case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
2182  {
2183  const SHADOW_MSG_OUT_AUDIO_OUT_VOLUME* msg =
2184  (const SHADOW_MSG_OUT_AUDIO_OUT_VOLUME*)message->wParam;
2185 
2186  if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
2187  {
2188  IFCALL(client->rdpsnd->SetVolume, client->rdpsnd, msg->left, msg->right);
2189  }
2190 
2191  break;
2192  }
2193 
2194  default:
2195  WLog_ERR(TAG, "Unknown message id: %" PRIu32 "", message->id);
2196  break;
2197  }
2198 
2199  shadow_client_free_queued_message(message);
2200  return 1;
2201 }
2202 
2203 static DWORD WINAPI shadow_client_thread(LPVOID arg)
2204 {
2205  rdpShadowClient* client = (rdpShadowClient*)arg;
2206  BOOL rc = FALSE;
2207  DWORD status = 0;
2208  wMessage message = { 0 };
2209  wMessage pointerPositionMsg = { 0 };
2210  wMessage pointerAlphaMsg = { 0 };
2211  wMessage audioVolumeMsg = { 0 };
2212  HANDLE ChannelEvent = 0;
2213  void* UpdateSubscriber = NULL;
2214  HANDLE UpdateEvent = 0;
2215  freerdp_peer* peer = NULL;
2216  rdpContext* context = NULL;
2217  rdpSettings* settings = NULL;
2218  rdpShadowServer* server = NULL;
2219  rdpShadowSubsystem* subsystem = NULL;
2220  wMessageQueue* MsgQueue = NULL;
2221  /* This should only be visited in client thread */
2222  SHADOW_GFX_STATUS gfxstatus = { 0 };
2223  rdpUpdate* update = NULL;
2224 
2225  WINPR_ASSERT(client);
2226 
2227  MsgQueue = client->MsgQueue;
2228  WINPR_ASSERT(MsgQueue);
2229 
2230  server = client->server;
2231  WINPR_ASSERT(server);
2232  subsystem = server->subsystem;
2233  context = (rdpContext*)client;
2234  peer = context->peer;
2235  WINPR_ASSERT(peer);
2236  WINPR_ASSERT(peer->context);
2237 
2238  settings = peer->context->settings;
2239  WINPR_ASSERT(settings);
2240 
2241  peer->Capabilities = shadow_client_capabilities;
2242  peer->PostConnect = shadow_client_post_connect;
2243  peer->Activate = shadow_client_activate;
2244  peer->Logon = shadow_client_logon;
2245  shadow_input_register_callbacks(peer->context->input);
2246 
2247  rc = peer->Initialize(peer);
2248  if (!rc)
2249  goto out;
2250 
2251  update = peer->context->update;
2252  WINPR_ASSERT(update);
2253 
2254  update->RefreshRect = shadow_client_refresh_rect;
2255  update->SuppressOutput = shadow_client_suppress_output;
2256  update->SurfaceFrameAcknowledge = shadow_client_surface_frame_acknowledge;
2257 
2258  if ((!client->vcm) || (!subsystem->updateEvent))
2259  goto out;
2260 
2261  UpdateSubscriber = shadow_multiclient_get_subscriber(subsystem->updateEvent);
2262 
2263  if (!UpdateSubscriber)
2264  goto out;
2265 
2266  UpdateEvent = shadow_multiclient_getevent(UpdateSubscriber);
2267  WINPR_ASSERT(UpdateEvent);
2268 
2269  ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm);
2270  WINPR_ASSERT(ChannelEvent);
2271 
2272  rc = freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, TRUE);
2273  WINPR_ASSERT(rc);
2274  rc = freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel, TRUE);
2275  WINPR_ASSERT(rc);
2276  rc = freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent, TRUE);
2277  WINPR_ASSERT(rc);
2278  rc = freerdp_settings_set_bool(settings, FreeRDP_SupportMonitorLayoutPdu, TRUE);
2279  WINPR_ASSERT(rc);
2280  while (1)
2281  {
2282  HANDLE events[MAXIMUM_WAIT_OBJECTS] = { 0 };
2283  DWORD nCount = 0;
2284  events[nCount++] = UpdateEvent;
2285  {
2286  DWORD tmp = peer->GetEventHandles(peer, &events[nCount], 64 - nCount);
2287 
2288  if (tmp == 0)
2289  {
2290  WLog_ERR(TAG, "Failed to get FreeRDP transport event handles");
2291  goto fail;
2292  }
2293 
2294  nCount += tmp;
2295  }
2296  events[nCount++] = ChannelEvent;
2297  events[nCount++] = MessageQueue_Event(MsgQueue);
2298 
2299 #if defined(CHANNEL_RDPGFX_SERVER)
2300  HANDLE gfxevent = rdpgfx_server_get_event_handle(client->rdpgfx);
2301 
2302  if (gfxevent)
2303  events[nCount++] = gfxevent;
2304 #endif
2305 
2306  status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
2307 
2308  if (status == WAIT_FAILED)
2309  goto fail;
2310 
2311  if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
2312  {
2313  /* The UpdateEvent means to start sending current frame. It is
2314  * triggered from subsystem implementation and it should ensure
2315  * that the screen and primary surface meta data (width, height,
2316  * scanline, invalid region, etc) is not changed until it is reset
2317  * (at shadow_multiclient_consume). As best practice, subsystem
2318  * implementation should invoke shadow_subsystem_frame_update which
2319  * triggers the event and then wait for completion */
2320  if (client->activated && !client->suppressOutput)
2321  {
2322  /* Send screen update or resize to this client */
2323 
2324  /* Check resize */
2325  if (shadow_client_recalc_desktop_size(client))
2326  {
2327  /* Screen size changed, do resize */
2328  if (!shadow_client_send_resize(client, &gfxstatus))
2329  {
2330  WLog_ERR(TAG, "Failed to send resize message");
2331  break;
2332  }
2333  }
2334  else
2335  {
2336  /* Send frame */
2337  if (!shadow_client_send_surface_update(client, &gfxstatus))
2338  {
2339  WLog_ERR(TAG, "Failed to send surface update");
2340  break;
2341  }
2342  }
2343  }
2344  else
2345  {
2346  /* Our client don't receive graphic updates. Just save the invalid region */
2347  if (!shadow_client_no_surface_update(client, &gfxstatus))
2348  {
2349  WLog_ERR(TAG, "Failed to handle surface update");
2350  break;
2351  }
2352  }
2353 
2354  /*
2355  * The return value of shadow_multiclient_consume is whether or not
2356  * the subscriber really consumes the event. It's not cared currently.
2357  */
2358  (void)shadow_multiclient_consume(UpdateSubscriber);
2359  }
2360 
2361  WINPR_ASSERT(peer->CheckFileDescriptor);
2362  if (!peer->CheckFileDescriptor(peer))
2363  {
2364  WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
2365  goto fail;
2366  }
2367 
2368  if (client->activated &&
2369  WTSVirtualChannelManagerIsChannelJoined(client->vcm, DRDYNVC_SVC_CHANNEL_NAME))
2370  {
2371  switch (WTSVirtualChannelManagerGetDrdynvcState(client->vcm))
2372  {
2373  /* Dynamic channel status may have been changed after processing */
2374  case DRDYNVC_STATE_NONE:
2375 
2376  /* Call this routine to Initialize drdynvc channel */
2377  if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
2378  {
2379  WLog_ERR(TAG, "Failed to initialize drdynvc channel");
2380  goto fail;
2381  }
2382 
2383  break;
2384 
2385  case DRDYNVC_STATE_READY:
2386 #if defined(CHANNEL_AUDIN_SERVER)
2387  if (client->audin && !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
2388  {
2389  if (!IFCALLRESULT(FALSE, client->audin->Open, client->audin))
2390  {
2391  WLog_ERR(TAG, "Failed to initialize audin channel");
2392  goto fail;
2393  }
2394  }
2395 #endif
2396 
2397  /* Init RDPGFX dynamic channel */
2398  if (freerdp_settings_get_bool(settings, FreeRDP_SupportGraphicsPipeline) &&
2399  client->rdpgfx && !gfxstatus.gfxOpened)
2400  {
2401  client->rdpgfx->FrameAcknowledge = shadow_client_rdpgfx_frame_acknowledge;
2402  client->rdpgfx->CapsAdvertise = shadow_client_rdpgfx_caps_advertise;
2403 
2404  if (!client->rdpgfx->Open(client->rdpgfx))
2405  {
2406  WLog_WARN(TAG, "Failed to open GraphicsPipeline");
2407  if (!freerdp_settings_set_bool(settings,
2408  FreeRDP_SupportGraphicsPipeline, FALSE))
2409  goto fail;
2410  }
2411  else
2412  {
2413  gfxstatus.gfxOpened = TRUE;
2414  WLog_INFO(TAG, "Gfx Pipeline Opened");
2415  }
2416  }
2417 
2418  break;
2419 
2420  default:
2421  break;
2422  }
2423  }
2424 
2425  if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
2426  {
2427  if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
2428  {
2429  WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure");
2430  goto fail;
2431  }
2432  }
2433 
2434 #if defined(CHANNEL_RDPGFX_SERVER)
2435  if (gfxevent)
2436  {
2437  if (WaitForSingleObject(gfxevent, 0) == WAIT_OBJECT_0)
2438  {
2439  rdpgfx_server_handle_messages(client->rdpgfx);
2440  }
2441  }
2442 #endif
2443 
2444  if (WaitForSingleObject(MessageQueue_Event(MsgQueue), 0) == WAIT_OBJECT_0)
2445  {
2446  /* Drain messages. Pointer update could be accumulated. */
2447  pointerPositionMsg.id = 0;
2448  pointerPositionMsg.Free = NULL;
2449  pointerAlphaMsg.id = 0;
2450  pointerAlphaMsg.Free = NULL;
2451  audioVolumeMsg.id = 0;
2452  audioVolumeMsg.Free = NULL;
2453 
2454  while (MessageQueue_Peek(MsgQueue, &message, TRUE))
2455  {
2456  if (message.id == WMQ_QUIT)
2457  {
2458  break;
2459  }
2460 
2461  switch (message.id)
2462  {
2463  case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
2464  /* Abandon previous message */
2465  shadow_client_free_queued_message(&pointerPositionMsg);
2466  pointerPositionMsg = message;
2467  break;
2468 
2469  case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
2470  /* Abandon previous message */
2471  shadow_client_free_queued_message(&pointerAlphaMsg);
2472  pointerAlphaMsg = message;
2473  break;
2474 
2475  case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
2476  /* Abandon previous message */
2477  shadow_client_free_queued_message(&audioVolumeMsg);
2478  audioVolumeMsg = message;
2479  break;
2480 
2481  default:
2482  shadow_client_subsystem_process_message(client, &message);
2483  break;
2484  }
2485  }
2486 
2487  if (message.id == WMQ_QUIT)
2488  {
2489  /* Release stored message */
2490  shadow_client_free_queued_message(&pointerPositionMsg);
2491  shadow_client_free_queued_message(&pointerAlphaMsg);
2492  shadow_client_free_queued_message(&audioVolumeMsg);
2493  goto fail;
2494  }
2495  else
2496  {
2497  /* Process accumulated messages if needed */
2498  if (pointerPositionMsg.id)
2499  {
2500  shadow_client_subsystem_process_message(client, &pointerPositionMsg);
2501  }
2502 
2503  if (pointerAlphaMsg.id)
2504  {
2505  shadow_client_subsystem_process_message(client, &pointerAlphaMsg);
2506  }
2507 
2508  if (audioVolumeMsg.id)
2509  {
2510  shadow_client_subsystem_process_message(client, &audioVolumeMsg);
2511  }
2512  }
2513  }
2514  }
2515 
2516 fail:
2517 
2518  /* Free channels early because we establish channels in post connect */
2519 #if defined(CHANNEL_AUDIN_SERVER)
2520  if (client->audin && !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
2521  {
2522  if (!IFCALLRESULT(FALSE, client->audin->Close, client->audin))
2523  {
2524  WLog_WARN(TAG, "AUDIN shutdown failure!");
2525  }
2526  }
2527 #endif
2528 
2529  if (gfxstatus.gfxOpened)
2530  {
2531  if (gfxstatus.gfxSurfaceCreated)
2532  {
2533  if (!shadow_client_rdpgfx_release_surface(client))
2534  WLog_WARN(TAG, "GFX release surface failure!");
2535  }
2536 
2537  WINPR_ASSERT(client->rdpgfx);
2538  WINPR_ASSERT(client->rdpgfx->Close);
2539  rc = client->rdpgfx->Close(client->rdpgfx);
2540  WINPR_ASSERT(rc);
2541  }
2542 
2543  shadow_client_channels_free(client);
2544 
2545  if (UpdateSubscriber)
2546  {
2547  shadow_multiclient_release_subscriber(UpdateSubscriber);
2548  UpdateSubscriber = NULL;
2549  }
2550 
2551  if (peer->connected && subsystem->ClientDisconnect)
2552  {
2553  subsystem->ClientDisconnect(subsystem, client);
2554  }
2555 
2556 out:
2557  WINPR_ASSERT(peer->Disconnect);
2558  peer->Disconnect(peer);
2559  freerdp_peer_context_free(peer);
2560  freerdp_peer_free(peer);
2561  ExitThread(0);
2562  return 0;
2563 }
2564 
2565 BOOL shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
2566 {
2567  rdpShadowClient* client = NULL;
2568  rdpShadowServer* server = NULL;
2569 
2570  if (!listener || !peer)
2571  return FALSE;
2572 
2573  server = (rdpShadowServer*)listener->info;
2574  WINPR_ASSERT(server);
2575 
2576  peer->ContextExtra = (void*)server;
2577  peer->ContextSize = sizeof(rdpShadowClient);
2578  peer->ContextNew = shadow_client_context_new;
2579  peer->ContextFree = shadow_client_context_free;
2580 
2581  if (!freerdp_peer_context_new_ex(peer, server->settings))
2582  return FALSE;
2583 
2584  client = (rdpShadowClient*)peer->context;
2585  WINPR_ASSERT(client);
2586 
2587  if (!(client->thread = CreateThread(NULL, 0, shadow_client_thread, client, 0, NULL)))
2588  {
2589  freerdp_peer_context_free(peer);
2590  return FALSE;
2591  }
2592  else
2593  {
2594  /* Close the thread handle to make it detached. */
2595  (void)CloseHandle(client->thread);
2596  client->thread = NULL;
2597  }
2598 
2599  return TRUE;
2600 }
2601 
2602 static void shadow_msg_out_addref(wMessage* message)
2603 {
2604  SHADOW_MSG_OUT* msg = NULL;
2605 
2606  WINPR_ASSERT(message);
2607  msg = (SHADOW_MSG_OUT*)message->wParam;
2608  WINPR_ASSERT(msg);
2609 
2610  InterlockedIncrement(&(msg->refCount));
2611 }
2612 
2613 static void shadow_msg_out_release(wMessage* message)
2614 {
2615  SHADOW_MSG_OUT* msg = NULL;
2616 
2617  WINPR_ASSERT(message);
2618  msg = (SHADOW_MSG_OUT*)message->wParam;
2619  WINPR_ASSERT(msg);
2620 
2621  if (InterlockedDecrement(&(msg->refCount)) <= 0)
2622  {
2623  IFCALL(msg->Free, message->id, msg);
2624  }
2625 }
2626 
2627 static BOOL shadow_client_dispatch_msg(rdpShadowClient* client, wMessage* message)
2628 {
2629  if (!client || !message)
2630  return FALSE;
2631 
2632  /* Add reference when it is posted */
2633  shadow_msg_out_addref(message);
2634 
2635  WINPR_ASSERT(client->MsgQueue);
2636  if (MessageQueue_Dispatch(client->MsgQueue, message))
2637  return TRUE;
2638  else
2639  {
2640  /* Release the reference since post failed */
2641  shadow_msg_out_release(message);
2642  return FALSE;
2643  }
2644 }
2645 
2646 BOOL shadow_client_post_msg(rdpShadowClient* client, void* context, UINT32 type,
2647  SHADOW_MSG_OUT* msg, void* lParam)
2648 {
2649  wMessage message = { 0 };
2650  message.context = context;
2651  message.id = type;
2652  message.wParam = (void*)msg;
2653  message.lParam = lParam;
2654  message.Free = shadow_msg_out_release;
2655  return shadow_client_dispatch_msg(client, &message);
2656 }
2657 
2658 int shadow_client_boardcast_msg(rdpShadowServer* server, void* context, UINT32 type,
2659  SHADOW_MSG_OUT* msg, void* lParam)
2660 {
2661  wMessage message = { 0 };
2662  rdpShadowClient* client = NULL;
2663  int count = 0;
2664 
2665  WINPR_ASSERT(server);
2666  WINPR_ASSERT(msg);
2667 
2668  message.context = context;
2669  message.id = type;
2670  message.wParam = (void*)msg;
2671  message.lParam = lParam;
2672  message.Free = shadow_msg_out_release;
2673  /* First add reference as we reference it in this function.
2674  * Therefore it would not be free'ed during post. */
2675  shadow_msg_out_addref(&message);
2676 
2677  WINPR_ASSERT(server->clients);
2678  ArrayList_Lock(server->clients);
2679 
2680  for (size_t index = 0; index < ArrayList_Count(server->clients); index++)
2681  {
2682  client = (rdpShadowClient*)ArrayList_GetItem(server->clients, index);
2683 
2684  if (shadow_client_dispatch_msg(client, &message))
2685  {
2686  count++;
2687  }
2688  }
2689 
2690  ArrayList_Unlock(server->clients);
2691  /* Release the reference for this function */
2692  shadow_msg_out_release(&message);
2693  return count;
2694 }
2695 
2696 int shadow_client_boardcast_quit(rdpShadowServer* server, int nExitCode)
2697 {
2698  wMessageQueue* queue = NULL;
2699  int count = 0;
2700 
2701  WINPR_ASSERT(server);
2702  WINPR_ASSERT(server->clients);
2703 
2704  ArrayList_Lock(server->clients);
2705 
2706  for (size_t index = 0; index < ArrayList_Count(server->clients); index++)
2707  {
2708  queue = ((rdpShadowClient*)ArrayList_GetItem(server->clients, index))->MsgQueue;
2709 
2710  if (MessageQueue_PostQuit(queue, nExitCode))
2711  {
2712  count++;
2713  }
2714  }
2715 
2716  ArrayList_Unlock(server->clients);
2717  return count;
2718 }
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_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
This struct contains function pointer to initialize/free objects.
Definition: collections.h:57