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