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