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