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;
54 settings->RdpSecurity = TRUE;
55 settings->TlsSecurity = TRUE;
56 settings->NlaSecurity = FALSE;
58 settings->CertificateFile = _strdup(server->CertificateFile);
59 settings->PrivateKeyFile = _strdup(server->PrivateKeyFile);
61 settings->RdpKeyFile = _strdup(settings->PrivateKeyFile);
63 client->inLobby = TRUE;
64 client->mayView = server->mayView;
65 client->mayInteract = server->mayInteract;
67 InitializeCriticalSectionAndSpinCount(&(client->lock), 4000);
69 region16_init(&(client->invalidRegion));
71 client->vcm = WTSOpenServerA((LPSTR) peer->context);
73 client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
75 client->encoder = shadow_encoder_new(client);
77 ArrayList_Add(server->clients, (void*) client);
80 void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
82 rdpShadowServer* server = client->server;
84 ArrayList_Remove(server->clients, (void*) client);
86 DeleteCriticalSection(&(client->lock));
88 region16_uninit(&(client->invalidRegion));
90 WTSCloseServer((HANDLE) client->vcm);
92 CloseHandle(client->StopEvent);
96 shadow_surface_free(client->lobby);
102 shadow_encoder_free(client->encoder);
103 client->encoder = NULL;
107 void shadow_client_message_free(wMessage* message)
109 if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID)
111 SHADOW_MSG_IN_REFRESH_OUTPUT* wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam;
116 else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID)
118 SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam;
123 BOOL shadow_client_capabilities(freerdp_peer* peer)
128 BOOL shadow_client_post_connect(freerdp_peer* peer)
131 rdpSettings* settings;
132 rdpShadowClient* client;
133 rdpShadowSurface* lobby;
134 rdpShadowServer* server;
135 RECTANGLE_16 invalidRect;
137 client = (rdpShadowClient*) peer->context;
138 settings = peer->settings;
139 server = client->server;
141 if (!server->shareSubRect)
143 width = server->screen->width;
144 height = server->screen->height;
148 width = server->subRect.right - server->subRect.left;
149 height = server->subRect.bottom - server->subRect.top;
152 settings->DesktopWidth = width;
153 settings->DesktopHeight = height;
155 if (settings->ColorDepth == 24)
156 settings->ColorDepth = 16; /* disable 24bpp */
158 WLog_ERR(TAG, "Client from %s is activated (%dx%d@%d)",
159 peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth);
161 peer->update->DesktopResize(peer->update->context);
163 shadow_client_channels_post_connect(client);
165 invalidRect.left = 0;
167 invalidRect.right = width;
168 invalidRect.bottom = height;
170 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &invalidRect);
172 lobby = client->lobby = shadow_surface_new(client->server, 0, 0, width, height);
177 freerdp_image_fill(lobby->data, PIXEL_FORMAT_XRGB32, lobby->scanline,
178 0, 0, lobby->width, lobby->height, 0x3BB9FF);
180 region16_union_rect(&(lobby->invalidRegion), &(lobby->invalidRegion), &invalidRect);
185 void shadow_client_refresh_rect(rdpShadowClient* client, BYTE count, RECTANGLE_16* areas)
187 wMessage message = { 0 };
188 SHADOW_MSG_IN_REFRESH_OUTPUT* wParam;
189 wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
191 wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_REFRESH_OUTPUT));
196 wParam->numRects = (UINT32) count;
198 if (wParam->numRects)
200 wParam->rects = (RECTANGLE_16*) calloc(wParam->numRects, sizeof(RECTANGLE_16));
206 CopyMemory(wParam->rects, areas, wParam->numRects * sizeof(RECTANGLE_16));
208 message.id = SHADOW_MSG_IN_REFRESH_OUTPUT_ID;
209 message.wParam = (void*) wParam;
210 message.lParam = NULL;
211 message.context = (void*) client;
212 message.Free = shadow_client_message_free;
214 MessageQueue_Dispatch(MsgPipe->In, &message);
217 void shadow_client_suppress_output(rdpShadowClient* client, BYTE allow, RECTANGLE_16* area)
219 wMessage message = { 0 };
220 SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam;
221 wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
223 wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_SUPPRESS_OUTPUT));
228 wParam->allow = (UINT32) allow;
231 CopyMemory(&(wParam->rect), area, sizeof(RECTANGLE_16));
233 message.id = SHADOW_MSG_IN_SUPPRESS_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 BOOL shadow_client_activate(freerdp_peer* peer)
244 rdpShadowClient* client;
246 client = (rdpShadowClient*) peer->context;
248 client->activated = TRUE;
249 client->inLobby = client->mayView ? FALSE : TRUE;
251 shadow_encoder_reset(client->encoder);
253 shadow_client_refresh_rect(client, 0, NULL);
258 void shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 frameId)
260 SURFACE_FRAME* frame;
261 wListDictionary* frameList;
263 frameList = client->encoder->frameList;
264 frame = (SURFACE_FRAME*) ListDictionary_GetItemValue(frameList, (void*) (size_t) frameId);
268 ListDictionary_Remove(frameList, (void*) (size_t) frameId);
273 int shadow_client_send_surface_frame_marker(rdpShadowClient* client, UINT32 action, UINT32 id)
275 SURFACE_FRAME_MARKER surfaceFrameMarker;
276 rdpContext* context = (rdpContext*) client;
277 rdpUpdate* update = context->update;
279 surfaceFrameMarker.frameAction = action;
280 surfaceFrameMarker.frameId = id;
282 IFCALL(update->SurfaceFrameMarker, context, &surfaceFrameMarker);
287 int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight)
299 rdpSettings* settings;
300 rdpShadowServer* server;
301 rdpShadowEncoder* encoder;
302 SURFACE_BITS_COMMAND cmd;
304 context = (rdpContext*) client;
305 update = context->update;
306 settings = context->settings;
308 server = client->server;
309 encoder = client->encoder;
311 pSrcData = surface->data;
312 nSrcStep = surface->scanline;
314 if (server->shareSubRect)
317 int subWidth, subHeight;
319 subX = server->subRect.left;
320 subY = server->subRect.top;
321 subWidth = server->subRect.right - server->subRect.left;
322 subHeight = server->subRect.bottom - server->subRect.top;
326 pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)];
329 if (encoder->frameAck)
330 frameId = (UINT32) shadow_encoder_create_frame_id(encoder);
332 if (settings->RemoteFxCodec)
335 RFX_MESSAGE* messages;
342 rect.height = nHeight;
344 messages = rfx_encode_messages(encoder->rfx, &rect, 1, pSrcData,
345 surface->width, surface->height, nSrcStep, &numMessages,
346 settings->MultifragMaxRequestSize);
348 cmd.codecID = settings->RemoteFxCodecId;
352 cmd.destRight = surface->width;
353 cmd.destBottom = surface->height;
356 cmd.width = surface->width;
357 cmd.height = surface->height;
359 for (i = 0; i < numMessages; i++)
361 Stream_SetPosition(s, 0);
362 rfx_write_message(encoder->rfx, s, &messages[i]);
363 rfx_message_free(encoder->rfx, &messages[i]);
365 cmd.bitmapDataLength = Stream_GetPosition(s);
366 cmd.bitmapData = Stream_Buffer(s);
368 first = (i == 0) ? TRUE : FALSE;
369 last = ((i + 1) == numMessages) ? TRUE : FALSE;
371 if (!encoder->frameAck)
372 IFCALL(update->SurfaceBits, update->context, &cmd);
374 IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId);
379 else if (settings->NSCodec)
381 NSC_MESSAGE* messages;
385 messages = nsc_encode_messages(encoder->nsc, pSrcData,
386 nXSrc, nYSrc, nWidth, nHeight, nSrcStep,
387 &numMessages, settings->MultifragMaxRequestSize);
390 cmd.codecID = settings->NSCodecId;
392 for (i = 0; i < numMessages; i++)
394 Stream_SetPosition(s, 0);
396 nsc_write_message(encoder->nsc, s, &messages[i]);
397 nsc_message_free(encoder->nsc, &messages[i]);
399 cmd.destLeft = messages[i].x;
400 cmd.destTop = messages[i].y;
401 cmd.destRight = messages[i].x + messages[i].width;
402 cmd.destBottom = messages[i].y + messages[i].height;
403 cmd.width = messages[i].width;
404 cmd.height = messages[i].height;
406 cmd.bitmapDataLength = Stream_GetPosition(s);
407 cmd.bitmapData = Stream_Buffer(s);
409 first = (i == 0) ? TRUE : FALSE;
410 last = ((i + 1) == numMessages) ? TRUE : FALSE;
412 if (!encoder->frameAck)
413 IFCALL(update->SurfaceBits, update->context, &cmd);
415 IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId);
424 int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight)
437 rdpSettings* settings;
440 BITMAP_DATA* bitmapData;
441 BITMAP_UPDATE bitmapUpdate;
442 rdpShadowServer* server;
443 rdpShadowEncoder* encoder;
445 context = (rdpContext*) client;
446 update = context->update;
447 settings = context->settings;
449 server = client->server;
450 encoder = client->encoder;
452 pSrcData = surface->data;
453 nSrcStep = surface->scanline;
455 MaxRegionWidth = 64 * 4;
456 MaxRegionHeight = 64 * 1;
458 if ((nXSrc % 4) != 0)
460 nWidth += (nXSrc % 4);
461 nXSrc -= (nXSrc % 4);
464 if ((nYSrc % 4) != 0)
466 nHeight += (nYSrc % 4);
467 nYSrc -= (nYSrc % 4);
470 if ((nWidth * nHeight) > (MaxRegionWidth * MaxRegionHeight))
476 rows = (nWidth + (MaxRegionWidth - (nWidth % MaxRegionWidth))) / MaxRegionWidth;
477 cols = (nHeight + (MaxRegionHeight - (nHeight % MaxRegionHeight))) / MaxRegionHeight;
479 for (i = 0; i < rows; i++)
481 for (j = 0; j < cols; j++)
483 nXSrcSub = nXSrc + (i * MaxRegionWidth);
484 nYSrcSub = nYSrc + (j * MaxRegionHeight);
486 nWidthSub = (i < (rows - 1)) ? MaxRegionWidth : nWidth - (i * MaxRegionWidth);
487 nHeightSub = (j < (cols - 1)) ? MaxRegionHeight : nHeight - (j * MaxRegionHeight);
489 if ((nWidthSub * nHeightSub) > 0)
491 shadow_client_send_bitmap_update(client, surface, nXSrcSub, nYSrcSub, nWidthSub, nHeightSub);
499 rows = (nWidth + (64 - (nWidth % 64))) / 64;
500 cols = (nHeight + (64 - (nHeight % 64))) / 64;
503 bitmapUpdate.count = bitmapUpdate.number = rows * cols;
504 bitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * bitmapUpdate.number);
505 bitmapUpdate.rectangles = bitmapData;
510 if ((nWidth % 4) != 0)
512 nXSrc -= (nWidth % 4);
513 nWidth += (nWidth % 4);
516 if ((nHeight % 4) != 0)
518 nYSrc -= (nHeight % 4);
519 nHeight += (nHeight % 4);
522 for (i = 0; i < rows; i++)
524 for (j = 0; j < cols; j++)
526 nWidth = (i < (rows - 1)) ? 64 : nWidth - (i * 64);
527 nHeight = (j < (cols - 1)) ? 64 : nHeight - (j * 64);
529 bitmapData[k].bitsPerPixel = 16;
530 bitmapData[k].width = nWidth;
531 bitmapData[k].height = nHeight;
532 bitmapData[k].destLeft = nXSrc + (i * 64);
533 bitmapData[k].destTop = nYSrc + (j * 64);
534 bitmapData[k].destRight = bitmapData[k].destLeft + nWidth - 1;
535 bitmapData[k].destBottom = bitmapData[k].destTop + nHeight - 1;
536 bitmapData[k].compressed = TRUE;
538 if (((nWidth * nHeight) > 0) && (nWidth >= 4) && (nHeight >= 4))
540 UINT32 srcFormat = PIXEL_FORMAT_RGB32;
550 Stream_SetPosition(s, 0);
551 Stream_SetPosition(ts, 0);
553 data = surface->data;
554 data = &data[(bitmapData[k].destTop * nSrcStep) +
555 (bitmapData[k].destLeft * 4)];
557 srcFormat = PIXEL_FORMAT_RGB32;
559 if (settings->ColorDepth > 24)
563 buffer = encoder->grid[k];
565 buffer = freerdp_bitmap_compress_planar(encoder->planar,
566 data, srcFormat, nWidth, nHeight, nSrcStep, buffer, &dstSize);
568 bitmapData[k].bitmapDataStream = buffer;
569 bitmapData[k].bitmapLength = dstSize;
571 bitmapData[k].bitsPerPixel = 32;
572 bitmapData[k].cbScanWidth = nWidth * 4;
573 bitmapData[k].cbUncompressedSize = nWidth * nHeight * 4;
577 int bytesPerPixel = 2;
578 UINT32 dstFormat = PIXEL_FORMAT_RGB16;
580 if (settings->ColorDepth == 15)
583 dstFormat = PIXEL_FORMAT_RGB15;
585 else if (settings->ColorDepth == 24)
588 dstFormat = PIXEL_FORMAT_XRGB32;
591 buffer = encoder->grid[k];
593 freerdp_image_copy(buffer, dstFormat, -1, 0, 0, nWidth, nHeight,
594 data, srcFormat, nSrcStep, 0, 0, NULL);
596 lines = freerdp_bitmap_compress((char*) buffer, nWidth, nHeight, s,
597 settings->ColorDepth, 64 * 64 * 4, nHeight - 1, ts, e);
599 Stream_SealLength(s);
601 bitmapData[k].bitmapDataStream = Stream_Buffer(s);
602 bitmapData[k].bitmapLength = Stream_Length(s);
604 buffer = encoder->grid[k];
605 CopyMemory(buffer, bitmapData[k].bitmapDataStream, bitmapData[k].bitmapLength);
606 bitmapData[k].bitmapDataStream = buffer;
608 bitmapData[k].bitsPerPixel = settings->ColorDepth;
609 bitmapData[k].cbScanWidth = nWidth * bytesPerPixel;
610 bitmapData[k].cbUncompressedSize = nWidth * nHeight * bytesPerPixel;
613 bitmapData[k].cbCompFirstRowSize = 0;
614 bitmapData[k].cbCompMainBodySize = bitmapData[k].bitmapLength;
621 bitmapUpdate.count = bitmapUpdate.number = k;
623 IFCALL(update->BitmapUpdate, context, &bitmapUpdate);
630 int shadow_client_send_surface_update(rdpShadowClient* client)
636 rdpSettings* settings;
637 rdpShadowServer* server;
638 rdpShadowSurface* surface;
639 rdpShadowEncoder* encoder;
640 REGION16 invalidRegion;
641 RECTANGLE_16 surfaceRect;
642 const RECTANGLE_16* extents;
644 context = (rdpContext*) client;
645 settings = context->settings;
646 server = client->server;
647 encoder = client->encoder;
649 surface = client->inLobby ? client->lobby : server->surface;
651 EnterCriticalSection(&(client->lock));
653 region16_init(&invalidRegion);
654 region16_copy(&invalidRegion, &(client->invalidRegion));
655 region16_clear(&(client->invalidRegion));
657 LeaveCriticalSection(&(client->lock));
659 surfaceRect.left = 0;
661 surfaceRect.right = surface->width;
662 surfaceRect.bottom = surface->height;
664 region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect);
666 if (server->shareSubRect)
668 region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect));
671 if (region16_is_empty(&invalidRegion))
673 region16_uninit(&invalidRegion);
677 extents = region16_extents(&invalidRegion);
679 nXSrc = extents->left - 0;
680 nYSrc = extents->top - 0;
681 nWidth = extents->right - extents->left;
682 nHeight = extents->bottom - extents->top;
684 //WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d bottom: %d",
685 // nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight);
687 if (settings->RemoteFxCodec || settings->NSCodec)
689 if (settings->RemoteFxCodec)
690 shadow_encoder_prepare(encoder, SHADOW_CODEC_REMOTEFX);
691 else if (settings->NSCodec)
692 shadow_encoder_prepare(encoder, SHADOW_CODEC_NSCODEC);
694 status = shadow_client_send_surface_bits(client, surface, nXSrc, nYSrc, nWidth, nHeight);
698 shadow_encoder_prepare(encoder, SHADOW_CODEC_BITMAP);
700 status = shadow_client_send_bitmap_update(client, surface, nXSrc, nYSrc, nWidth, nHeight);
703 region16_uninit(&invalidRegion);
708 int shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
712 const RECTANGLE_16* rects;
714 EnterCriticalSection(&(client->lock));
716 rects = region16_rects(region, &numRects);
718 for (index = 0; index < numRects; index++)
720 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
723 LeaveCriticalSection(&(client->lock));
728 void* shadow_client_thread(rdpShadowClient* client)
739 rdpSettings* settings;
740 rdpShadowServer* server;
741 rdpShadowScreen* screen;
742 rdpShadowEncoder* encoder;
743 rdpShadowSubsystem* subsystem;
745 server = client->server;
746 screen = server->screen;
747 encoder = client->encoder;
748 subsystem = server->subsystem;
750 context = (rdpContext*) client;
751 peer = context->peer;
752 settings = peer->settings;
754 peer->Capabilities = shadow_client_capabilities;
755 peer->PostConnect = shadow_client_post_connect;
756 peer->Activate = shadow_client_activate;
758 shadow_input_register_callbacks(peer->input);
760 peer->Initialize(peer);
762 peer->update->RefreshRect = (pRefreshRect) shadow_client_refresh_rect;
763 peer->update->SuppressOutput = (pSuppressOutput) shadow_client_suppress_output;
764 peer->update->SurfaceFrameAcknowledge = (pSurfaceFrameAcknowledge) shadow_client_surface_frame_acknowledge;
766 StopEvent = client->StopEvent;
767 UpdateEvent = subsystem->updateEvent;
768 ClientEvent = peer->GetEventHandle(peer);
769 ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm);
774 events[nCount++] = StopEvent;
775 events[nCount++] = UpdateEvent;
776 events[nCount++] = ClientEvent;
777 events[nCount++] = ChannelEvent;
779 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
781 if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0)
783 if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
785 EnterSynchronizationBarrier(&(subsystem->barrier), 0);
791 if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
793 if (client->activated)
797 const RECTANGLE_16* rects;
799 rects = region16_rects(&(subsystem->invalidRegion), &numRects);
801 for (index = 0; index < numRects; index++)
803 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
806 shadow_client_send_surface_update(client);
809 EnterSynchronizationBarrier(&(subsystem->barrier), 0);
811 while (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0);
814 if (WaitForSingleObject(ClientEvent, 0) == WAIT_OBJECT_0)
816 if (!peer->CheckFileDescriptor(peer))
818 WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
823 if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
825 if (WTSVirtualChannelManagerCheckFileDescriptor(client->vcm) != TRUE)
827 WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure");
833 peer->Disconnect(peer);
835 freerdp_peer_context_free(peer);
836 freerdp_peer_free(peer);
843 void shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
845 rdpShadowClient* client;
846 rdpShadowServer* server;
848 server = (rdpShadowServer*) listener->info;
850 peer->ContextExtra = (void*) server;
851 peer->ContextSize = sizeof(rdpShadowClient);
852 peer->ContextNew = (psPeerContextNew) shadow_client_context_new;
853 peer->ContextFree = (psPeerContextFree) shadow_client_context_free;
854 freerdp_peer_context_new(peer);
856 client = (rdpShadowClient*) peer->context;
858 client->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
859 shadow_client_thread, client, 0, NULL);