2 * FreeRDP: A Remote Desktop Protocol Implementation
4 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
23 #include <winpr/crt.h>
24 #include <winpr/file.h>
25 #include <winpr/path.h>
26 #include <winpr/synch.h>
27 #include <winpr/thread.h>
28 #include <winpr/sysinfo.h>
30 #include <freerdp/log.h>
34 #define TAG CLIENT_TAG("shadow")
36 void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
38 rdpSettings* settings;
39 rdpShadowServer* server;
41 server = (rdpShadowServer*) peer->ContextExtra;
42 client->server = server;
43 client->subsystem = server->subsystem;
45 settings = peer->settings;
47 settings->ColorDepth = 32;
48 settings->NSCodec = TRUE;
49 settings->RemoteFxCodec = TRUE;
50 settings->BitmapCacheV3Enabled = TRUE;
51 settings->FrameMarkerCommandEnabled = TRUE;
52 settings->SurfaceFrameMarkerEnabled = TRUE;
53 settings->SupportGraphicsPipeline = FALSE;
55 settings->DrawAllowSkipAlpha = TRUE;
56 settings->DrawAllowColorSubsampling = TRUE;
57 settings->DrawAllowDynamicColorFidelity = TRUE;
59 settings->RdpSecurity = TRUE;
60 settings->TlsSecurity = TRUE;
61 settings->NlaSecurity = FALSE;
63 settings->CertificateFile = _strdup(server->CertificateFile);
64 settings->PrivateKeyFile = _strdup(server->PrivateKeyFile);
66 settings->RdpKeyFile = _strdup(settings->PrivateKeyFile);
68 client->inLobby = TRUE;
69 client->mayView = server->mayView;
70 client->mayInteract = server->mayInteract;
72 InitializeCriticalSectionAndSpinCount(&(client->lock), 4000);
74 region16_init(&(client->invalidRegion));
76 client->vcm = WTSOpenServerA((LPSTR) peer->context);
78 client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
80 client->encoder = shadow_encoder_new(client);
82 ArrayList_Add(server->clients, (void*) client);
85 void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
87 rdpShadowServer* server = client->server;
89 ArrayList_Remove(server->clients, (void*) client);
91 DeleteCriticalSection(&(client->lock));
93 region16_uninit(&(client->invalidRegion));
95 WTSCloseServer((HANDLE) client->vcm);
97 CloseHandle(client->StopEvent);
101 shadow_surface_free(client->lobby);
102 client->lobby = NULL;
107 shadow_encoder_free(client->encoder);
108 client->encoder = NULL;
112 void shadow_client_message_free(wMessage* message)
114 if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID)
116 SHADOW_MSG_IN_REFRESH_OUTPUT* wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam;
121 else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID)
123 SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam;
128 BOOL shadow_client_capabilities(freerdp_peer* peer)
133 BOOL shadow_client_post_connect(freerdp_peer* peer)
137 rdpSettings* settings;
138 rdpShadowClient* client;
139 rdpShadowServer* server;
140 RECTANGLE_16 invalidRect;
141 rdpShadowSubsystem* subsystem;
143 client = (rdpShadowClient*) peer->context;
144 settings = peer->settings;
145 server = client->server;
146 subsystem = server->subsystem;
148 if (!server->shareSubRect)
150 width = server->screen->width;
151 height = server->screen->height;
155 width = server->subRect.right - server->subRect.left;
156 height = server->subRect.bottom - server->subRect.top;
159 settings->DesktopWidth = width;
160 settings->DesktopHeight = height;
162 if (settings->ColorDepth == 24)
163 settings->ColorDepth = 16; /* disable 24bpp */
165 if (settings->MultifragMaxRequestSize < 0x3F0000)
166 settings->NSCodec = FALSE; /* NSCodec compressor does not support fragmentation yet */
168 WLog_ERR(TAG, "Client from %s is activated (%dx%d@%d)",
169 peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth);
171 peer->update->DesktopResize(peer->update->context);
173 shadow_client_channels_post_connect(client);
175 invalidRect.left = 0;
177 invalidRect.right = width;
178 invalidRect.bottom = height;
180 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &invalidRect);
182 shadow_client_init_lobby(client);
186 if (settings->Username && settings->Password)
187 settings->AutoLogonEnabled = TRUE;
189 if (settings->AutoLogonEnabled && server->authentication)
191 if (subsystem->Authenticate)
193 authStatus = subsystem->Authenticate(subsystem,
194 settings->Username, settings->Domain, settings->Password);
198 if (server->authentication)
202 WLog_ERR(TAG, "client authentication failure: %d", authStatus);
210 void shadow_client_refresh_rect(rdpShadowClient* client, BYTE count, RECTANGLE_16* areas)
212 wMessage message = { 0 };
213 SHADOW_MSG_IN_REFRESH_OUTPUT* wParam;
214 wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
216 wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_REFRESH_OUTPUT));
221 wParam->numRects = (UINT32) count;
223 if (wParam->numRects)
225 wParam->rects = (RECTANGLE_16*) calloc(wParam->numRects, sizeof(RECTANGLE_16));
231 CopyMemory(wParam->rects, areas, wParam->numRects * sizeof(RECTANGLE_16));
233 message.id = SHADOW_MSG_IN_REFRESH_OUTPUT_ID;
234 message.wParam = (void*) wParam;
235 message.lParam = NULL;
236 message.context = (void*) client;
237 message.Free = shadow_client_message_free;
239 MessageQueue_Dispatch(MsgPipe->In, &message);
242 void shadow_client_suppress_output(rdpShadowClient* client, BYTE allow, RECTANGLE_16* area)
244 wMessage message = { 0 };
245 SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam;
246 wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
248 wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_SUPPRESS_OUTPUT));
253 wParam->allow = (UINT32) allow;
256 CopyMemory(&(wParam->rect), area, sizeof(RECTANGLE_16));
258 message.id = SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID;
259 message.wParam = (void*) wParam;
260 message.lParam = NULL;
261 message.context = (void*) client;
262 message.Free = shadow_client_message_free;
264 MessageQueue_Dispatch(MsgPipe->In, &message);
267 BOOL shadow_client_activate(freerdp_peer* peer)
269 rdpSettings* settings = peer->settings;
270 rdpShadowClient* client = (rdpShadowClient*) peer->context;
272 if (strcmp(settings->ClientDir, "librdp") == 0)
274 /* Hack for Mac/iOS/Android Microsoft RDP clients */
276 settings->RemoteFxCodec = FALSE;
278 settings->NSCodec = FALSE;
279 settings->NSCodecAllowSubsampling = FALSE;
281 settings->SurfaceFrameMarkerEnabled = FALSE;
284 client->activated = TRUE;
285 client->inLobby = client->mayView ? FALSE : TRUE;
287 shadow_encoder_reset(client->encoder);
289 shadow_client_refresh_rect(client, 0, NULL);
294 void shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 frameId)
296 SURFACE_FRAME* frame;
297 wListDictionary* frameList;
299 frameList = client->encoder->frameList;
300 frame = (SURFACE_FRAME*) ListDictionary_GetItemValue(frameList, (void*) (size_t) frameId);
304 ListDictionary_Remove(frameList, (void*) (size_t) frameId);
309 int shadow_client_send_surface_frame_marker(rdpShadowClient* client, UINT32 action, UINT32 id)
311 SURFACE_FRAME_MARKER surfaceFrameMarker;
312 rdpContext* context = (rdpContext*) client;
313 rdpUpdate* update = context->update;
315 surfaceFrameMarker.frameAction = action;
316 surfaceFrameMarker.frameId = id;
318 IFCALL(update->SurfaceFrameMarker, context, &surfaceFrameMarker);
323 int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight)
335 rdpSettings* settings;
336 rdpShadowServer* server;
337 rdpShadowEncoder* encoder;
338 SURFACE_BITS_COMMAND cmd;
340 context = (rdpContext*) client;
341 update = context->update;
342 settings = context->settings;
344 server = client->server;
345 encoder = client->encoder;
347 pSrcData = surface->data;
348 nSrcStep = surface->scanline;
350 if (server->shareSubRect)
353 int subWidth, subHeight;
355 subX = server->subRect.left;
356 subY = server->subRect.top;
357 subWidth = server->subRect.right - server->subRect.left;
358 subHeight = server->subRect.bottom - server->subRect.top;
362 pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)];
365 if (encoder->frameAck)
366 frameId = (UINT32) shadow_encoder_create_frame_id(encoder);
368 if (settings->RemoteFxCodec)
371 RFX_MESSAGE* messages;
373 shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX);
380 rect.height = nHeight;
382 messages = rfx_encode_messages(encoder->rfx, &rect, 1, pSrcData,
383 surface->width, surface->height, nSrcStep, &numMessages,
384 settings->MultifragMaxRequestSize);
386 cmd.codecID = settings->RemoteFxCodecId;
390 cmd.destRight = surface->width;
391 cmd.destBottom = surface->height;
394 cmd.width = surface->width;
395 cmd.height = surface->height;
397 for (i = 0; i < numMessages; i++)
399 Stream_SetPosition(s, 0);
400 rfx_write_message(encoder->rfx, s, &messages[i]);
401 rfx_message_free(encoder->rfx, &messages[i]);
403 cmd.bitmapDataLength = Stream_GetPosition(s);
404 cmd.bitmapData = Stream_Buffer(s);
406 first = (i == 0) ? TRUE : FALSE;
407 last = ((i + 1) == numMessages) ? TRUE : FALSE;
409 if (!encoder->frameAck)
410 IFCALL(update->SurfaceBits, update->context, &cmd);
412 IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId);
417 else if (settings->NSCodec)
419 shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC);
422 Stream_SetPosition(s, 0);
424 pSrcData = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
426 nsc_compose_message(encoder->nsc, s, pSrcData, nWidth, nHeight, nSrcStep);
429 cmd.codecID = settings->NSCodecId;
430 cmd.destLeft = nXSrc;
432 cmd.destRight = cmd.destLeft + nWidth;
433 cmd.destBottom = cmd.destTop + nHeight;
435 cmd.height = nHeight;
437 cmd.bitmapDataLength = Stream_GetPosition(s);
438 cmd.bitmapData = Stream_Buffer(s);
443 if (!encoder->frameAck)
444 IFCALL(update->SurfaceBits, update->context, &cmd);
446 IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId);
452 int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight)
465 rdpSettings* settings;
466 UINT32 maxUpdateSize;
467 UINT32 totalBitmapSize;
468 UINT32 updateSizeEstimate;
469 BITMAP_DATA* bitmapData;
470 BITMAP_UPDATE bitmapUpdate;
471 rdpShadowServer* server;
472 rdpShadowEncoder* encoder;
474 context = (rdpContext*) client;
475 update = context->update;
476 settings = context->settings;
478 server = client->server;
479 encoder = client->encoder;
481 maxUpdateSize = settings->MultifragMaxRequestSize;
483 if (settings->ColorDepth < 32)
484 shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED);
486 shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR);
488 pSrcData = surface->data;
489 nSrcStep = surface->scanline;
490 SrcFormat = PIXEL_FORMAT_RGB32;
492 if ((nXSrc % 4) != 0)
494 nWidth += (nXSrc % 4);
495 nXSrc -= (nXSrc % 4);
498 if ((nYSrc % 4) != 0)
500 nHeight += (nYSrc % 4);
501 nYSrc -= (nYSrc % 4);
504 rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0);
505 cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0);
510 bitmapUpdate.count = bitmapUpdate.number = rows * cols;
511 bitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * bitmapUpdate.number);
512 bitmapUpdate.rectangles = bitmapData;
517 if ((nWidth % 4) != 0)
519 nXSrc -= (nWidth % 4);
520 nWidth += (nWidth % 4);
523 if ((nHeight % 4) != 0)
525 nYSrc -= (nHeight % 4);
526 nHeight += (nHeight % 4);
529 for (yIdx = 0; yIdx < rows; yIdx++)
531 for (xIdx = 0; xIdx < cols; xIdx++)
533 bitmap = &bitmapData[k];
537 bitmap->destLeft = nXSrc + (xIdx * 64);
538 bitmap->destTop = nYSrc + (yIdx * 64);
540 if ((bitmap->destLeft + bitmap->width) > (nXSrc + nWidth))
541 bitmap->width = (nXSrc + nWidth) - bitmap->destLeft;
543 if ((bitmap->destTop + bitmap->height) > (nYSrc + nHeight))
544 bitmap->height = (nYSrc + nHeight) - bitmap->destTop;
546 bitmap->destRight = bitmap->destLeft + bitmap->width - 1;
547 bitmap->destBottom = bitmap->destTop + bitmap->height - 1;
548 bitmap->compressed = TRUE;
550 if ((bitmap->width < 4) || (bitmap->height < 4))
553 if (settings->ColorDepth < 32)
555 int bitsPerPixel = settings->ColorDepth;
556 int bytesPerPixel = (bitsPerPixel + 7) / 8;
558 DstSize = 64 * 64 * 4;
559 buffer = encoder->grid[k];
561 interleaved_compress(encoder->interleaved, buffer, &DstSize, bitmap->width, bitmap->height,
562 pSrcData, SrcFormat, nSrcStep, bitmap->destLeft, bitmap->destTop, NULL, bitsPerPixel);
564 bitmap->bitmapDataStream = buffer;
565 bitmap->bitmapLength = DstSize;
566 bitmap->bitsPerPixel = bitsPerPixel;
567 bitmap->cbScanWidth = bitmap->width * bytesPerPixel;
568 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel;
574 buffer = encoder->grid[k];
575 data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)];
577 buffer = freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat,
578 bitmap->width, bitmap->height, nSrcStep, buffer, &dstSize);
580 bitmap->bitmapDataStream = buffer;
581 bitmap->bitmapLength = dstSize;
582 bitmap->bitsPerPixel = 32;
583 bitmap->cbScanWidth = bitmap->width * 4;
584 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4;
587 bitmap->cbCompFirstRowSize = 0;
588 bitmap->cbCompMainBodySize = bitmap->bitmapLength;
590 totalBitmapSize += bitmap->bitmapLength;
595 bitmapUpdate.count = bitmapUpdate.number = k;
597 updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.count) + 16;
599 if (updateSizeEstimate > maxUpdateSize)
603 UINT32 newUpdateSize;
604 BITMAP_DATA* fragBitmapData;
606 fragBitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * k);
607 bitmapUpdate.rectangles = fragBitmapData;
614 newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16);
616 if ((newUpdateSize < maxUpdateSize) && ((i + 1) < k))
618 CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA));
619 updateSize = newUpdateSize;
625 CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA));
626 updateSize = newUpdateSize;
629 bitmapUpdate.count = bitmapUpdate.number = j;
630 IFCALL(update->BitmapUpdate, context, &bitmapUpdate);
636 free(fragBitmapData);
640 IFCALL(update->BitmapUpdate, context, &bitmapUpdate);
648 int shadow_client_send_surface_update(rdpShadowClient* client)
654 rdpSettings* settings;
655 rdpShadowServer* server;
656 rdpShadowSurface* surface;
657 rdpShadowEncoder* encoder;
658 REGION16 invalidRegion;
659 RECTANGLE_16 surfaceRect;
660 const RECTANGLE_16* extents;
662 context = (rdpContext*) client;
663 settings = context->settings;
664 server = client->server;
665 encoder = client->encoder;
667 surface = client->inLobby ? client->lobby : server->surface;
669 EnterCriticalSection(&(client->lock));
671 region16_init(&invalidRegion);
672 region16_copy(&invalidRegion, &(client->invalidRegion));
673 region16_clear(&(client->invalidRegion));
675 LeaveCriticalSection(&(client->lock));
677 surfaceRect.left = 0;
679 surfaceRect.right = surface->width;
680 surfaceRect.bottom = surface->height;
682 region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect);
684 if (server->shareSubRect)
686 region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect));
689 if (region16_is_empty(&invalidRegion))
691 region16_uninit(&invalidRegion);
695 extents = region16_extents(&invalidRegion);
697 nXSrc = extents->left - 0;
698 nYSrc = extents->top - 0;
699 nWidth = extents->right - extents->left;
700 nHeight = extents->bottom - extents->top;
702 //WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d bottom: %d",
703 // nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight);
705 if (settings->RemoteFxCodec || settings->NSCodec)
707 status = shadow_client_send_surface_bits(client, surface, nXSrc, nYSrc, nWidth, nHeight);
711 status = shadow_client_send_bitmap_update(client, surface, nXSrc, nYSrc, nWidth, nHeight);
714 region16_uninit(&invalidRegion);
719 int shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
723 const RECTANGLE_16* rects;
725 EnterCriticalSection(&(client->lock));
727 rects = region16_rects(region, &numRects);
729 for (index = 0; index < numRects; index++)
731 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
734 LeaveCriticalSection(&(client->lock));
739 void* shadow_client_thread(rdpShadowClient* client)
750 rdpSettings* settings;
751 rdpShadowServer* server;
752 rdpShadowScreen* screen;
753 rdpShadowEncoder* encoder;
754 rdpShadowSubsystem* subsystem;
756 server = client->server;
757 screen = server->screen;
758 encoder = client->encoder;
759 subsystem = server->subsystem;
761 context = (rdpContext*) client;
762 peer = context->peer;
763 settings = peer->settings;
765 peer->Capabilities = shadow_client_capabilities;
766 peer->PostConnect = shadow_client_post_connect;
767 peer->Activate = shadow_client_activate;
769 shadow_input_register_callbacks(peer->input);
771 peer->Initialize(peer);
773 peer->update->RefreshRect = (pRefreshRect) shadow_client_refresh_rect;
774 peer->update->SuppressOutput = (pSuppressOutput) shadow_client_suppress_output;
775 peer->update->SurfaceFrameAcknowledge = (pSurfaceFrameAcknowledge) shadow_client_surface_frame_acknowledge;
777 StopEvent = client->StopEvent;
778 UpdateEvent = subsystem->updateEvent;
779 ClientEvent = peer->GetEventHandle(peer);
780 ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm);
785 events[nCount++] = StopEvent;
786 events[nCount++] = UpdateEvent;
787 events[nCount++] = ClientEvent;
788 events[nCount++] = ChannelEvent;
790 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
792 if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0)
794 if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
796 EnterSynchronizationBarrier(&(subsystem->barrier), 0);
802 if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
804 if (client->activated)
808 const RECTANGLE_16* rects;
810 rects = region16_rects(&(subsystem->invalidRegion), &numRects);
812 for (index = 0; index < numRects; index++)
814 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
817 shadow_client_send_surface_update(client);
820 EnterSynchronizationBarrier(&(subsystem->barrier), 0);
822 while (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0);
825 if (WaitForSingleObject(ClientEvent, 0) == WAIT_OBJECT_0)
827 if (!peer->CheckFileDescriptor(peer))
829 WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
834 if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
836 if (WTSVirtualChannelManagerCheckFileDescriptor(client->vcm) != TRUE)
838 WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure");
844 peer->Disconnect(peer);
846 freerdp_peer_context_free(peer);
847 freerdp_peer_free(peer);
854 void shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
856 rdpShadowClient* client;
857 rdpShadowServer* server;
859 server = (rdpShadowServer*) listener->info;
861 peer->ContextExtra = (void*) server;
862 peer->ContextSize = sizeof(rdpShadowClient);
863 peer->ContextNew = (psPeerContextNew) shadow_client_context_new;
864 peer->ContextFree = (psPeerContextFree) shadow_client_context_free;
865 freerdp_peer_context_new(peer);
867 client = (rdpShadowClient*) peer->context;
869 client->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
870 shadow_client_thread, client, 0, NULL);