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 extern rdpShadowFont* g_Font;
38 void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
40 rdpSettings* settings;
41 rdpShadowServer* server;
43 server = (rdpShadowServer*) peer->ContextExtra;
44 client->server = server;
45 client->subsystem = server->subsystem;
47 settings = peer->settings;
49 settings->ColorDepth = 32;
50 settings->NSCodec = TRUE;
51 settings->RemoteFxCodec = TRUE;
52 settings->BitmapCacheV3Enabled = TRUE;
53 settings->FrameMarkerCommandEnabled = TRUE;
54 settings->SurfaceFrameMarkerEnabled = TRUE;
55 settings->SupportGraphicsPipeline = FALSE;
57 settings->DrawAllowSkipAlpha = TRUE;
58 settings->DrawAllowColorSubsampling = TRUE;
59 settings->DrawAllowDynamicColorFidelity = TRUE;
61 settings->RdpSecurity = TRUE;
62 settings->TlsSecurity = TRUE;
63 settings->NlaSecurity = FALSE;
65 settings->CertificateFile = _strdup(server->CertificateFile);
66 settings->PrivateKeyFile = _strdup(server->PrivateKeyFile);
68 settings->RdpKeyFile = _strdup(settings->PrivateKeyFile);
70 client->inLobby = TRUE;
71 client->mayView = server->mayView;
72 client->mayInteract = server->mayInteract;
74 InitializeCriticalSectionAndSpinCount(&(client->lock), 4000);
76 region16_init(&(client->invalidRegion));
78 client->vcm = WTSOpenServerA((LPSTR) peer->context);
80 client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
82 client->encoder = shadow_encoder_new(client);
84 ArrayList_Add(server->clients, (void*) client);
87 void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
89 rdpShadowServer* server = client->server;
91 ArrayList_Remove(server->clients, (void*) client);
93 DeleteCriticalSection(&(client->lock));
95 region16_uninit(&(client->invalidRegion));
97 WTSCloseServer((HANDLE) client->vcm);
99 CloseHandle(client->StopEvent);
103 shadow_surface_free(client->lobby);
104 client->lobby = NULL;
109 shadow_encoder_free(client->encoder);
110 client->encoder = NULL;
114 void shadow_client_message_free(wMessage* message)
116 if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID)
118 SHADOW_MSG_IN_REFRESH_OUTPUT* wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam;
123 else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID)
125 SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam;
130 BOOL shadow_client_capabilities(freerdp_peer* peer)
135 int shadow_client_init_lobby(rdpShadowClient* client)
139 RECTANGLE_16 invalidRect;
140 rdpShadowSurface* lobby;
141 rdpContext* context = (rdpContext*) client;
142 rdpSettings* settings = context->settings;
144 width = settings->DesktopWidth;
145 height = settings->DesktopHeight;
147 lobby = client->lobby = shadow_surface_new(client->server, 0, 0, width, height);
152 freerdp_image_fill(lobby->data, PIXEL_FORMAT_XRGB32, lobby->scanline,
153 0, 0, lobby->width, lobby->height, 0x3BB9FF);
157 shadow_font_draw_text(lobby, 16, 16, g_Font, "Welcome to the shadow server!");
160 invalidRect.left = 0;
162 invalidRect.right = width;
163 invalidRect.bottom = height;
165 region16_union_rect(&(lobby->invalidRegion), &(lobby->invalidRegion), &invalidRect);
170 BOOL shadow_client_post_connect(freerdp_peer* peer)
174 rdpSettings* settings;
175 rdpShadowClient* client;
176 rdpShadowServer* server;
177 RECTANGLE_16 invalidRect;
178 rdpShadowSubsystem* subsystem;
180 client = (rdpShadowClient*) peer->context;
181 settings = peer->settings;
182 server = client->server;
183 subsystem = server->subsystem;
185 if (!server->shareSubRect)
187 width = server->screen->width;
188 height = server->screen->height;
192 width = server->subRect.right - server->subRect.left;
193 height = server->subRect.bottom - server->subRect.top;
196 settings->DesktopWidth = width;
197 settings->DesktopHeight = height;
199 if (settings->ColorDepth == 24)
200 settings->ColorDepth = 16; /* disable 24bpp */
202 WLog_ERR(TAG, "Client from %s is activated (%dx%d@%d)",
203 peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth);
205 peer->update->DesktopResize(peer->update->context);
207 shadow_client_channels_post_connect(client);
209 invalidRect.left = 0;
211 invalidRect.right = width;
212 invalidRect.bottom = height;
214 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &invalidRect);
216 shadow_client_init_lobby(client);
220 if (settings->Username && settings->Password)
221 settings->AutoLogonEnabled = TRUE;
223 if (settings->AutoLogonEnabled && server->authentication)
225 if (subsystem->Authenticate)
227 authStatus = subsystem->Authenticate(subsystem,
228 settings->Username, settings->Domain, settings->Password);
232 if (server->authentication)
236 WLog_ERR(TAG, "client authentication failure: %d", authStatus);
244 void shadow_client_refresh_rect(rdpShadowClient* client, BYTE count, RECTANGLE_16* areas)
246 wMessage message = { 0 };
247 SHADOW_MSG_IN_REFRESH_OUTPUT* wParam;
248 wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
250 wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_REFRESH_OUTPUT));
255 wParam->numRects = (UINT32) count;
257 if (wParam->numRects)
259 wParam->rects = (RECTANGLE_16*) calloc(wParam->numRects, sizeof(RECTANGLE_16));
265 CopyMemory(wParam->rects, areas, wParam->numRects * sizeof(RECTANGLE_16));
267 message.id = SHADOW_MSG_IN_REFRESH_OUTPUT_ID;
268 message.wParam = (void*) wParam;
269 message.lParam = NULL;
270 message.context = (void*) client;
271 message.Free = shadow_client_message_free;
273 MessageQueue_Dispatch(MsgPipe->In, &message);
276 void shadow_client_suppress_output(rdpShadowClient* client, BYTE allow, RECTANGLE_16* area)
278 wMessage message = { 0 };
279 SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam;
280 wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
282 wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_SUPPRESS_OUTPUT));
287 wParam->allow = (UINT32) allow;
290 CopyMemory(&(wParam->rect), area, sizeof(RECTANGLE_16));
292 message.id = SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID;
293 message.wParam = (void*) wParam;
294 message.lParam = NULL;
295 message.context = (void*) client;
296 message.Free = shadow_client_message_free;
298 MessageQueue_Dispatch(MsgPipe->In, &message);
301 BOOL shadow_client_activate(freerdp_peer* peer)
303 rdpSettings* settings = peer->settings;
304 rdpShadowClient* client = (rdpShadowClient*) peer->context;
306 if (strcmp(settings->ClientDir, "librdp") == 0)
308 /* Hack for Mac/iOS/Android Microsoft RDP clients */
310 settings->RemoteFxCodec = FALSE;
312 settings->NSCodec = FALSE;
313 settings->NSCodecAllowSubsampling = FALSE;
315 settings->SurfaceFrameMarkerEnabled = FALSE;
318 client->activated = TRUE;
319 client->inLobby = client->mayView ? FALSE : TRUE;
321 shadow_encoder_reset(client->encoder);
323 shadow_client_refresh_rect(client, 0, NULL);
328 void shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 frameId)
330 SURFACE_FRAME* frame;
331 wListDictionary* frameList;
333 frameList = client->encoder->frameList;
334 frame = (SURFACE_FRAME*) ListDictionary_GetItemValue(frameList, (void*) (size_t) frameId);
338 ListDictionary_Remove(frameList, (void*) (size_t) frameId);
343 int shadow_client_send_surface_frame_marker(rdpShadowClient* client, UINT32 action, UINT32 id)
345 SURFACE_FRAME_MARKER surfaceFrameMarker;
346 rdpContext* context = (rdpContext*) client;
347 rdpUpdate* update = context->update;
349 surfaceFrameMarker.frameAction = action;
350 surfaceFrameMarker.frameId = id;
352 IFCALL(update->SurfaceFrameMarker, context, &surfaceFrameMarker);
357 int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight)
369 rdpSettings* settings;
370 rdpShadowServer* server;
371 rdpShadowEncoder* encoder;
372 SURFACE_BITS_COMMAND cmd;
374 context = (rdpContext*) client;
375 update = context->update;
376 settings = context->settings;
378 server = client->server;
379 encoder = client->encoder;
381 pSrcData = surface->data;
382 nSrcStep = surface->scanline;
384 if (server->shareSubRect)
387 int subWidth, subHeight;
389 subX = server->subRect.left;
390 subY = server->subRect.top;
391 subWidth = server->subRect.right - server->subRect.left;
392 subHeight = server->subRect.bottom - server->subRect.top;
396 pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)];
399 if (encoder->frameAck)
400 frameId = (UINT32) shadow_encoder_create_frame_id(encoder);
402 if (settings->RemoteFxCodec)
405 RFX_MESSAGE* messages;
407 shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX);
414 rect.height = nHeight;
416 messages = rfx_encode_messages(encoder->rfx, &rect, 1, pSrcData,
417 surface->width, surface->height, nSrcStep, &numMessages,
418 settings->MultifragMaxRequestSize);
420 cmd.codecID = settings->RemoteFxCodecId;
424 cmd.destRight = surface->width;
425 cmd.destBottom = surface->height;
428 cmd.width = surface->width;
429 cmd.height = surface->height;
431 for (i = 0; i < numMessages; i++)
433 Stream_SetPosition(s, 0);
434 rfx_write_message(encoder->rfx, s, &messages[i]);
435 rfx_message_free(encoder->rfx, &messages[i]);
437 cmd.bitmapDataLength = Stream_GetPosition(s);
438 cmd.bitmapData = Stream_Buffer(s);
440 first = (i == 0) ? TRUE : FALSE;
441 last = ((i + 1) == numMessages) ? TRUE : FALSE;
443 if (!encoder->frameAck)
444 IFCALL(update->SurfaceBits, update->context, &cmd);
446 IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId);
451 else if (settings->NSCodec)
453 shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC);
456 Stream_SetPosition(s, 0);
458 pSrcData = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
460 nsc_compose_message(encoder->nsc, s, pSrcData, nWidth, nHeight, nSrcStep);
463 cmd.codecID = settings->NSCodecId;
464 cmd.destLeft = nXSrc;
466 cmd.destRight = cmd.destLeft + nWidth;
467 cmd.destBottom = cmd.destTop + nHeight;
469 cmd.height = nHeight;
471 cmd.bitmapDataLength = Stream_GetPosition(s);
472 cmd.bitmapData = Stream_Buffer(s);
477 if (!encoder->frameAck)
478 IFCALL(update->SurfaceBits, update->context, &cmd);
480 IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId);
486 int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight)
499 rdpSettings* settings;
500 UINT32 maxUpdateSize;
501 UINT32 totalBitmapSize;
502 UINT32 updateSizeEstimate;
503 BITMAP_DATA* bitmapData;
504 BITMAP_UPDATE bitmapUpdate;
505 rdpShadowServer* server;
506 rdpShadowEncoder* encoder;
508 context = (rdpContext*) client;
509 update = context->update;
510 settings = context->settings;
512 server = client->server;
513 encoder = client->encoder;
515 maxUpdateSize = settings->MultifragMaxRequestSize;
517 if (settings->ColorDepth < 32)
518 shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED);
520 shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR);
522 pSrcData = surface->data;
523 nSrcStep = surface->scanline;
524 SrcFormat = PIXEL_FORMAT_RGB32;
526 if ((nXSrc % 4) != 0)
528 nWidth += (nXSrc % 4);
529 nXSrc -= (nXSrc % 4);
532 if ((nYSrc % 4) != 0)
534 nHeight += (nYSrc % 4);
535 nYSrc -= (nYSrc % 4);
538 rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0);
539 cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0);
544 bitmapUpdate.count = bitmapUpdate.number = rows * cols;
545 bitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * bitmapUpdate.number);
546 bitmapUpdate.rectangles = bitmapData;
551 if ((nWidth % 4) != 0)
553 nXSrc -= (nWidth % 4);
554 nWidth += (nWidth % 4);
557 if ((nHeight % 4) != 0)
559 nYSrc -= (nHeight % 4);
560 nHeight += (nHeight % 4);
563 for (yIdx = 0; yIdx < rows; yIdx++)
565 for (xIdx = 0; xIdx < cols; xIdx++)
567 bitmap = &bitmapData[k];
571 bitmap->destLeft = nXSrc + (xIdx * 64);
572 bitmap->destTop = nYSrc + (yIdx * 64);
574 if ((bitmap->destLeft + bitmap->width) > (nXSrc + nWidth))
575 bitmap->width = (nXSrc + nWidth) - bitmap->destLeft;
577 if ((bitmap->destTop + bitmap->height) > (nYSrc + nHeight))
578 bitmap->height = (nYSrc + nHeight) - bitmap->destTop;
580 bitmap->destRight = bitmap->destLeft + bitmap->width - 1;
581 bitmap->destBottom = bitmap->destTop + bitmap->height - 1;
582 bitmap->compressed = TRUE;
584 if ((bitmap->width < 4) || (bitmap->height < 4))
587 if (settings->ColorDepth < 32)
589 int bitsPerPixel = settings->ColorDepth;
590 int bytesPerPixel = (bitsPerPixel + 7) / 8;
592 DstSize = 64 * 64 * 4;
593 buffer = encoder->grid[k];
595 interleaved_compress(encoder->interleaved, buffer, &DstSize, bitmap->width, bitmap->height,
596 pSrcData, SrcFormat, nSrcStep, bitmap->destLeft, bitmap->destTop, NULL, bitsPerPixel);
598 bitmap->bitmapDataStream = buffer;
599 bitmap->bitmapLength = DstSize;
600 bitmap->bitsPerPixel = bitsPerPixel;
601 bitmap->cbScanWidth = bitmap->width * bytesPerPixel;
602 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel;
608 buffer = encoder->grid[k];
609 data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)];
611 buffer = freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat,
612 bitmap->width, bitmap->height, nSrcStep, buffer, &dstSize);
614 bitmap->bitmapDataStream = buffer;
615 bitmap->bitmapLength = dstSize;
616 bitmap->bitsPerPixel = 32;
617 bitmap->cbScanWidth = bitmap->width * 4;
618 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4;
621 bitmap->cbCompFirstRowSize = 0;
622 bitmap->cbCompMainBodySize = bitmap->bitmapLength;
624 totalBitmapSize += bitmap->bitmapLength;
629 bitmapUpdate.count = bitmapUpdate.number = k;
631 updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.count) + 16;
633 if (updateSizeEstimate > maxUpdateSize)
635 fprintf(stderr, "update size estimate larger than maximum update size\n");
638 IFCALL(update->BitmapUpdate, context, &bitmapUpdate);
645 int shadow_client_send_surface_update(rdpShadowClient* client)
651 rdpSettings* settings;
652 rdpShadowServer* server;
653 rdpShadowSurface* surface;
654 rdpShadowEncoder* encoder;
655 REGION16 invalidRegion;
656 RECTANGLE_16 surfaceRect;
657 const RECTANGLE_16* extents;
659 context = (rdpContext*) client;
660 settings = context->settings;
661 server = client->server;
662 encoder = client->encoder;
664 surface = client->inLobby ? client->lobby : server->surface;
666 EnterCriticalSection(&(client->lock));
668 region16_init(&invalidRegion);
669 region16_copy(&invalidRegion, &(client->invalidRegion));
670 region16_clear(&(client->invalidRegion));
672 LeaveCriticalSection(&(client->lock));
674 surfaceRect.left = 0;
676 surfaceRect.right = surface->width;
677 surfaceRect.bottom = surface->height;
679 region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect);
681 if (server->shareSubRect)
683 region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect));
686 if (region16_is_empty(&invalidRegion))
688 region16_uninit(&invalidRegion);
692 extents = region16_extents(&invalidRegion);
694 nXSrc = extents->left - 0;
695 nYSrc = extents->top - 0;
696 nWidth = extents->right - extents->left;
697 nHeight = extents->bottom - extents->top;
699 //WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d bottom: %d",
700 // nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight);
702 if (settings->RemoteFxCodec || settings->NSCodec)
704 status = shadow_client_send_surface_bits(client, surface, nXSrc, nYSrc, nWidth, nHeight);
708 status = shadow_client_send_bitmap_update(client, surface, nXSrc, nYSrc, nWidth, nHeight);
711 region16_uninit(&invalidRegion);
716 int shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
720 const RECTANGLE_16* rects;
722 EnterCriticalSection(&(client->lock));
724 rects = region16_rects(region, &numRects);
726 for (index = 0; index < numRects; index++)
728 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
731 LeaveCriticalSection(&(client->lock));
736 void* shadow_client_thread(rdpShadowClient* client)
747 rdpSettings* settings;
748 rdpShadowServer* server;
749 rdpShadowScreen* screen;
750 rdpShadowEncoder* encoder;
751 rdpShadowSubsystem* subsystem;
753 server = client->server;
754 screen = server->screen;
755 encoder = client->encoder;
756 subsystem = server->subsystem;
758 context = (rdpContext*) client;
759 peer = context->peer;
760 settings = peer->settings;
762 peer->Capabilities = shadow_client_capabilities;
763 peer->PostConnect = shadow_client_post_connect;
764 peer->Activate = shadow_client_activate;
766 shadow_input_register_callbacks(peer->input);
768 peer->Initialize(peer);
770 peer->update->RefreshRect = (pRefreshRect) shadow_client_refresh_rect;
771 peer->update->SuppressOutput = (pSuppressOutput) shadow_client_suppress_output;
772 peer->update->SurfaceFrameAcknowledge = (pSurfaceFrameAcknowledge) shadow_client_surface_frame_acknowledge;
774 StopEvent = client->StopEvent;
775 UpdateEvent = subsystem->updateEvent;
776 ClientEvent = peer->GetEventHandle(peer);
777 ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm);
782 events[nCount++] = StopEvent;
783 events[nCount++] = UpdateEvent;
784 events[nCount++] = ClientEvent;
785 events[nCount++] = ChannelEvent;
787 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
789 if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0)
791 if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
793 EnterSynchronizationBarrier(&(subsystem->barrier), 0);
799 if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
801 if (client->activated)
805 const RECTANGLE_16* rects;
807 rects = region16_rects(&(subsystem->invalidRegion), &numRects);
809 for (index = 0; index < numRects; index++)
811 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
814 shadow_client_send_surface_update(client);
817 EnterSynchronizationBarrier(&(subsystem->barrier), 0);
819 while (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0);
822 if (WaitForSingleObject(ClientEvent, 0) == WAIT_OBJECT_0)
824 if (!peer->CheckFileDescriptor(peer))
826 WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
831 if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
833 if (WTSVirtualChannelManagerCheckFileDescriptor(client->vcm) != TRUE)
835 WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure");
841 peer->Disconnect(peer);
843 freerdp_peer_context_free(peer);
844 freerdp_peer_free(peer);
851 void shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
853 rdpShadowClient* client;
854 rdpShadowServer* server;
856 server = (rdpShadowServer*) listener->info;
858 peer->ContextExtra = (void*) server;
859 peer->ContextSize = sizeof(rdpShadowClient);
860 peer->ContextNew = (psPeerContextNew) shadow_client_context_new;
861 peer->ContextFree = (psPeerContextFree) shadow_client_context_free;
862 freerdp_peer_context_new(peer);
864 client = (rdpShadowClient*) peer->context;
866 client->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
867 shadow_client_thread, client, 0, NULL);