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