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