1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 *
4 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
5 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
6 * Copyright 2017 Thincast Technologies GmbH
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <winpr/crt.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
35 #include "shadow.h"
36
37 #define TAG CLIENT_TAG("shadow")
38
39 struct _SHADOW_GFX_STATUS
40 {
41 BOOL gfxOpened;
42 BOOL gfxSurfaceCreated;
43 };
44 typedef struct _SHADOW_GFX_STATUS SHADOW_GFX_STATUS;
45
shadow_client_rdpgfx_new_surface(rdpShadowClient * client)46 static INLINE BOOL shadow_client_rdpgfx_new_surface(rdpShadowClient* client)
47 {
48 UINT error = CHANNEL_RC_OK;
49 RDPGFX_CREATE_SURFACE_PDU createSurface;
50 RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU surfaceToOutput;
51 RdpgfxServerContext* context = client->rdpgfx;
52 rdpSettings* settings = ((rdpContext*)client)->settings;
53 createSurface.width = settings->DesktopWidth;
54 createSurface.height = settings->DesktopHeight;
55 createSurface.pixelFormat = GFX_PIXEL_FORMAT_XRGB_8888;
56 createSurface.surfaceId = 0;
57 surfaceToOutput.outputOriginX = 0;
58 surfaceToOutput.outputOriginY = 0;
59 surfaceToOutput.surfaceId = 0;
60 surfaceToOutput.reserved = 0;
61 IFCALLRET(context->CreateSurface, error, context, &createSurface);
62
63 if (error)
64 {
65 WLog_ERR(TAG, "CreateSurface failed with error %" PRIu32 "", error);
66 return FALSE;
67 }
68
69 IFCALLRET(context->MapSurfaceToOutput, error, context, &surfaceToOutput);
70
71 if (error)
72 {
73 WLog_ERR(TAG, "MapSurfaceToOutput failed with error %" PRIu32 "", error);
74 return FALSE;
75 }
76
77 return TRUE;
78 }
79
shadow_client_rdpgfx_release_surface(rdpShadowClient * client)80 static INLINE BOOL shadow_client_rdpgfx_release_surface(rdpShadowClient* client)
81 {
82 UINT error = CHANNEL_RC_OK;
83 RDPGFX_DELETE_SURFACE_PDU pdu;
84 RdpgfxServerContext* context = client->rdpgfx;
85 pdu.surfaceId = 0;
86 IFCALLRET(context->DeleteSurface, error, context, &pdu);
87
88 if (error)
89 {
90 WLog_ERR(TAG, "DeleteSurface failed with error %" PRIu32 "", error);
91 return FALSE;
92 }
93
94 return TRUE;
95 }
96
shadow_client_rdpgfx_reset_graphic(rdpShadowClient * client)97 static INLINE BOOL shadow_client_rdpgfx_reset_graphic(rdpShadowClient* client)
98 {
99 UINT error = CHANNEL_RC_OK;
100 RDPGFX_RESET_GRAPHICS_PDU pdu;
101 RdpgfxServerContext* context = client->rdpgfx;
102 rdpSettings* settings = ((rdpContext*)client)->settings;
103 pdu.width = settings->DesktopWidth;
104 pdu.height = settings->DesktopHeight;
105 pdu.monitorCount = client->subsystem->numMonitors;
106 pdu.monitorDefArray = client->subsystem->monitors;
107 IFCALLRET(context->ResetGraphics, error, context, &pdu);
108
109 if (error)
110 {
111 WLog_ERR(TAG, "ResetGraphics failed with error %" PRIu32 "", error);
112 return FALSE;
113 }
114
115 return TRUE;
116 }
117
shadow_client_free_queued_message(void * obj)118 static INLINE void shadow_client_free_queued_message(void* obj)
119 {
120 wMessage* message = (wMessage*)obj;
121
122 if (message->Free)
123 {
124 message->Free(message);
125 message->Free = NULL;
126 }
127 }
128
shadow_client_context_new(freerdp_peer * peer,rdpShadowClient * client)129 static BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
130 {
131 const char bind_address[] = "bind-address,";
132 rdpSettings* settings;
133 rdpShadowServer* server;
134 const wObject cb = { NULL, NULL, NULL, shadow_client_free_queued_message, NULL };
135 server = (rdpShadowServer*)peer->ContextExtra;
136 client->server = server;
137 client->subsystem = server->subsystem;
138 settings = peer->settings;
139 settings->ColorDepth = 32;
140 settings->NSCodec = TRUE;
141 settings->RemoteFxCodec = TRUE;
142 settings->BitmapCacheV3Enabled = TRUE;
143 settings->FrameMarkerCommandEnabled = TRUE;
144 settings->SurfaceFrameMarkerEnabled = TRUE;
145 settings->SupportGraphicsPipeline = TRUE;
146 settings->GfxH264 = FALSE;
147 settings->DrawAllowSkipAlpha = TRUE;
148 settings->DrawAllowColorSubsampling = TRUE;
149 settings->DrawAllowDynamicColorFidelity = TRUE;
150 settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6;
151
152 if (!(settings->CertificateFile = _strdup(server->CertificateFile)))
153 goto fail_cert_file;
154
155 if (!(settings->PrivateKeyFile = _strdup(server->PrivateKeyFile)))
156 goto fail_privkey_file;
157
158 if (!(settings->RdpKeyFile = _strdup(settings->PrivateKeyFile)))
159 goto fail_rdpkey_file;
160
161 if (server->ipcSocket && (strncmp(bind_address, server->ipcSocket,
162 strnlen(bind_address, sizeof(bind_address))) != 0))
163 {
164 settings->LyncRdpMode = TRUE;
165 settings->CompressionEnabled = FALSE;
166 }
167
168 client->inLobby = TRUE;
169 client->mayView = server->mayView;
170 client->mayInteract = server->mayInteract;
171
172 if (!InitializeCriticalSectionAndSpinCount(&(client->lock), 4000))
173 goto fail_client_lock;
174
175 region16_init(&(client->invalidRegion));
176 client->vcm = WTSOpenServerA((LPSTR)peer->context);
177
178 if (!client->vcm || client->vcm == INVALID_HANDLE_VALUE)
179 goto fail_open_server;
180
181 if (!(client->MsgQueue = MessageQueue_New(&cb)))
182 goto fail_message_queue;
183
184 if (!(client->encoder = shadow_encoder_new(client)))
185 goto fail_encoder_new;
186
187 if (ArrayList_Add(server->clients, (void*)client) >= 0)
188 return TRUE;
189
190 shadow_encoder_free(client->encoder);
191 client->encoder = NULL;
192 fail_encoder_new:
193 MessageQueue_Free(client->MsgQueue);
194 client->MsgQueue = NULL;
195 fail_message_queue:
196 WTSCloseServer((HANDLE)client->vcm);
197 client->vcm = NULL;
198 fail_open_server:
199 DeleteCriticalSection(&(client->lock));
200 fail_client_lock:
201 free(settings->RdpKeyFile);
202 settings->RdpKeyFile = NULL;
203 fail_rdpkey_file:
204 free(settings->PrivateKeyFile);
205 settings->PrivateKeyFile = NULL;
206 fail_privkey_file:
207 free(settings->CertificateFile);
208 settings->CertificateFile = NULL;
209 fail_cert_file:
210 return FALSE;
211 }
212
shadow_client_context_free(freerdp_peer * peer,rdpShadowClient * client)213 static void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
214 {
215 rdpShadowServer* server = client->server;
216 WINPR_UNUSED(peer);
217 ArrayList_Remove(server->clients, (void*)client);
218
219 if (client->encoder)
220 {
221 shadow_encoder_free(client->encoder);
222 client->encoder = NULL;
223 }
224
225 /* Clear queued messages and free resource */
226 MessageQueue_Clear(client->MsgQueue);
227 MessageQueue_Free(client->MsgQueue);
228 WTSCloseServer((HANDLE)client->vcm);
229 client->vcm = NULL;
230 region16_uninit(&(client->invalidRegion));
231 DeleteCriticalSection(&(client->lock));
232 }
233
shadow_client_mark_invalid(rdpShadowClient * client,int numRects,const RECTANGLE_16 * rects)234 static INLINE void shadow_client_mark_invalid(rdpShadowClient* client, int numRects,
235 const RECTANGLE_16* rects)
236 {
237 int index;
238 RECTANGLE_16 screenRegion;
239 rdpSettings* settings = ((rdpContext*)client)->settings;
240 EnterCriticalSection(&(client->lock));
241
242 /* Mark client invalid region. No rectangle means full screen */
243 if (numRects > 0)
244 {
245 for (index = 0; index < numRects; index++)
246 {
247 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
248 }
249 }
250 else
251 {
252 screenRegion.left = 0;
253 screenRegion.top = 0;
254 screenRegion.right = settings->DesktopWidth;
255 screenRegion.bottom = settings->DesktopHeight;
256 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &screenRegion);
257 }
258
259 LeaveCriticalSection(&(client->lock));
260 }
261
262 /**
263 * Function description
264 * Recalculate client desktop size and update to rdpSettings
265 *
266 * @return TRUE if width/height changed.
267 */
shadow_client_recalc_desktop_size(rdpShadowClient * client)268 static INLINE BOOL shadow_client_recalc_desktop_size(rdpShadowClient* client)
269 {
270 int width, height;
271 rdpShadowServer* server = client->server;
272 rdpSettings* settings = client->context.settings;
273 RECTANGLE_16 viewport = { 0, 0, server->surface->width, server->surface->height };
274
275 if (server->shareSubRect)
276 {
277 rectangles_intersection(&viewport, &(server->subRect), &viewport);
278 }
279
280 width = viewport.right - viewport.left;
281 height = viewport.bottom - viewport.top;
282
283 if (settings->DesktopWidth != (UINT32)width || settings->DesktopHeight != (UINT32)height)
284 {
285 settings->DesktopWidth = width;
286 settings->DesktopHeight = height;
287 return TRUE;
288 }
289
290 return FALSE;
291 }
292
shadow_client_capabilities(freerdp_peer * peer)293 static BOOL shadow_client_capabilities(freerdp_peer* peer)
294 {
295 rdpShadowSubsystem* subsystem;
296 rdpShadowClient* client;
297 BOOL ret = TRUE;
298 client = (rdpShadowClient*)peer->context;
299 subsystem = client->server->subsystem;
300 IFCALLRET(subsystem->ClientCapabilities, ret, subsystem, client);
301
302 if (!ret)
303 WLog_WARN(TAG, "subsystem->ClientCapabilities failed");
304
305 /* Recalculate desktop size regardless whether previous call fail
306 * or not. Make sure we send correct width/height to client */
307 (void)shadow_client_recalc_desktop_size(client);
308 return ret;
309 }
310
shadow_client_post_connect(freerdp_peer * peer)311 static BOOL shadow_client_post_connect(freerdp_peer* peer)
312 {
313 int authStatus;
314 rdpSettings* settings;
315 rdpShadowClient* client;
316 rdpShadowServer* server;
317 rdpShadowSubsystem* subsystem;
318 client = (rdpShadowClient*)peer->context;
319 settings = peer->settings;
320 server = client->server;
321 subsystem = server->subsystem;
322
323 if (settings->ColorDepth == 24)
324 settings->ColorDepth = 16; /* disable 24bpp */
325
326 if (settings->MultifragMaxRequestSize < 0x3F0000)
327 settings->NSCodec = FALSE; /* NSCodec compressor does not support fragmentation yet */
328
329 WLog_INFO(TAG, "Client from %s is activated (%" PRIu32 "x%" PRIu32 "@%" PRIu32 ")",
330 peer->hostname, settings->DesktopWidth, settings->DesktopHeight,
331 settings->ColorDepth);
332
333 /* Resize client if necessary */
334 if (shadow_client_recalc_desktop_size(client))
335 {
336 peer->update->DesktopResize(peer->update->context);
337 WLog_INFO(TAG, "Client from %s is resized (%" PRIu32 "x%" PRIu32 "@%" PRIu32 ")",
338 peer->hostname, settings->DesktopWidth, settings->DesktopHeight,
339 settings->ColorDepth);
340 }
341
342 if (shadow_client_channels_post_connect(client) != CHANNEL_RC_OK)
343 return FALSE;
344
345 shadow_client_mark_invalid(client, 0, NULL);
346 authStatus = -1;
347
348 if (settings->Username && settings->Password)
349 settings->AutoLogonEnabled = TRUE;
350
351 if (server->authentication && !settings->NlaSecurity)
352 {
353 if (subsystem->Authenticate)
354 {
355 authStatus = subsystem->Authenticate(subsystem, client, settings->Username,
356 settings->Domain, settings->Password);
357 }
358
359 if (authStatus < 0)
360 {
361 WLog_ERR(TAG, "client authentication failure: %d", authStatus);
362 return FALSE;
363 }
364 }
365
366 if (subsystem->ClientConnect)
367 {
368 return subsystem->ClientConnect(subsystem, client);
369 }
370
371 return TRUE;
372 }
373
374 /* Convert rects in sub rect coordinate to client/surface coordinate */
shadow_client_convert_rects(rdpShadowClient * client,RECTANGLE_16 * dst,const RECTANGLE_16 * src,UINT32 numRects)375 static INLINE void shadow_client_convert_rects(rdpShadowClient* client, RECTANGLE_16* dst,
376 const RECTANGLE_16* src, UINT32 numRects)
377 {
378 if (client->server->shareSubRect)
379 {
380 UINT32 i = 0;
381 UINT16 offsetX = client->server->subRect.left;
382 UINT16 offsetY = client->server->subRect.top;
383
384 for (i = 0; i < numRects; i++)
385 {
386 dst[i].left = src[i].left + offsetX;
387 dst[i].right = src[i].right + offsetX;
388 dst[i].top = src[i].top + offsetY;
389 dst[i].bottom = src[i].bottom + offsetY;
390 }
391 }
392 else
393 {
394 if (src != dst)
395 {
396 CopyMemory(dst, src, numRects * sizeof(RECTANGLE_16));
397 }
398 }
399 }
400
shadow_client_refresh_request(rdpShadowClient * client)401 static BOOL shadow_client_refresh_request(rdpShadowClient* client)
402 {
403 wMessage message = { 0 };
404 wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
405 message.id = SHADOW_MSG_IN_REFRESH_REQUEST_ID;
406 message.wParam = NULL;
407 message.lParam = NULL;
408 message.context = (void*)client;
409 message.Free = NULL;
410 return MessageQueue_Dispatch(MsgPipe->In, &message);
411 }
412
shadow_client_refresh_rect(rdpContext * context,BYTE count,const RECTANGLE_16 * areas)413 static BOOL shadow_client_refresh_rect(rdpContext* context, BYTE count, const RECTANGLE_16* areas)
414 {
415 rdpShadowClient* client = (rdpShadowClient*)context;
416 RECTANGLE_16* rects;
417
418 /* It is invalid if we have area count but no actual area */
419 if (count && !areas)
420 return FALSE;
421
422 if (count)
423 {
424 rects = (RECTANGLE_16*)calloc(count, sizeof(RECTANGLE_16));
425
426 if (!rects)
427 {
428 return FALSE;
429 }
430
431 shadow_client_convert_rects(client, rects, areas, count);
432 shadow_client_mark_invalid(client, count, rects);
433 free(rects);
434 }
435 else
436 {
437 shadow_client_mark_invalid(client, 0, NULL);
438 }
439
440 return shadow_client_refresh_request(client);
441 }
442
shadow_client_suppress_output(rdpContext * context,BYTE allow,const RECTANGLE_16 * area)443 static BOOL shadow_client_suppress_output(rdpContext* context, BYTE allow, const RECTANGLE_16* area)
444 {
445 rdpShadowClient* client = (rdpShadowClient*)context;
446 RECTANGLE_16 region;
447 client->suppressOutput = allow ? FALSE : TRUE;
448
449 if (allow)
450 {
451 if (area)
452 {
453 shadow_client_convert_rects(client, ®ion, area, 1);
454 shadow_client_mark_invalid(client, 1, ®ion);
455 }
456 else
457 {
458 shadow_client_mark_invalid(client, 0, NULL);
459 }
460 }
461
462 return shadow_client_refresh_request(client);
463 }
464
shadow_client_activate(freerdp_peer * peer)465 static BOOL shadow_client_activate(freerdp_peer* peer)
466 {
467 rdpSettings* settings = peer->settings;
468 rdpShadowClient* client = (rdpShadowClient*)peer->context;
469
470 if (settings->ClientDir && (strcmp(settings->ClientDir, "librdp") == 0))
471 {
472 /* Hack for Mac/iOS/Android Microsoft RDP clients */
473 settings->RemoteFxCodec = FALSE;
474 settings->NSCodec = FALSE;
475 settings->NSCodecAllowSubsampling = FALSE;
476 settings->SurfaceFrameMarkerEnabled = FALSE;
477 }
478
479 client->activated = TRUE;
480 client->inLobby = client->mayView ? FALSE : TRUE;
481
482 if (shadow_encoder_reset(client->encoder) < 0)
483 {
484 WLog_ERR(TAG, "Failed to reset encoder");
485 return FALSE;
486 }
487
488 /* Update full screen in next update */
489 return shadow_client_refresh_rect(&client->context, 0, NULL);
490 }
491
shadow_client_logon(freerdp_peer * peer,SEC_WINNT_AUTH_IDENTITY * identity,BOOL automatic)492 static BOOL shadow_client_logon(freerdp_peer* peer, SEC_WINNT_AUTH_IDENTITY* identity,
493 BOOL automatic)
494 {
495 char* user = NULL;
496 char* domain = NULL;
497 char* password = NULL;
498 rdpSettings* settings = peer->settings;
499
500 if (identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
501 {
502 if (identity->User)
503 ConvertFromUnicode(CP_UTF8, 0, identity->User, identity->UserLength, &user, 0, NULL,
504 NULL);
505
506 if (identity->Domain)
507 ConvertFromUnicode(CP_UTF8, 0, identity->Domain, identity->DomainLength, &domain, 0,
508 NULL, NULL);
509
510 if (identity->Password)
511 ConvertFromUnicode(CP_UTF8, 0, identity->Password, identity->PasswordLength, &user, 0,
512 NULL, NULL);
513 }
514 else
515 {
516 if (identity->User)
517 user = _strdup((char*)identity->User);
518
519 if (identity->Domain)
520 domain = _strdup((char*)identity->Domain);
521
522 if (identity->Password)
523 password = _strdup((char*)identity->Password);
524 }
525
526 if ((identity->User && !user) || (identity->Domain && !domain) ||
527 (identity->Password && !password))
528 {
529 free(user);
530 free(domain);
531 free(password);
532 return FALSE;
533 }
534
535 if (user)
536 {
537 free(settings->Username);
538 settings->Username = user;
539 user = NULL;
540 }
541
542 if (domain)
543 {
544 free(settings->Domain);
545 settings->Domain = domain;
546 domain = NULL;
547 }
548
549 if (password)
550 {
551 free(settings->Password);
552 settings->Password = password;
553 password = NULL;
554 }
555
556 free(user);
557 free(domain);
558 free(password);
559 return TRUE;
560 }
561
shadow_client_common_frame_acknowledge(rdpShadowClient * client,UINT32 frameId)562 static INLINE void shadow_client_common_frame_acknowledge(rdpShadowClient* client, UINT32 frameId)
563 {
564 /*
565 * Record the last client acknowledged frame id to
566 * calculate how much frames are in progress.
567 * Some rdp clients (win7 mstsc) skips frame ACK if it is
568 * inactive, we should not expect ACK for each frame.
569 * So it is OK to calculate inflight frame count according to
570 * a latest acknowledged frame id.
571 */
572 client->encoder->lastAckframeId = frameId;
573 }
574
shadow_client_surface_frame_acknowledge(rdpContext * context,UINT32 frameId)575 static BOOL shadow_client_surface_frame_acknowledge(rdpContext* context, UINT32 frameId)
576 {
577 rdpShadowClient* client = (rdpShadowClient*)context;
578 shadow_client_common_frame_acknowledge(client, frameId);
579 /*
580 * Reset queueDepth for legacy none RDPGFX acknowledge
581 */
582 client->encoder->queueDepth = QUEUE_DEPTH_UNAVAILABLE;
583 return TRUE;
584 }
585
586 static UINT
shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext * context,const RDPGFX_FRAME_ACKNOWLEDGE_PDU * frameAcknowledge)587 shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context,
588 const RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge)
589 {
590 rdpShadowClient* client = (rdpShadowClient*)context->custom;
591 shadow_client_common_frame_acknowledge(client, frameAcknowledge->frameId);
592 client->encoder->queueDepth = frameAcknowledge->queueDepth;
593 return CHANNEL_RC_OK;
594 }
595
shadow_are_caps_filtered(const rdpSettings * settings,UINT32 caps)596 static BOOL shadow_are_caps_filtered(const rdpSettings* settings, UINT32 caps)
597 {
598 const UINT32 filter = settings->GfxCapsFilter;
599 const UINT32 capList[] = {
600 RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, RDPGFX_CAPVERSION_10,
601 RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103,
602 RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_106
603 };
604 UINT32 x;
605
606 for (x = 0; x < ARRAYSIZE(capList); x++)
607 {
608 if (caps == capList[x])
609 return (filter & (1 << x)) != 0;
610 }
611
612 return TRUE;
613 }
614
shadow_client_caps_test_version(RdpgfxServerContext * context,BOOL h264,const RDPGFX_CAPSET * capsSets,UINT32 capsSetCount,UINT32 capsVersion,UINT * rc)615 static BOOL shadow_client_caps_test_version(RdpgfxServerContext* context, BOOL h264,
616 const RDPGFX_CAPSET* capsSets, UINT32 capsSetCount,
617 UINT32 capsVersion, UINT* rc)
618 {
619 UINT32 flags = 0;
620 UINT32 index;
621 rdpSettings* settings;
622 settings = context->rdpcontext->settings;
623
624 if (shadow_are_caps_filtered(settings, capsVersion))
625 return FALSE;
626
627 for (index = 0; index < capsSetCount; index++)
628 {
629 const RDPGFX_CAPSET* currentCaps = &capsSets[index];
630
631 if (currentCaps->version == capsVersion)
632 {
633 RDPGFX_CAPSET caps = *currentCaps;
634 RDPGFX_CAPS_CONFIRM_PDU pdu;
635 pdu.capsSet = ∩︀
636
637 if (settings)
638 {
639 flags = pdu.capsSet->flags;
640 settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
641
642 if (h264)
643 settings->GfxAVC444v2 = settings->GfxAVC444 = settings->GfxH264 =
644 !(flags & RDPGFX_CAPS_FLAG_AVC_DISABLED);
645 else
646 {
647 settings->GfxAVC444v2 = settings->GfxAVC444 = settings->GfxH264 = FALSE;
648 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
649 }
650 }
651
652 *rc = context->CapsConfirm(context, &pdu);
653 return TRUE;
654 }
655 }
656
657 return FALSE;
658 }
659
660 /**
661 * Function description
662 *
663 * @return 0 on success, otherwise a Win32 error code
664 */
shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext * context,const RDPGFX_CAPS_ADVERTISE_PDU * capsAdvertise)665 static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context,
666 const RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise)
667 {
668 UINT16 index;
669 UINT rc = ERROR_INTERNAL_ERROR;
670 BOOL h264 = FALSE;
671 rdpSettings* settings = context->rdpcontext->settings;
672 UINT32 flags = 0;
673 rdpShadowClient* client = (rdpShadowClient*)context->custom;
674
675 #ifdef WITH_GFX_H264
676 if (shadow_encoder_prepare(client->encoder, FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444) >= 0)
677 h264 = TRUE;
678
679 #endif
680
681 /* Request full screen update for new gfx channel */
682 if (!shadow_client_refresh_rect(&client->context, 0, NULL))
683 return rc;
684
685 if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
686 capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_106, &rc))
687 return rc;
688
689 if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
690 capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_105, &rc))
691 return rc;
692
693 if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
694 capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_104, &rc))
695 return rc;
696
697 if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
698 capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_103, &rc))
699 return rc;
700
701 if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
702 capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_102, &rc))
703 return rc;
704
705 if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
706 capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_101, &rc))
707 return rc;
708
709 if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets,
710 capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_10, &rc))
711 return rc;
712
713 if (!shadow_are_caps_filtered(settings, RDPGFX_CAPVERSION_81))
714 {
715 for (index = 0; index < capsAdvertise->capsSetCount; index++)
716 {
717 const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
718
719 if (currentCaps->version == RDPGFX_CAPVERSION_81)
720 {
721 RDPGFX_CAPSET caps = *currentCaps;
722 RDPGFX_CAPS_CONFIRM_PDU pdu;
723 pdu.capsSet = ∩︀
724
725 if (settings)
726 {
727 flags = pdu.capsSet->flags;
728 settings->GfxAVC444v2 = settings->GfxAVC444 = FALSE;
729 settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT);
730 settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
731 #ifndef WITH_GFX_H264
732 settings->GfxH264 = FALSE;
733 pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED;
734 #else
735 if (h264)
736 settings->GfxH264 = (flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED);
737 else
738 settings->GfxH264 = FALSE;
739 #endif
740 }
741
742 return context->CapsConfirm(context, &pdu);
743 }
744 }
745 }
746
747 if (!shadow_are_caps_filtered(settings, RDPGFX_CAPVERSION_8))
748 {
749 for (index = 0; index < capsAdvertise->capsSetCount; index++)
750 {
751 const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
752
753 if (currentCaps->version == RDPGFX_CAPVERSION_8)
754 {
755 RDPGFX_CAPSET caps = *currentCaps;
756 RDPGFX_CAPS_CONFIRM_PDU pdu;
757 pdu.capsSet = ∩︀
758
759 if (settings)
760 {
761 flags = pdu.capsSet->flags;
762 settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT);
763 settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE);
764 }
765
766 return context->CapsConfirm(context, &pdu);
767 }
768 }
769 }
770
771 return CHANNEL_RC_UNSUPPORTED_VERSION;
772 }
773
rdpgfx_estimate_h264_avc420(RDPGFX_AVC420_BITMAP_STREAM * havc420)774 static INLINE UINT32 rdpgfx_estimate_h264_avc420(RDPGFX_AVC420_BITMAP_STREAM* havc420)
775 {
776 /* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */
777 return sizeof(UINT32) /* numRegionRects */
778 + 10 /* regionRects + quantQualityVals */
779 * havc420->meta.numRegionRects +
780 havc420->length;
781 }
782
783 /**
784 * Function description
785 *
786 * @return TRUE on success
787 */
shadow_client_send_surface_gfx(rdpShadowClient * client,const BYTE * pSrcData,int nSrcStep,int nXSrc,int nYSrc,int nWidth,int nHeight)788 static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, const BYTE* pSrcData,
789 int nSrcStep, int nXSrc, int nYSrc, int nWidth,
790 int nHeight)
791 {
792 UINT error = CHANNEL_RC_OK;
793 rdpContext* context = (rdpContext*)client;
794 rdpSettings* settings;
795 rdpShadowEncoder* encoder;
796 RDPGFX_SURFACE_COMMAND cmd;
797 RDPGFX_START_FRAME_PDU cmdstart;
798 RDPGFX_END_FRAME_PDU cmdend;
799 SYSTEMTIME sTime;
800
801 if (!context || !pSrcData)
802 return FALSE;
803
804 settings = context->settings;
805 encoder = client->encoder;
806
807 if (!settings || !encoder)
808 return FALSE;
809
810 cmdstart.frameId = shadow_encoder_create_frame_id(encoder);
811 GetSystemTime(&sTime);
812 cmdstart.timestamp =
813 sTime.wHour << 22 | sTime.wMinute << 16 | sTime.wSecond << 10 | sTime.wMilliseconds;
814 cmdend.frameId = cmdstart.frameId;
815 cmd.surfaceId = 0;
816 cmd.codecId = 0;
817 cmd.contextId = 0;
818 cmd.format = PIXEL_FORMAT_BGRX32;
819 cmd.left = nXSrc;
820 cmd.top = nYSrc;
821 cmd.right = cmd.left + nWidth;
822 cmd.bottom = cmd.top + nHeight;
823 cmd.width = nWidth;
824 cmd.height = nHeight;
825 cmd.length = 0;
826 cmd.data = NULL;
827 cmd.extra = NULL;
828
829 if (settings->GfxAVC444 || settings->GfxAVC444v2)
830 {
831 RDPGFX_AVC444_BITMAP_STREAM avc444;
832 RECTANGLE_16 regionRect;
833 RDPGFX_H264_QUANT_QUALITY quantQualityVal;
834 BYTE version = settings->GfxAVC444v2 ? 2 : 1;
835
836 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC444) < 0)
837 {
838 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AVC444");
839 return FALSE;
840 }
841
842 if (avc444_compress(encoder->h264, pSrcData, cmd.format, nSrcStep, nWidth, nHeight, version,
843 &avc444.LC, &avc444.bitstream[0].data, &avc444.bitstream[0].length,
844 &avc444.bitstream[1].data, &avc444.bitstream[1].length) < 0)
845 {
846 WLog_ERR(TAG, "avc420_compress failed for avc444");
847 return FALSE;
848 }
849
850 regionRect.left = cmd.left;
851 regionRect.top = cmd.top;
852 regionRect.right = cmd.right;
853 regionRect.bottom = cmd.bottom;
854 quantQualityVal.qp = encoder->h264->QP;
855 quantQualityVal.r = 0;
856 quantQualityVal.p = 0;
857 quantQualityVal.qualityVal = 100 - quantQualityVal.qp;
858 avc444.bitstream[0].meta.numRegionRects = 1;
859 avc444.bitstream[0].meta.regionRects = ®ionRect;
860 avc444.bitstream[0].meta.quantQualityVals = &quantQualityVal;
861 avc444.bitstream[1].meta.numRegionRects = 1;
862 avc444.bitstream[1].meta.regionRects = ®ionRect;
863 avc444.bitstream[1].meta.quantQualityVals = &quantQualityVal;
864 avc444.cbAvc420EncodedBitstream1 = rdpgfx_estimate_h264_avc420(&avc444.bitstream[0]);
865 cmd.codecId = settings->GfxAVC444v2 ? RDPGFX_CODECID_AVC444v2 : RDPGFX_CODECID_AVC444;
866 cmd.extra = (void*)&avc444;
867 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart,
868 &cmdend);
869
870 if (error)
871 {
872 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
873 return FALSE;
874 }
875 }
876 else if (settings->GfxH264)
877 {
878 RDPGFX_AVC420_BITMAP_STREAM avc420;
879 RECTANGLE_16 regionRect;
880 RDPGFX_H264_QUANT_QUALITY quantQualityVal;
881
882 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC420) < 0)
883 {
884 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AVC420");
885 return FALSE;
886 }
887
888 if (avc420_compress(encoder->h264, pSrcData, cmd.format, nSrcStep, nWidth, nHeight,
889 &avc420.data, &avc420.length) < 0)
890 {
891 WLog_ERR(TAG, "avc420_compress failed");
892 return FALSE;
893 }
894
895 cmd.codecId = RDPGFX_CODECID_AVC420;
896 cmd.extra = (void*)&avc420;
897 regionRect.left = cmd.left;
898 regionRect.top = cmd.top;
899 regionRect.right = cmd.right;
900 regionRect.bottom = cmd.bottom;
901 quantQualityVal.qp = encoder->h264->QP;
902 quantQualityVal.r = 0;
903 quantQualityVal.p = 0;
904 quantQualityVal.qualityVal = 100 - quantQualityVal.qp;
905 avc420.meta.numRegionRects = 1;
906 avc420.meta.regionRects = ®ionRect;
907 avc420.meta.quantQualityVals = &quantQualityVal;
908 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart,
909 &cmdend);
910
911 if (error)
912 {
913 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
914 return FALSE;
915 }
916 }
917
918 return TRUE;
919 }
920
921 /**
922 * Function description
923 *
924 * @return TRUE on success
925 */
shadow_client_send_surface_bits(rdpShadowClient * client,BYTE * pSrcData,int nSrcStep,int nXSrc,int nYSrc,int nWidth,int nHeight)926 static BOOL shadow_client_send_surface_bits(rdpShadowClient* client, BYTE* pSrcData, int nSrcStep,
927 int nXSrc, int nYSrc, int nWidth, int nHeight)
928 {
929 BOOL ret = TRUE;
930 size_t i;
931 BOOL first;
932 BOOL last;
933 wStream* s;
934 size_t numMessages;
935 UINT32 frameId = 0;
936 rdpUpdate* update;
937 rdpContext* context = (rdpContext*)client;
938 rdpSettings* settings;
939 rdpShadowEncoder* encoder;
940 SURFACE_BITS_COMMAND cmd = { 0 };
941
942 if (!context || !pSrcData)
943 return FALSE;
944
945 update = context->update;
946 settings = context->settings;
947 encoder = client->encoder;
948
949 if (!update || !settings || !encoder)
950 return FALSE;
951
952 if (encoder->frameAck)
953 frameId = shadow_encoder_create_frame_id(encoder);
954
955 if (settings->RemoteFxCodec)
956 {
957 RFX_RECT rect;
958 RFX_MESSAGE* messages;
959 RFX_RECT* messageRects = NULL;
960
961 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX) < 0)
962 {
963 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_REMOTEFX");
964 return FALSE;
965 }
966
967 s = encoder->bs;
968 rect.x = nXSrc;
969 rect.y = nYSrc;
970 rect.width = nWidth;
971 rect.height = nHeight;
972
973 if (!(messages = rfx_encode_messages_ex(
974 encoder->rfx, &rect, 1, pSrcData, settings->DesktopWidth, settings->DesktopHeight,
975 nSrcStep, &numMessages, settings->MultifragMaxRequestSize)))
976 {
977 WLog_ERR(TAG, "rfx_encode_messages_ex failed");
978 return FALSE;
979 }
980
981 cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
982 cmd.bmp.codecID = settings->RemoteFxCodecId;
983 cmd.destLeft = 0;
984 cmd.destTop = 0;
985 cmd.destRight = settings->DesktopWidth;
986 cmd.destBottom = settings->DesktopHeight;
987 cmd.bmp.bpp = 32;
988 cmd.bmp.flags = 0;
989 cmd.bmp.width = settings->DesktopWidth;
990 cmd.bmp.height = settings->DesktopHeight;
991 cmd.skipCompression = TRUE;
992
993 if (numMessages > 0)
994 messageRects = messages[0].rects;
995
996 for (i = 0; i < numMessages; i++)
997 {
998 Stream_SetPosition(s, 0);
999
1000 if (!rfx_write_message(encoder->rfx, s, &messages[i]))
1001 {
1002 while (i < numMessages)
1003 {
1004 rfx_message_free(encoder->rfx, &messages[i++]);
1005 }
1006
1007 WLog_ERR(TAG, "rfx_write_message failed");
1008 ret = FALSE;
1009 break;
1010 }
1011
1012 rfx_message_free(encoder->rfx, &messages[i]);
1013 cmd.bmp.bitmapDataLength = Stream_GetPosition(s);
1014 cmd.bmp.bitmapData = Stream_Buffer(s);
1015 first = (i == 0) ? TRUE : FALSE;
1016 last = ((i + 1) == numMessages) ? TRUE : FALSE;
1017
1018 if (!encoder->frameAck)
1019 IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
1020 else
1021 IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last,
1022 frameId);
1023
1024 if (!ret)
1025 {
1026 WLog_ERR(TAG, "Send surface bits(RemoteFxCodec) failed");
1027 break;
1028 }
1029 }
1030
1031 free(messageRects);
1032 free(messages);
1033 }
1034 else if (settings->NSCodec)
1035 {
1036 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC) < 0)
1037 {
1038 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_NSCODEC");
1039 return FALSE;
1040 }
1041
1042 s = encoder->bs;
1043 Stream_SetPosition(s, 0);
1044 pSrcData = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
1045 nsc_compose_message(encoder->nsc, s, pSrcData, nWidth, nHeight, nSrcStep);
1046 cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
1047 cmd.bmp.bpp = 32;
1048 cmd.bmp.codecID = settings->NSCodecId;
1049 cmd.destLeft = nXSrc;
1050 cmd.destTop = nYSrc;
1051 cmd.destRight = cmd.destLeft + nWidth;
1052 cmd.destBottom = cmd.destTop + nHeight;
1053 cmd.bmp.width = nWidth;
1054 cmd.bmp.height = nHeight;
1055 cmd.bmp.bitmapDataLength = Stream_GetPosition(s);
1056 cmd.bmp.bitmapData = Stream_Buffer(s);
1057 first = TRUE;
1058 last = TRUE;
1059
1060 if (!encoder->frameAck)
1061 IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
1062 else
1063 IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last, frameId);
1064
1065 if (!ret)
1066 {
1067 WLog_ERR(TAG, "Send surface bits(NSCodec) failed");
1068 }
1069 }
1070
1071 return ret;
1072 }
1073
1074 /**
1075 * Function description
1076 *
1077 * @return TRUE on success
1078 */
shadow_client_send_bitmap_update(rdpShadowClient * client,BYTE * pSrcData,int nSrcStep,int nXSrc,int nYSrc,int nWidth,int nHeight)1079 static BOOL shadow_client_send_bitmap_update(rdpShadowClient* client, BYTE* pSrcData, int nSrcStep,
1080 int nXSrc, int nYSrc, int nWidth, int nHeight)
1081 {
1082 BOOL ret = TRUE;
1083 BYTE* data;
1084 BYTE* buffer;
1085 size_t k;
1086 int yIdx, xIdx;
1087 int rows, cols;
1088 UINT32 DstSize;
1089 UINT32 SrcFormat;
1090 BITMAP_DATA* bitmap;
1091 rdpUpdate* update;
1092 rdpContext* context = (rdpContext*)client;
1093 rdpSettings* settings;
1094 UINT32 maxUpdateSize;
1095 UINT32 totalBitmapSize;
1096 UINT32 updateSizeEstimate;
1097 BITMAP_DATA* bitmapData;
1098 BITMAP_UPDATE bitmapUpdate;
1099 rdpShadowEncoder* encoder;
1100
1101 if (!context || !pSrcData)
1102 return FALSE;
1103
1104 update = context->update;
1105 settings = context->settings;
1106 encoder = client->encoder;
1107
1108 if (!update || !settings || !encoder)
1109 return FALSE;
1110
1111 maxUpdateSize = settings->MultifragMaxRequestSize;
1112
1113 if (settings->ColorDepth < 32)
1114 {
1115 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED) < 0)
1116 {
1117 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_INTERLEAVED");
1118 return FALSE;
1119 }
1120 }
1121 else
1122 {
1123 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR) < 0)
1124 {
1125 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_PLANAR");
1126 return FALSE;
1127 }
1128 }
1129
1130 SrcFormat = PIXEL_FORMAT_BGRX32;
1131
1132 if ((nXSrc % 4) != 0)
1133 {
1134 nWidth += (nXSrc % 4);
1135 nXSrc -= (nXSrc % 4);
1136 }
1137
1138 if ((nYSrc % 4) != 0)
1139 {
1140 nHeight += (nYSrc % 4);
1141 nYSrc -= (nYSrc % 4);
1142 }
1143
1144 rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0);
1145 cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0);
1146 k = 0;
1147 totalBitmapSize = 0;
1148 bitmapUpdate.count = bitmapUpdate.number = rows * cols;
1149
1150 if (!(bitmapData = (BITMAP_DATA*)calloc(bitmapUpdate.number, sizeof(BITMAP_DATA))))
1151 return FALSE;
1152
1153 bitmapUpdate.rectangles = bitmapData;
1154
1155 if ((nWidth % 4) != 0)
1156 {
1157 nWidth += (4 - (nWidth % 4));
1158 }
1159
1160 if ((nHeight % 4) != 0)
1161 {
1162 nHeight += (4 - (nHeight % 4));
1163 }
1164
1165 for (yIdx = 0; yIdx < rows; yIdx++)
1166 {
1167 for (xIdx = 0; xIdx < cols; xIdx++)
1168 {
1169 bitmap = &bitmapData[k];
1170 bitmap->width = 64;
1171 bitmap->height = 64;
1172 bitmap->destLeft = nXSrc + (xIdx * 64);
1173 bitmap->destTop = nYSrc + (yIdx * 64);
1174
1175 if ((INT64)(bitmap->destLeft + bitmap->width) > (nXSrc + nWidth))
1176 bitmap->width = (UINT32)(nXSrc + nWidth) - bitmap->destLeft;
1177
1178 if ((INT64)(bitmap->destTop + bitmap->height) > (nYSrc + nHeight))
1179 bitmap->height = (UINT32)(nYSrc + nHeight) - bitmap->destTop;
1180
1181 bitmap->destRight = bitmap->destLeft + bitmap->width - 1;
1182 bitmap->destBottom = bitmap->destTop + bitmap->height - 1;
1183 bitmap->compressed = TRUE;
1184
1185 if ((bitmap->width < 4) || (bitmap->height < 4))
1186 continue;
1187
1188 if (settings->ColorDepth < 32)
1189 {
1190 int bitsPerPixel = settings->ColorDepth;
1191 int bytesPerPixel = (bitsPerPixel + 7) / 8;
1192 DstSize = 64 * 64 * 4;
1193 buffer = encoder->grid[k];
1194 interleaved_compress(encoder->interleaved, buffer, &DstSize, bitmap->width,
1195 bitmap->height, pSrcData, SrcFormat, nSrcStep,
1196 bitmap->destLeft, bitmap->destTop, NULL, bitsPerPixel);
1197 bitmap->bitmapDataStream = buffer;
1198 bitmap->bitmapLength = DstSize;
1199 bitmap->bitsPerPixel = bitsPerPixel;
1200 bitmap->cbScanWidth = bitmap->width * bytesPerPixel;
1201 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel;
1202 }
1203 else
1204 {
1205 UINT32 dstSize;
1206 buffer = encoder->grid[k];
1207 data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)];
1208 buffer =
1209 freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat, bitmap->width,
1210 bitmap->height, nSrcStep, buffer, &dstSize);
1211 bitmap->bitmapDataStream = buffer;
1212 bitmap->bitmapLength = dstSize;
1213 bitmap->bitsPerPixel = 32;
1214 bitmap->cbScanWidth = bitmap->width * 4;
1215 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4;
1216 }
1217
1218 bitmap->cbCompFirstRowSize = 0;
1219 bitmap->cbCompMainBodySize = bitmap->bitmapLength;
1220 totalBitmapSize += bitmap->bitmapLength;
1221 k++;
1222 }
1223 }
1224
1225 bitmapUpdate.count = bitmapUpdate.number = k;
1226 updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.count) + 16;
1227
1228 if (updateSizeEstimate > maxUpdateSize)
1229 {
1230 UINT32 i, j;
1231 UINT32 updateSize;
1232 UINT32 newUpdateSize;
1233 BITMAP_DATA* fragBitmapData = NULL;
1234
1235 if (k > 0)
1236 fragBitmapData = (BITMAP_DATA*)calloc(k, sizeof(BITMAP_DATA));
1237
1238 if (!fragBitmapData)
1239 {
1240 WLog_ERR(TAG, "Failed to allocate memory for fragBitmapData");
1241 ret = FALSE;
1242 goto out;
1243 }
1244
1245 bitmapUpdate.rectangles = fragBitmapData;
1246 i = j = 0;
1247 updateSize = 1024;
1248
1249 while (i < k)
1250 {
1251 newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16);
1252
1253 if (newUpdateSize < maxUpdateSize)
1254 {
1255 CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA));
1256 updateSize = newUpdateSize;
1257 }
1258
1259 if ((newUpdateSize >= maxUpdateSize) || (i + 1) >= k)
1260 {
1261 bitmapUpdate.count = bitmapUpdate.number = j;
1262 IFCALLRET(update->BitmapUpdate, ret, context, &bitmapUpdate);
1263
1264 if (!ret)
1265 {
1266 WLog_ERR(TAG, "BitmapUpdate failed");
1267 break;
1268 }
1269
1270 updateSize = 1024;
1271 j = 0;
1272 }
1273 }
1274
1275 free(fragBitmapData);
1276 }
1277 else
1278 {
1279 IFCALLRET(update->BitmapUpdate, ret, context, &bitmapUpdate);
1280
1281 if (!ret)
1282 {
1283 WLog_ERR(TAG, "BitmapUpdate failed");
1284 }
1285 }
1286
1287 out:
1288 free(bitmapData);
1289 return ret;
1290 }
1291
1292 /**
1293 * Function description
1294 *
1295 * @return TRUE on success (or nothing need to be updated)
1296 */
shadow_client_send_surface_update(rdpShadowClient * client,SHADOW_GFX_STATUS * pStatus)1297 static BOOL shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
1298 {
1299 BOOL ret = TRUE;
1300 int nXSrc, nYSrc;
1301 int nWidth, nHeight;
1302 rdpContext* context = (rdpContext*)client;
1303 rdpSettings* settings;
1304 rdpShadowServer* server;
1305 rdpShadowSurface* surface;
1306 REGION16 invalidRegion;
1307 RECTANGLE_16 surfaceRect;
1308 const RECTANGLE_16* extents;
1309 BYTE* pSrcData;
1310 int nSrcStep;
1311 UINT32 index;
1312 UINT32 numRects = 0;
1313 const RECTANGLE_16* rects;
1314
1315 if (!context || !pStatus)
1316 return FALSE;
1317
1318 settings = context->settings;
1319 server = client->server;
1320
1321 if (!settings || !server)
1322 return FALSE;
1323
1324 surface = client->inLobby ? server->lobby : server->surface;
1325
1326 if (!surface)
1327 return FALSE;
1328
1329 EnterCriticalSection(&(client->lock));
1330 region16_init(&invalidRegion);
1331 region16_copy(&invalidRegion, &(client->invalidRegion));
1332 region16_clear(&(client->invalidRegion));
1333 LeaveCriticalSection(&(client->lock));
1334
1335 EnterCriticalSection(&surface->lock);
1336 rects = region16_rects(&(surface->invalidRegion), &numRects);
1337
1338 for (index = 0; index < numRects; index++)
1339 region16_union_rect(&invalidRegion, &invalidRegion, &rects[index]);
1340
1341 surfaceRect.left = 0;
1342 surfaceRect.top = 0;
1343 surfaceRect.right = surface->width;
1344 surfaceRect.bottom = surface->height;
1345 region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect);
1346
1347 if (server->shareSubRect)
1348 {
1349 region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect));
1350 }
1351
1352 if (region16_is_empty(&invalidRegion))
1353 {
1354 /* No image region need to be updated. Success */
1355 goto out;
1356 }
1357
1358 extents = region16_extents(&invalidRegion);
1359 nXSrc = extents->left;
1360 nYSrc = extents->top;
1361 nWidth = extents->right - extents->left;
1362 nHeight = extents->bottom - extents->top;
1363 pSrcData = surface->data;
1364 nSrcStep = surface->scanline;
1365
1366 /* Move to new pSrcData / nXSrc / nYSrc according to sub rect */
1367 if (server->shareSubRect)
1368 {
1369 int subX, subY;
1370 subX = server->subRect.left;
1371 subY = server->subRect.top;
1372 nXSrc -= subX;
1373 nYSrc -= subY;
1374 pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)];
1375 }
1376
1377 // WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d
1378 // bottom: %d", nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight);
1379
1380 if (settings->SupportGraphicsPipeline && settings->GfxH264 && pStatus->gfxOpened)
1381 {
1382 /* GFX/h264 always full screen encoded */
1383 nWidth = settings->DesktopWidth;
1384 nHeight = settings->DesktopHeight;
1385
1386 /* Create primary surface if have not */
1387 if (!pStatus->gfxSurfaceCreated)
1388 {
1389 /* Only init surface when we have h264 supported */
1390 if (!(ret = shadow_client_rdpgfx_reset_graphic(client)))
1391 goto out;
1392
1393 if (!(ret = shadow_client_rdpgfx_new_surface(client)))
1394 goto out;
1395
1396 pStatus->gfxSurfaceCreated = TRUE;
1397 }
1398
1399 ret = shadow_client_send_surface_gfx(client, pSrcData, nSrcStep, 0, 0, nWidth, nHeight);
1400 }
1401 else if (settings->RemoteFxCodec || settings->NSCodec)
1402 {
1403 ret = shadow_client_send_surface_bits(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth,
1404 nHeight);
1405 }
1406 else
1407 {
1408 ret = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth,
1409 nHeight);
1410 }
1411
1412 out:
1413 LeaveCriticalSection(&surface->lock);
1414 region16_uninit(&invalidRegion);
1415 return ret;
1416 }
1417
1418 /**
1419 * Function description
1420 * Notify client for resize. The new desktop width/height
1421 * should have already been updated in rdpSettings.
1422 *
1423 * @return TRUE on success
1424 */
shadow_client_send_resize(rdpShadowClient * client,SHADOW_GFX_STATUS * pStatus)1425 static BOOL shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
1426 {
1427 rdpContext* context = (rdpContext*)client;
1428 rdpSettings* settings;
1429 freerdp_peer* peer;
1430
1431 if (!context || !pStatus)
1432 return FALSE;
1433
1434 peer = context->peer;
1435 settings = context->settings;
1436
1437 if (!peer || !settings)
1438 return FALSE;
1439
1440 /**
1441 * Unset client activated flag to avoid sending update message during
1442 * resize. DesktopResize will reactive the client and
1443 * shadow_client_activate would be invoked later.
1444 */
1445 client->activated = FALSE;
1446
1447 /* Close Gfx surfaces */
1448 if (pStatus->gfxSurfaceCreated)
1449 {
1450 if (!shadow_client_rdpgfx_release_surface(client))
1451 return FALSE;
1452
1453 pStatus->gfxSurfaceCreated = FALSE;
1454 }
1455
1456 /* Send Resize */
1457 if (!peer->update->DesktopResize(peer->update->context))
1458 {
1459 WLog_ERR(TAG, "DesktopResize failed");
1460 return FALSE;
1461 }
1462
1463 /* Clear my invalidRegion. shadow_client_activate refreshes fullscreen */
1464 EnterCriticalSection(&(client->lock));
1465 region16_clear(&(client->invalidRegion));
1466 LeaveCriticalSection(&(client->lock));
1467 WLog_INFO(TAG, "Client from %s is resized (%" PRIu32 "x%" PRIu32 "@%" PRIu32 ")",
1468 peer->hostname, settings->DesktopWidth, settings->DesktopHeight,
1469 settings->ColorDepth);
1470 return TRUE;
1471 }
1472
1473 /**
1474 * Function description
1475 * Mark invalid region for client
1476 *
1477 * @return TRUE on success
1478 */
shadow_client_surface_update(rdpShadowClient * client,REGION16 * region)1479 static BOOL shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
1480 {
1481 UINT32 numRects = 0;
1482 const RECTANGLE_16* rects;
1483 rects = region16_rects(region, &numRects);
1484 shadow_client_mark_invalid(client, numRects, rects);
1485 return TRUE;
1486 }
1487
1488 /**
1489 * Function description
1490 * Only union invalid region from server surface
1491 *
1492 * @return TRUE on success
1493 */
shadow_client_no_surface_update(rdpShadowClient * client,SHADOW_GFX_STATUS * pStatus)1494 static INLINE BOOL shadow_client_no_surface_update(rdpShadowClient* client,
1495 SHADOW_GFX_STATUS* pStatus)
1496 {
1497 rdpShadowServer* server;
1498 rdpShadowSurface* surface;
1499 WINPR_UNUSED(pStatus);
1500 server = client->server;
1501 surface = client->inLobby ? server->lobby : server->surface;
1502 return shadow_client_surface_update(client, &(surface->invalidRegion));
1503 }
1504
shadow_client_subsystem_process_message(rdpShadowClient * client,wMessage * message)1505 static int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message)
1506 {
1507 rdpContext* context = (rdpContext*)client;
1508 rdpUpdate* update = context->update;
1509
1510 /* FIXME: the pointer updates appear to be broken when used with bulk compression and mstsc */
1511
1512 switch (message->id)
1513 {
1514 case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
1515 {
1516 POINTER_POSITION_UPDATE pointerPosition;
1517 SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg =
1518 (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*)message->wParam;
1519 pointerPosition.xPos = msg->xPos;
1520 pointerPosition.yPos = msg->yPos;
1521
1522 if (client->server->shareSubRect)
1523 {
1524 pointerPosition.xPos -= client->server->subRect.left;
1525 pointerPosition.yPos -= client->server->subRect.top;
1526 }
1527
1528 if (client->activated)
1529 {
1530 if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
1531 {
1532 IFCALL(update->pointer->PointerPosition, context, &pointerPosition);
1533 client->pointerX = msg->xPos;
1534 client->pointerY = msg->yPos;
1535 }
1536 }
1537
1538 break;
1539 }
1540
1541 case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
1542 {
1543 POINTER_NEW_UPDATE pointerNew;
1544 POINTER_COLOR_UPDATE* pointerColor;
1545 POINTER_CACHED_UPDATE pointerCached;
1546 SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg =
1547 (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)message->wParam;
1548 ZeroMemory(&pointerNew, sizeof(POINTER_NEW_UPDATE));
1549 pointerNew.xorBpp = 24;
1550 pointerColor = &(pointerNew.colorPtrAttr);
1551 pointerColor->cacheIndex = 0;
1552 pointerColor->xPos = msg->xHot;
1553 pointerColor->yPos = msg->yHot;
1554 pointerColor->width = msg->width;
1555 pointerColor->height = msg->height;
1556 pointerColor->lengthAndMask = msg->lengthAndMask;
1557 pointerColor->lengthXorMask = msg->lengthXorMask;
1558 pointerColor->xorMaskData = msg->xorMaskData;
1559 pointerColor->andMaskData = msg->andMaskData;
1560 pointerCached.cacheIndex = pointerColor->cacheIndex;
1561
1562 if (client->activated)
1563 {
1564 IFCALL(update->pointer->PointerNew, context, &pointerNew);
1565 IFCALL(update->pointer->PointerCached, context, &pointerCached);
1566 }
1567
1568 break;
1569 }
1570
1571 case SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID:
1572 {
1573 SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES* msg =
1574 (SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES*)message->wParam;
1575
1576 if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
1577 {
1578 client->rdpsnd->src_format = msg->audio_format;
1579 IFCALL(client->rdpsnd->SendSamples, client->rdpsnd, msg->buf, msg->nFrames,
1580 msg->wTimestamp);
1581 }
1582
1583 break;
1584 }
1585
1586 case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
1587 {
1588 SHADOW_MSG_OUT_AUDIO_OUT_VOLUME* msg =
1589 (SHADOW_MSG_OUT_AUDIO_OUT_VOLUME*)message->wParam;
1590
1591 if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
1592 {
1593 IFCALL(client->rdpsnd->SetVolume, client->rdpsnd, msg->left, msg->right);
1594 }
1595
1596 break;
1597 }
1598
1599 default:
1600 WLog_ERR(TAG, "Unknown message id: %" PRIu32 "", message->id);
1601 break;
1602 }
1603
1604 shadow_client_free_queued_message(message);
1605 return 1;
1606 }
1607
shadow_client_thread(LPVOID arg)1608 static DWORD WINAPI shadow_client_thread(LPVOID arg)
1609 {
1610 rdpShadowClient* client = (rdpShadowClient*)arg;
1611 DWORD status;
1612 DWORD nCount;
1613 wMessage message;
1614 wMessage pointerPositionMsg;
1615 wMessage pointerAlphaMsg;
1616 wMessage audioVolumeMsg;
1617 HANDLE events[32];
1618 HANDLE ChannelEvent;
1619 void* UpdateSubscriber;
1620 HANDLE UpdateEvent;
1621 freerdp_peer* peer;
1622 rdpContext* context;
1623 rdpSettings* settings;
1624 rdpShadowServer* server;
1625 rdpShadowSubsystem* subsystem;
1626 wMessageQueue* MsgQueue = client->MsgQueue;
1627 /* This should only be visited in client thread */
1628 SHADOW_GFX_STATUS gfxstatus;
1629 gfxstatus.gfxOpened = FALSE;
1630 gfxstatus.gfxSurfaceCreated = FALSE;
1631 server = client->server;
1632 subsystem = server->subsystem;
1633 context = (rdpContext*)client;
1634 peer = context->peer;
1635 settings = peer->settings;
1636 peer->Capabilities = shadow_client_capabilities;
1637 peer->PostConnect = shadow_client_post_connect;
1638 peer->Activate = shadow_client_activate;
1639 peer->Logon = shadow_client_logon;
1640 shadow_input_register_callbacks(peer->input);
1641 peer->Initialize(peer);
1642 peer->update->RefreshRect = shadow_client_refresh_rect;
1643 peer->update->SuppressOutput = shadow_client_suppress_output;
1644 peer->update->SurfaceFrameAcknowledge = shadow_client_surface_frame_acknowledge;
1645
1646 if ((!client->vcm) || (!subsystem->updateEvent))
1647 goto out;
1648
1649 UpdateSubscriber = shadow_multiclient_get_subscriber(subsystem->updateEvent);
1650
1651 if (!UpdateSubscriber)
1652 goto out;
1653
1654 UpdateEvent = shadow_multiclient_getevent(UpdateSubscriber);
1655 ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm);
1656
1657 while (1)
1658 {
1659 nCount = 0;
1660 events[nCount++] = UpdateEvent;
1661 {
1662 DWORD tmp = peer->GetEventHandles(peer, &events[nCount], 64 - nCount);
1663
1664 if (tmp == 0)
1665 {
1666 WLog_ERR(TAG, "Failed to get FreeRDP transport event handles");
1667 goto fail;
1668 }
1669
1670 nCount += tmp;
1671 }
1672 events[nCount++] = ChannelEvent;
1673 events[nCount++] = MessageQueue_Event(MsgQueue);
1674 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
1675
1676 if (status == WAIT_FAILED)
1677 goto fail;
1678
1679 if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
1680 {
1681 /* The UpdateEvent means to start sending current frame. It is
1682 * triggered from subsystem implementation and it should ensure
1683 * that the screen and primary surface meta data (width, height,
1684 * scanline, invalid region, etc) is not changed until it is reset
1685 * (at shadow_multiclient_consume). As best practice, subsystem
1686 * implementation should invoke shadow_subsystem_frame_update which
1687 * triggers the event and then wait for completion */
1688 if (client->activated && !client->suppressOutput)
1689 {
1690 /* Send screen update or resize to this client */
1691
1692 /* Check resize */
1693 if (shadow_client_recalc_desktop_size(client))
1694 {
1695 /* Screen size changed, do resize */
1696 if (!shadow_client_send_resize(client, &gfxstatus))
1697 {
1698 WLog_ERR(TAG, "Failed to send resize message");
1699 break;
1700 }
1701 }
1702 else
1703 {
1704 /* Send frame */
1705 if (!shadow_client_send_surface_update(client, &gfxstatus))
1706 {
1707 WLog_ERR(TAG, "Failed to send surface update");
1708 break;
1709 }
1710 }
1711 }
1712 else
1713 {
1714 /* Our client don't receive graphic updates. Just save the invalid region */
1715 if (!shadow_client_no_surface_update(client, &gfxstatus))
1716 {
1717 WLog_ERR(TAG, "Failed to handle surface update");
1718 break;
1719 }
1720 }
1721
1722 /*
1723 * The return value of shadow_multiclient_consume is whether or not
1724 * the subscriber really consumes the event. It's not cared currently.
1725 */
1726 (void)shadow_multiclient_consume(UpdateSubscriber);
1727 }
1728
1729 if (!peer->CheckFileDescriptor(peer))
1730 {
1731 WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
1732 goto fail;
1733 }
1734 else
1735 {
1736 if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, "drdynvc"))
1737 {
1738 switch (WTSVirtualChannelManagerGetDrdynvcState(client->vcm))
1739 {
1740 /* Dynamic channel status may have been changed after processing */
1741 case DRDYNVC_STATE_NONE:
1742
1743 /* Call this routine to Initialize drdynvc channel */
1744 if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
1745 {
1746 WLog_ERR(TAG, "Failed to initialize drdynvc channel");
1747 goto fail;
1748 }
1749
1750 break;
1751
1752 case DRDYNVC_STATE_READY:
1753 if (client->audin &&
1754 !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
1755 {
1756 if (!IFCALLRESULT(FALSE, client->audin->Open, client->audin))
1757 {
1758 WLog_ERR(TAG, "Failed to initialize audin channel");
1759 goto fail;
1760 }
1761 }
1762
1763 /* Init RDPGFX dynamic channel */
1764 if (settings->SupportGraphicsPipeline && client->rdpgfx &&
1765 !gfxstatus.gfxOpened)
1766 {
1767 client->rdpgfx->FrameAcknowledge =
1768 shadow_client_rdpgfx_frame_acknowledge;
1769 client->rdpgfx->CapsAdvertise = shadow_client_rdpgfx_caps_advertise;
1770
1771 if (!client->rdpgfx->Open(client->rdpgfx))
1772 {
1773 WLog_WARN(TAG, "Failed to open GraphicsPipeline");
1774 settings->SupportGraphicsPipeline = FALSE;
1775 }
1776
1777 gfxstatus.gfxOpened = TRUE;
1778 WLog_INFO(TAG, "Gfx Pipeline Opened");
1779 }
1780
1781 break;
1782
1783 default:
1784 break;
1785 }
1786 }
1787 }
1788
1789 if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
1790 {
1791 if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
1792 {
1793 WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure");
1794 goto fail;
1795 }
1796 }
1797
1798 if (WaitForSingleObject(MessageQueue_Event(MsgQueue), 0) == WAIT_OBJECT_0)
1799 {
1800 /* Drain messages. Pointer update could be accumulated. */
1801 pointerPositionMsg.id = 0;
1802 pointerPositionMsg.Free = NULL;
1803 pointerAlphaMsg.id = 0;
1804 pointerAlphaMsg.Free = NULL;
1805 audioVolumeMsg.id = 0;
1806 audioVolumeMsg.Free = NULL;
1807
1808 while (MessageQueue_Peek(MsgQueue, &message, TRUE))
1809 {
1810 if (message.id == WMQ_QUIT)
1811 {
1812 break;
1813 }
1814
1815 switch (message.id)
1816 {
1817 case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
1818 /* Abandon previous message */
1819 shadow_client_free_queued_message(&pointerPositionMsg);
1820 CopyMemory(&pointerPositionMsg, &message, sizeof(wMessage));
1821 break;
1822
1823 case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
1824 /* Abandon previous message */
1825 shadow_client_free_queued_message(&pointerAlphaMsg);
1826 CopyMemory(&pointerAlphaMsg, &message, sizeof(wMessage));
1827 break;
1828
1829 case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
1830 /* Abandon previous message */
1831 shadow_client_free_queued_message(&audioVolumeMsg);
1832 CopyMemory(&audioVolumeMsg, &message, sizeof(wMessage));
1833 break;
1834
1835 default:
1836 shadow_client_subsystem_process_message(client, &message);
1837 break;
1838 }
1839 }
1840
1841 if (message.id == WMQ_QUIT)
1842 {
1843 /* Release stored message */
1844 shadow_client_free_queued_message(&pointerPositionMsg);
1845 shadow_client_free_queued_message(&pointerAlphaMsg);
1846 shadow_client_free_queued_message(&audioVolumeMsg);
1847 goto fail;
1848 }
1849 else
1850 {
1851 /* Process accumulated messages if needed */
1852 if (pointerPositionMsg.id)
1853 {
1854 shadow_client_subsystem_process_message(client, &pointerPositionMsg);
1855 }
1856
1857 if (pointerAlphaMsg.id)
1858 {
1859 shadow_client_subsystem_process_message(client, &pointerAlphaMsg);
1860 }
1861
1862 if (audioVolumeMsg.id)
1863 {
1864 shadow_client_subsystem_process_message(client, &audioVolumeMsg);
1865 }
1866 }
1867 }
1868 }
1869
1870 fail:
1871
1872 /* Free channels early because we establish channels in post connect */
1873 if (client->audin && !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
1874 {
1875 if (!IFCALLRESULT(FALSE, client->audin->Close, client->audin))
1876 {
1877 WLog_WARN(TAG, "AUDIN shutdown failure!");
1878 }
1879 }
1880
1881 if (gfxstatus.gfxOpened)
1882 {
1883 if (gfxstatus.gfxSurfaceCreated)
1884 {
1885 if (!shadow_client_rdpgfx_release_surface(client))
1886 WLog_WARN(TAG, "GFX release surface failure!");
1887 }
1888
1889 (void)client->rdpgfx->Close(client->rdpgfx);
1890 }
1891
1892 shadow_client_channels_free(client);
1893
1894 if (UpdateSubscriber)
1895 {
1896 shadow_multiclient_release_subscriber(UpdateSubscriber);
1897 UpdateSubscriber = NULL;
1898 }
1899
1900 if (peer->connected && subsystem->ClientDisconnect)
1901 {
1902 subsystem->ClientDisconnect(subsystem, client);
1903 }
1904
1905 out:
1906 peer->Disconnect(peer);
1907 freerdp_peer_context_free(peer);
1908 freerdp_peer_free(peer);
1909 ExitThread(0);
1910 return 0;
1911 }
1912
shadow_client_accepted(freerdp_listener * listener,freerdp_peer * peer)1913 BOOL shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
1914 {
1915 rdpShadowClient* client;
1916 rdpShadowServer* server;
1917
1918 if (!listener || !peer)
1919 return FALSE;
1920
1921 server = (rdpShadowServer*)listener->info;
1922 peer->ContextExtra = (void*)server;
1923 peer->ContextSize = sizeof(rdpShadowClient);
1924 peer->ContextNew = (psPeerContextNew)shadow_client_context_new;
1925 peer->ContextFree = (psPeerContextFree)shadow_client_context_free;
1926 peer->settings = freerdp_settings_clone(server->settings);
1927
1928 if (!freerdp_peer_context_new(peer))
1929 return FALSE;
1930
1931 client = (rdpShadowClient*)peer->context;
1932
1933 if (!(client->thread = CreateThread(NULL, 0, shadow_client_thread, client, 0, NULL)))
1934 {
1935 freerdp_peer_context_free(peer);
1936 return FALSE;
1937 }
1938 else
1939 {
1940 /* Close the thread handle to make it detached. */
1941 CloseHandle(client->thread);
1942 client->thread = NULL;
1943 }
1944
1945 return TRUE;
1946 }
1947
shadow_msg_out_addref(wMessage * message)1948 static void shadow_msg_out_addref(wMessage* message)
1949 {
1950 SHADOW_MSG_OUT* msg = (SHADOW_MSG_OUT*)message->wParam;
1951 InterlockedIncrement(&(msg->refCount));
1952 }
1953
shadow_msg_out_release(wMessage * message)1954 static void shadow_msg_out_release(wMessage* message)
1955 {
1956 SHADOW_MSG_OUT* msg = (SHADOW_MSG_OUT*)message->wParam;
1957
1958 if (InterlockedDecrement(&(msg->refCount)) <= 0)
1959 {
1960 if (msg->Free)
1961 msg->Free(message->id, msg);
1962 }
1963 }
1964
shadow_client_dispatch_msg(rdpShadowClient * client,wMessage * message)1965 static BOOL shadow_client_dispatch_msg(rdpShadowClient* client, wMessage* message)
1966 {
1967 if (!client || !message)
1968 return FALSE;
1969
1970 /* Add reference when it is posted */
1971 shadow_msg_out_addref(message);
1972
1973 if (MessageQueue_Dispatch(client->MsgQueue, message))
1974 return TRUE;
1975 else
1976 {
1977 /* Release the reference since post failed */
1978 shadow_msg_out_release(message);
1979 return FALSE;
1980 }
1981 }
1982
shadow_client_post_msg(rdpShadowClient * client,void * context,UINT32 type,SHADOW_MSG_OUT * msg,void * lParam)1983 BOOL shadow_client_post_msg(rdpShadowClient* client, void* context, UINT32 type,
1984 SHADOW_MSG_OUT* msg, void* lParam)
1985 {
1986 wMessage message = { 0 };
1987 message.context = context;
1988 message.id = type;
1989 message.wParam = (void*)msg;
1990 message.lParam = lParam;
1991 message.Free = shadow_msg_out_release;
1992 return shadow_client_dispatch_msg(client, &message);
1993 }
1994
shadow_client_boardcast_msg(rdpShadowServer * server,void * context,UINT32 type,SHADOW_MSG_OUT * msg,void * lParam)1995 int shadow_client_boardcast_msg(rdpShadowServer* server, void* context, UINT32 type,
1996 SHADOW_MSG_OUT* msg, void* lParam)
1997 {
1998 wMessage message = { 0 };
1999 rdpShadowClient* client = NULL;
2000 int count = 0;
2001 int index = 0;
2002 message.context = context;
2003 message.id = type;
2004 message.wParam = (void*)msg;
2005 message.lParam = lParam;
2006 message.Free = shadow_msg_out_release;
2007 /* First add reference as we reference it in this function.
2008 * Therefore it would not be free'ed during post. */
2009 shadow_msg_out_addref(&message);
2010 ArrayList_Lock(server->clients);
2011
2012 for (index = 0; index < ArrayList_Count(server->clients); index++)
2013 {
2014 client = (rdpShadowClient*)ArrayList_GetItem(server->clients, index);
2015
2016 if (shadow_client_dispatch_msg(client, &message))
2017 {
2018 count++;
2019 }
2020 }
2021
2022 ArrayList_Unlock(server->clients);
2023 /* Release the reference for this function */
2024 shadow_msg_out_release(&message);
2025 return count;
2026 }
2027
shadow_client_boardcast_quit(rdpShadowServer * server,int nExitCode)2028 int shadow_client_boardcast_quit(rdpShadowServer* server, int nExitCode)
2029 {
2030 wMessageQueue* queue = NULL;
2031 int count = 0;
2032 int index = 0;
2033 ArrayList_Lock(server->clients);
2034
2035 for (index = 0; index < ArrayList_Count(server->clients); index++)
2036 {
2037 queue = ((rdpShadowClient*)ArrayList_GetItem(server->clients, index))->MsgQueue;
2038
2039 if (MessageQueue_PostQuit(queue, nExitCode))
2040 {
2041 count++;
2042 }
2043 }
2044
2045 ArrayList_Unlock(server->clients);
2046 return count;
2047 }
2048