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