1
/* $Id: ConsoleVRDPServer.cpp $ */
3
* VBox Console VRDP Helper class
7
* Copyright (C) 2006-2010 Oracle Corporation
9
* This file is part of VirtualBox Open Source Edition (OSE), as
10
* available from http://www.virtualbox.org. This file is free software;
11
* you can redistribute it and/or modify it under the terms of the GNU
12
* General Public License (GPL) as published by the Free Software
13
* Foundation, in version 2 as it comes in the "COPYING" file of the
14
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18
#include "ConsoleVRDPServer.h"
19
#include "ConsoleImpl.h"
20
#include "DisplayImpl.h"
21
#include "KeyboardImpl.h"
22
#include "MouseImpl.h"
24
#include "AutoCaller.h"
29
#include <iprt/param.h>
30
#include <iprt/path.h>
31
#include <iprt/alloca.h>
35
#include <VBox/VRDPOrders.h>
36
#endif /* VBOX_WITH_VRDP */
38
class VRDPConsoleCallback :
39
VBOX_SCRIPTABLE_IMPL(IConsoleCallback)
42
VRDPConsoleCallback(ConsoleVRDPServer *server)
45
#ifndef VBOX_WITH_XPCOM
47
#endif /* !VBOX_WITH_XPCOM */
50
virtual ~VRDPConsoleCallback() {}
54
#ifndef VBOX_WITH_XPCOM
55
STDMETHOD_(ULONG, AddRef)() {
56
return ::InterlockedIncrement(&refcnt);
58
STDMETHOD_(ULONG, Release)()
60
long cnt = ::InterlockedDecrement(&refcnt);
65
STDMETHOD(QueryInterface)(REFIID riid , void **ppObj)
67
if (riid == IID_IUnknown) {
72
if (riid == IID_IConsoleCallback) {
80
#endif /* !VBOX_WITH_XPCOM */
83
STDMETHOD(OnMousePointerShapeChange)(BOOL visible, BOOL alpha, ULONG xHot, ULONG yHot,
84
ULONG width, ULONG height, ComSafeArrayIn(BYTE,shape));
86
STDMETHOD(OnMouseCapabilityChange)(BOOL supportsAbsolute, BOOL supportsRelative, BOOL needsHostCursor)
90
m_server->NotifyAbsoluteMouse(!!supportsAbsolute);
95
STDMETHOD(OnKeyboardLedsChange)(BOOL fNumLock, BOOL fCapsLock, BOOL fScrollLock)
99
m_server->NotifyKeyboardLedsChange(fNumLock, fCapsLock, fScrollLock);
104
STDMETHOD(OnStateChange)(MachineState_T machineState)
109
STDMETHOD(OnAdditionsStateChange)()
114
STDMETHOD(OnMediumChange)(IMediumAttachment *aAttachment)
119
STDMETHOD(OnCPUChange)(ULONG aCPU, BOOL aRemove)
124
STDMETHOD(OnNetworkAdapterChange)(INetworkAdapter *aNetworkAdapter)
129
STDMETHOD(OnSerialPortChange)(ISerialPort *aSerialPort)
134
STDMETHOD(OnParallelPortChange)(IParallelPort *aParallelPort)
139
STDMETHOD(OnStorageControllerChange)()
144
STDMETHOD(OnVRDPServerChange)()
149
STDMETHOD(OnRemoteDisplayInfoChange)()
154
STDMETHOD(OnUSBControllerChange)()
159
STDMETHOD(OnUSBDeviceStateChange)(IUSBDevice *aDevice, BOOL aAttached,
160
IVirtualBoxErrorInfo *aError)
165
STDMETHOD(OnSharedFolderChange)(Scope_T aScope)
170
STDMETHOD(OnRuntimeError)(BOOL fatal, IN_BSTR id, IN_BSTR message)
175
STDMETHOD(OnCanShowWindow)(BOOL *canShow)
179
/* we don't manage window activation here: always agree */
184
STDMETHOD(OnShowWindow)(ULONG64 *winId)
188
/* we don't manage window activation here */
194
ConsoleVRDPServer *m_server;
195
#ifndef VBOX_WITH_XPCOM
197
#endif /* !VBOX_WITH_XPCOM */
200
#ifdef VBOX_WITH_XPCOM
201
#include <nsMemory.h>
202
NS_DECL_CLASSINFO(VRDPConsoleCallback)
203
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VRDPConsoleCallback, IConsoleCallback)
204
#endif /* VBOX_WITH_XPCOM */
206
#ifdef DEBUG_sunlover
207
#define LOGDUMPPTR Log
208
void dumpPointer(const uint8_t *pu8Shape, uint32_t width, uint32_t height, bool fXorMaskRGB32)
212
const uint8_t *pu8And = pu8Shape;
214
for (i = 0; i < height; i++)
217
LOGDUMPPTR(("%p: ", pu8And));
218
for (j = 0; j < (width + 7) / 8; j++)
221
for (k = 0; k < 8; k++)
223
LOGDUMPPTR(("%d", ((*pu8And) & (1 << (7 - k)))? 1: 0));
233
uint32_t *pu32Xor = (uint32_t*)(pu8Shape + ((((width + 7) / 8) * height + 3) & ~3));
235
for (i = 0; i < height; i++)
238
LOGDUMPPTR(("%p: ", pu32Xor));
239
for (j = 0; j < width; j++)
241
LOGDUMPPTR(("%08X", *pu32Xor++));
248
/* RDP 24 bit RGB mask. */
249
uint8_t *pu8Xor = (uint8_t*)(pu8Shape + ((((width + 7) / 8) * height + 3) & ~3));
250
for (i = 0; i < height; i++)
253
LOGDUMPPTR(("%p: ", pu8Xor));
254
for (j = 0; j < width; j++)
256
LOGDUMPPTR(("%02X%02X%02X", pu8Xor[2], pu8Xor[1], pu8Xor[0]));
264
#define dumpPointer(a, b, c, d) do {} while (0)
265
#endif /* DEBUG_sunlover */
267
static void findTopLeftBorder(const uint8_t *pu8AndMask, const uint8_t *pu8XorMask, uint32_t width, uint32_t height, uint32_t *pxSkip, uint32_t *pySkip)
270
* Find the top border of the AND mask. First assign to special value.
272
uint32_t ySkipAnd = ~0;
274
const uint8_t *pu8And = pu8AndMask;
275
const uint32_t cbAndRow = (width + 7) / 8;
276
const uint8_t maskLastByte = (uint8_t)( 0xFF << (cbAndRow * 8 - width) );
278
Assert(cbAndRow > 0);
283
for (y = 0; y < height && ySkipAnd == ~(uint32_t)0; y++, pu8And += cbAndRow)
285
/* For each complete byte in the row. */
286
for (x = 0; x < cbAndRow - 1; x++)
288
if (pu8And[x] != 0xFF)
295
if (ySkipAnd == ~(uint32_t)0)
298
if ((pu8And[cbAndRow - 1] & maskLastByte) != maskLastByte)
305
if (ySkipAnd == ~(uint32_t)0)
311
* Find the left border of the AND mask.
313
uint32_t xSkipAnd = ~0;
315
/* For all bit columns. */
316
for (x = 0; x < width && xSkipAnd == ~(uint32_t)0; x++)
318
pu8And = pu8AndMask + x/8; /* Currently checking byte. */
319
uint8_t mask = 1 << (7 - x%8); /* Currently checking bit in the byte. */
321
for (y = ySkipAnd; y < height; y++, pu8And += cbAndRow)
323
if ((*pu8And & mask) == 0)
331
if (xSkipAnd == ~(uint32_t)0)
337
* Find the XOR mask top border.
339
uint32_t ySkipXor = ~0;
341
uint32_t *pu32XorStart = (uint32_t *)pu8XorMask;
343
uint32_t *pu32Xor = pu32XorStart;
345
for (y = 0; y < height && ySkipXor == ~(uint32_t)0; y++, pu32Xor += width)
347
for (x = 0; x < width; x++)
357
if (ySkipXor == ~(uint32_t)0)
363
* Find the left border of the XOR mask.
365
uint32_t xSkipXor = ~(uint32_t)0;
367
/* For all columns. */
368
for (x = 0; x < width && xSkipXor == ~(uint32_t)0; x++)
370
pu32Xor = pu32XorStart + x; /* Currently checking dword. */
372
for (y = ySkipXor; y < height; y++, pu32Xor += width)
382
if (xSkipXor == ~(uint32_t)0)
387
*pxSkip = RT_MIN(xSkipAnd, xSkipXor);
388
*pySkip = RT_MIN(ySkipAnd, ySkipXor);
391
/* Generate an AND mask for alpha pointers here, because
392
* guest driver does not do that correctly for Vista pointers.
393
* Similar fix, changing the alpha threshold, could be applied
394
* for the guest driver, but then additions reinstall would be
395
* necessary, which we try to avoid.
397
static void mousePointerGenerateANDMask(uint8_t *pu8DstAndMask, int cbDstAndMask, const uint8_t *pu8SrcAlpha, int w, int h)
399
memset(pu8DstAndMask, 0xFF, cbDstAndMask);
402
for (y = 0; y < h; y++)
404
uint8_t bitmask = 0x80;
407
for (x = 0; x < w; x++, bitmask >>= 1)
414
/* Whether alpha channel value is not transparent enough for the pixel to be seen. */
415
if (pu8SrcAlpha[x * 4 + 3] > 0x7f)
417
pu8DstAndMask[x / 8] &= ~bitmask;
421
/* Point to next source and dest scans. */
422
pu8SrcAlpha += w * 4;
423
pu8DstAndMask += (w + 7) / 8;
427
STDMETHODIMP VRDPConsoleCallback::OnMousePointerShapeChange(BOOL visible,
433
ComSafeArrayIn(BYTE,inShape))
435
LogSunlover(("VRDPConsoleCallback::OnMousePointerShapeChange: %d, %d, %lux%lu, @%lu,%lu\n", visible, alpha, width, height, xHot, yHot));
439
com::SafeArray <BYTE> aShape(ComSafeArrayInArg (inShape));
440
if (aShape.size() == 0)
444
m_server->MousePointerHide();
447
else if (width != 0 && height != 0)
449
/* Pointer consists of 1 bpp AND and 24 BPP XOR masks.
450
* 'shape' AND mask followed by XOR mask.
451
* XOR mask contains 32 bit (lsb)BGR0(msb) values.
453
* We convert this to RDP color format which consist of
454
* one bpp AND mask and 24 BPP (BGR) color XOR image.
456
* RDP clients expect 8 aligned width and height of
457
* pointer (preferably 32x32).
459
* They even contain bugs which do not appear for
460
* 32x32 pointers but would appear for a 41x32 one.
462
* So set pointer size to 32x32. This can be done safely
463
* because most pointers are 32x32.
465
uint8_t* shape = aShape.raw();
467
dumpPointer(shape, width, height, true);
469
int cbDstAndMask = (((width + 7) / 8) * height + 3) & ~3;
471
uint8_t *pu8AndMask = shape;
472
uint8_t *pu8XorMask = shape + cbDstAndMask;
476
pu8AndMask = (uint8_t*)alloca(cbDstAndMask);
478
mousePointerGenerateANDMask(pu8AndMask, cbDstAndMask, pu8XorMask, width, height);
481
/* Windows guest alpha pointers are wider than 32 pixels.
482
* Try to find out the top-left border of the pointer and
483
* then copy only meaningful bits. All complete top rows
484
* and all complete left columns where (AND == 1 && XOR == 0)
485
* are skipped. Hot spot is adjusted.
487
uint32_t ySkip = 0; /* How many rows to skip at the top. */
488
uint32_t xSkip = 0; /* How many columns to skip at the left. */
490
findTopLeftBorder(pu8AndMask, pu8XorMask, width, height, &xSkip, &ySkip);
492
/* Must not skip the hot spot. */
493
xSkip = RT_MIN(xSkip, xHot);
494
ySkip = RT_MIN(ySkip, yHot);
497
* Compute size and allocate memory for the pointer.
499
const uint32_t dstwidth = 32;
500
const uint32_t dstheight = 32;
502
VRDPCOLORPOINTER *pointer = NULL;
504
uint32_t dstmaskwidth = (dstwidth + 7) / 8;
506
uint32_t rdpmaskwidth = dstmaskwidth;
507
uint32_t rdpmasklen = dstheight * rdpmaskwidth;
509
uint32_t rdpdatawidth = dstwidth * 3;
510
uint32_t rdpdatalen = dstheight * rdpdatawidth;
512
pointer = (VRDPCOLORPOINTER *)RTMemTmpAlloc(sizeof(VRDPCOLORPOINTER) + rdpmasklen + rdpdatalen);
516
uint8_t *maskarray = (uint8_t*)pointer + sizeof(VRDPCOLORPOINTER);
517
uint8_t *dataarray = maskarray + rdpmasklen;
519
memset(maskarray, 0xFF, rdpmasklen);
520
memset(dataarray, 0x00, rdpdatalen);
522
uint32_t srcmaskwidth = (width + 7) / 8;
523
uint32_t srcdatawidth = width * 4;
526
uint8_t *src = pu8AndMask + ySkip * srcmaskwidth;
527
uint8_t *dst = maskarray + (dstheight - 1) * rdpmaskwidth;
529
uint32_t minheight = RT_MIN(height - ySkip, dstheight);
530
uint32_t minwidth = RT_MIN(width - xSkip, dstwidth);
534
for (y = 0; y < minheight; y++)
536
for (x = 0; x < minwidth; x++)
538
uint32_t byteIndex = (x + xSkip) / 8;
539
uint32_t bitIndex = (x + xSkip) % 8;
541
bool bit = (src[byteIndex] & (1 << (7 - bitIndex))) != 0;
548
dst[byteIndex] &= ~(1 << (7 - bitIndex));
556
/* Point src to XOR mask */
557
src = pu8XorMask + ySkip * srcdatawidth;
558
dst = dataarray + (dstheight - 1) * rdpdatawidth;
560
for (y = 0; y < minheight ; y++)
562
for (x = 0; x < minwidth; x++)
564
memcpy(dst + x * 3, &src[4 * (x + xSkip)], 3);
571
pointer->u16HotX = (uint16_t)(xHot - xSkip);
572
pointer->u16HotY = (uint16_t)(yHot - ySkip);
574
pointer->u16Width = (uint16_t)dstwidth;
575
pointer->u16Height = (uint16_t)dstheight;
577
pointer->u16MaskLen = (uint16_t)rdpmasklen;
578
pointer->u16DataLen = (uint16_t)rdpdatalen;
580
dumpPointer((uint8_t*)pointer + sizeof(*pointer), dstwidth, dstheight, false);
582
m_server->MousePointerUpdate(pointer);
584
RTMemTmpFree(pointer);
594
////////////////////////////////////////////////////////////////////////////////
596
#ifdef VBOX_WITH_VRDP
597
RTLDRMOD ConsoleVRDPServer::mVRDPLibrary;
599
PFNVRDPCREATESERVER ConsoleVRDPServer::mpfnVRDPCreateServer = NULL;
601
VRDPENTRYPOINTS_1 *ConsoleVRDPServer::mpEntryPoints = NULL;
603
VRDPCALLBACKS_1 ConsoleVRDPServer::mCallbacks =
605
{ VRDP_INTERFACE_VERSION_1, sizeof(VRDPCALLBACKS_1) },
606
ConsoleVRDPServer::VRDPCallbackQueryProperty,
607
ConsoleVRDPServer::VRDPCallbackClientLogon,
608
ConsoleVRDPServer::VRDPCallbackClientConnect,
609
ConsoleVRDPServer::VRDPCallbackClientDisconnect,
610
ConsoleVRDPServer::VRDPCallbackIntercept,
611
ConsoleVRDPServer::VRDPCallbackUSB,
612
ConsoleVRDPServer::VRDPCallbackClipboard,
613
ConsoleVRDPServer::VRDPCallbackFramebufferQuery,
614
ConsoleVRDPServer::VRDPCallbackFramebufferLock,
615
ConsoleVRDPServer::VRDPCallbackFramebufferUnlock,
616
ConsoleVRDPServer::VRDPCallbackInput,
617
ConsoleVRDPServer::VRDPCallbackVideoModeHint
620
DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackQueryProperty(void *pvCallback, uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut)
622
ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
624
int rc = VERR_NOT_SUPPORTED;
628
case VRDP_QP_NETWORK_PORT:
630
/* This is obsolete, the VRDP server uses VRDP_QP_NETWORK_PORT_RANGE instead. */
633
if (cbBuffer >= sizeof(uint32_t))
635
*(uint32_t *)pvBuffer = (uint32_t)port;
640
rc = VINF_BUFFER_OVERFLOW;
643
*pcbOut = sizeof(uint32_t);
646
case VRDP_QP_NETWORK_ADDRESS:
649
server->mConsole->getVRDPServer()->COMGETTER(NetAddress)(bstr.asOutParam());
651
/* The server expects UTF8. */
652
com::Utf8Str address = bstr;
654
size_t cbAddress = address.length() + 1;
656
if (cbAddress >= 0x10000)
658
/* More than 64K seems to be an invalid address. */
659
rc = VERR_TOO_MUCH_DATA;
663
if ((size_t)cbBuffer >= cbAddress)
669
memcpy(pvBuffer, address.raw(), cbAddress);
673
/* The value is an empty string. */
674
*(uint8_t *)pvBuffer = 0;
682
rc = VINF_BUFFER_OVERFLOW;
685
*pcbOut = (uint32_t)cbAddress;
688
case VRDP_QP_NUMBER_MONITORS:
692
server->mConsole->machine()->COMGETTER(MonitorCount)(&cMonitors);
694
if (cbBuffer >= sizeof(uint32_t))
696
*(uint32_t *)pvBuffer = (uint32_t)cMonitors;
701
rc = VINF_BUFFER_OVERFLOW;
704
*pcbOut = sizeof(uint32_t);
707
case VRDP_QP_NETWORK_PORT_RANGE:
710
HRESULT hrc = server->mConsole->getVRDPServer()->COMGETTER(Ports)(bstr.asOutParam());
722
/* The server expects UTF8. */
723
com::Utf8Str portRange = bstr;
725
size_t cbPortRange = portRange.length () + 1;
727
if (cbPortRange >= 0x10000)
729
/* More than 64K seems to be an invalid port range string. */
730
rc = VERR_TOO_MUCH_DATA;
734
if ((size_t)cbBuffer >= cbPortRange)
740
memcpy(pvBuffer, portRange.raw(), cbPortRange);
744
/* The value is an empty string. */
745
*(uint8_t *)pvBuffer = 0;
753
rc = VINF_BUFFER_OVERFLOW;
756
*pcbOut = (uint32_t)cbPortRange;
759
#ifdef VBOX_WITH_VRDP_VIDEO_CHANNEL
760
case VRDP_QP_VIDEO_CHANNEL:
762
BOOL fVideoEnabled = FALSE;
764
server->mConsole->getVRDPServer()->COMGETTER(VideoChannel)(&fVideoEnabled);
766
if (cbBuffer >= sizeof(uint32_t))
768
*(uint32_t *)pvBuffer = (uint32_t)fVideoEnabled;
773
rc = VINF_BUFFER_OVERFLOW;
776
*pcbOut = sizeof(uint32_t);
779
case VRDP_QP_VIDEO_CHANNEL_QUALITY:
783
server->mConsole->getVRDPServer()->COMGETTER(VideoChannelQuality)(&ulQuality);
785
if (cbBuffer >= sizeof(uint32_t))
787
*(uint32_t *)pvBuffer = (uint32_t)ulQuality;
792
rc = VINF_BUFFER_OVERFLOW;
795
*pcbOut = sizeof(uint32_t);
798
case VRDP_QP_VIDEO_CHANNEL_SUNFLSH:
803
HRESULT hrc = server->mConsole->machine ()->GetExtraData(Bstr("VRDP/SunFlsh"), bstr.asOutParam());
804
if (hrc == S_OK && !bstr.isEmpty())
806
com::Utf8Str sunFlsh = bstr;
807
if (!sunFlsh.isEmpty())
809
ulSunFlsh = sunFlsh.toUInt32();
813
if (cbBuffer >= sizeof(uint32_t))
815
*(uint32_t *)pvBuffer = (uint32_t)ulSunFlsh;
820
rc = VINF_BUFFER_OVERFLOW;
823
*pcbOut = sizeof(uint32_t);
825
#endif /* VBOX_WITH_VRDP_VIDEO_CHANNEL */
827
case VRDP_QP_FEATURE:
829
if (cbBuffer < sizeof(VRDPFEATURE))
831
rc = VERR_INVALID_PARAMETER;
835
size_t cbInfo = cbBuffer - RT_OFFSETOF(VRDPFEATURE, achInfo);
837
VRDPFEATURE *pFeature = (VRDPFEATURE *)pvBuffer;
840
rc = RTStrNLenEx(pFeature->achInfo, cbInfo, &cchInfo);
844
rc = VERR_INVALID_PARAMETER;
848
/* features are mapped to "VRDP/Feature/NAME" extra data. */
849
com::Utf8Str extraData("VRDP/Feature/");
850
extraData.append(com::Utf8Str(pFeature->achInfo));
854
/* @todo these features should be per client. */
855
NOREF(pFeature->u32ClientId);
857
if ( RTStrICmp(pFeature->achInfo, "Client/DisableDisplay") == 0
858
|| RTStrICmp(pFeature->achInfo, "Client/DisableInput") == 0
859
|| RTStrICmp(pFeature->achInfo, "Client/DisableAudio") == 0
860
|| RTStrICmp(pFeature->achInfo, "Client/DisableUSB") == 0
861
|| RTStrICmp(pFeature->achInfo, "Client/DisableClipboard") == 0
864
HRESULT hrc = server->mConsole->machine ()->GetExtraData(com::Bstr(extraData), bstrValue.asOutParam());
865
if (hrc == S_OK && !bstrValue.isEmpty())
872
rc = VERR_NOT_SUPPORTED;
875
/* Copy the value string to the callers buffer. */
876
if (rc == VINF_SUCCESS)
878
com::Utf8Str value = bstrValue;
880
size_t cb = value.length() + 1;
882
if ((size_t)cbInfo >= cb)
884
memcpy(pFeature->achInfo, value.c_str(), cb);
888
rc = VINF_BUFFER_OVERFLOW;
891
*pcbOut = (uint32_t)cb;
895
case VRDP_SP_NETWORK_BIND_PORT:
897
if (cbBuffer != sizeof(uint32_t))
899
rc = VERR_INVALID_PARAMETER;
903
ULONG port = *(uint32_t *)pvBuffer;
905
server->mVRDPBindPort = port;
911
*pcbOut = sizeof(uint32_t);
914
server->mConsole->onRemoteDisplayInfoChange();
924
DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClientLogon(void *pvCallback, uint32_t u32ClientId, const char *pszUser, const char *pszPassword, const char *pszDomain)
926
ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
928
return server->mConsole->VRDPClientLogon (u32ClientId, pszUser, pszPassword, pszDomain);
931
DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientConnect (void *pvCallback, uint32_t u32ClientId)
933
ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
935
server->mConsole->VRDPClientConnect (u32ClientId);
938
DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientDisconnect (void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercepted)
940
ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
942
server->mConsole->VRDPClientDisconnect (u32ClientId, fu32Intercepted);
945
DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackIntercept (void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercept, void **ppvIntercept)
947
ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
949
LogFlowFunc(("%x\n", fu32Intercept));
951
int rc = VERR_NOT_SUPPORTED;
953
switch (fu32Intercept)
955
case VRDP_CLIENT_INTERCEPT_AUDIO:
957
server->mConsole->VRDPInterceptAudio (u32ClientId);
960
*ppvIntercept = server;
965
case VRDP_CLIENT_INTERCEPT_USB:
967
server->mConsole->VRDPInterceptUSB (u32ClientId, ppvIntercept);
971
case VRDP_CLIENT_INTERCEPT_CLIPBOARD:
973
server->mConsole->VRDPInterceptClipboard (u32ClientId);
976
*ppvIntercept = server;
988
DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackUSB (void *pvCallback, void *pvIntercept, uint32_t u32ClientId, uint8_t u8Code, const void *pvRet, uint32_t cbRet)
991
return USBClientResponseCallback (pvIntercept, u32ClientId, u8Code, pvRet, cbRet);
993
return VERR_NOT_SUPPORTED;
997
DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClipboard (void *pvCallback, void *pvIntercept, uint32_t u32ClientId, uint32_t u32Function, uint32_t u32Format, const void *pvData, uint32_t cbData)
999
return ClipboardCallback (pvIntercept, u32ClientId, u32Function, u32Format, pvData, cbData);
1002
DECLCALLBACK(bool) ConsoleVRDPServer::VRDPCallbackFramebufferQuery (void *pvCallback, unsigned uScreenId, VRDPFRAMEBUFFERINFO *pInfo)
1004
ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1006
bool fAvailable = false;
1008
IFramebuffer *pfb = NULL;
1012
server->mConsole->getDisplay ()->GetFramebuffer (uScreenId, &pfb, &xOrigin, &yOrigin);
1018
/* Query framebuffer parameters. */
1020
pfb->COMGETTER(BytesPerLine) (&lineSize);
1022
ULONG bitsPerPixel = 0;
1023
pfb->COMGETTER(BitsPerPixel) (&bitsPerPixel);
1025
BYTE *address = NULL;
1026
pfb->COMGETTER(Address) (&address);
1029
pfb->COMGETTER(Height) (&height);
1032
pfb->COMGETTER(Width) (&width);
1034
/* Now fill the information as requested by the caller. */
1035
pInfo->pu8Bits = address;
1036
pInfo->xOrigin = xOrigin;
1037
pInfo->yOrigin = yOrigin;
1038
pInfo->cWidth = width;
1039
pInfo->cHeight = height;
1040
pInfo->cBitsPerPixel = bitsPerPixel;
1041
pInfo->cbLine = lineSize;
1048
if (server->maFramebuffers[uScreenId])
1050
server->maFramebuffers[uScreenId]->Release ();
1052
server->maFramebuffers[uScreenId] = pfb;
1057
DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferLock (void *pvCallback, unsigned uScreenId)
1059
ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1061
if (server->maFramebuffers[uScreenId])
1063
server->maFramebuffers[uScreenId]->Lock ();
1067
DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferUnlock (void *pvCallback, unsigned uScreenId)
1069
ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1071
if (server->maFramebuffers[uScreenId])
1073
server->maFramebuffers[uScreenId]->Unlock ();
1077
static void fixKbdLockStatus (VRDPInputSynch *pInputSynch, IKeyboard *pKeyboard)
1079
if ( pInputSynch->cGuestNumLockAdaptions
1080
&& (pInputSynch->fGuestNumLock != pInputSynch->fClientNumLock))
1082
pInputSynch->cGuestNumLockAdaptions--;
1083
pKeyboard->PutScancode(0x45);
1084
pKeyboard->PutScancode(0x45 | 0x80);
1086
if ( pInputSynch->cGuestCapsLockAdaptions
1087
&& (pInputSynch->fGuestCapsLock != pInputSynch->fClientCapsLock))
1089
pInputSynch->cGuestCapsLockAdaptions--;
1090
pKeyboard->PutScancode(0x3a);
1091
pKeyboard->PutScancode(0x3a | 0x80);
1095
DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackInput (void *pvCallback, int type, const void *pvInput, unsigned cbInput)
1097
ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1098
Console *pConsole = server->mConsole;
1102
case VRDP_INPUT_SCANCODE:
1104
if (cbInput == sizeof (VRDPINPUTSCANCODE))
1106
IKeyboard *pKeyboard = pConsole->getKeyboard ();
1108
const VRDPINPUTSCANCODE *pInputScancode = (VRDPINPUTSCANCODE *)pvInput;
1110
/* Track lock keys. */
1111
if (pInputScancode->uScancode == 0x45)
1113
server->m_InputSynch.fClientNumLock = !server->m_InputSynch.fClientNumLock;
1115
else if (pInputScancode->uScancode == 0x3a)
1117
server->m_InputSynch.fClientCapsLock = !server->m_InputSynch.fClientCapsLock;
1119
else if (pInputScancode->uScancode == 0x46)
1121
server->m_InputSynch.fClientScrollLock = !server->m_InputSynch.fClientScrollLock;
1123
else if ((pInputScancode->uScancode & 0x80) == 0)
1126
fixKbdLockStatus (&server->m_InputSynch, pKeyboard);
1129
pKeyboard->PutScancode((LONG)pInputScancode->uScancode);
1133
case VRDP_INPUT_POINT:
1135
if (cbInput == sizeof (VRDPINPUTPOINT))
1137
const VRDPINPUTPOINT *pInputPoint = (VRDPINPUTPOINT *)pvInput;
1139
int mouseButtons = 0;
1142
if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON1)
1144
mouseButtons |= MouseButtonState_LeftButton;
1146
if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON2)
1148
mouseButtons |= MouseButtonState_RightButton;
1150
if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON3)
1152
mouseButtons |= MouseButtonState_MiddleButton;
1154
if (pInputPoint->uButtons & VRDP_INPUT_POINT_WHEEL_UP)
1156
mouseButtons |= MouseButtonState_WheelUp;
1159
if (pInputPoint->uButtons & VRDP_INPUT_POINT_WHEEL_DOWN)
1161
mouseButtons |= MouseButtonState_WheelDown;
1165
if (server->m_fGuestWantsAbsolute)
1167
pConsole->getMouse()->PutMouseEventAbsolute (pInputPoint->x + 1, pInputPoint->y + 1, iWheel, 0 /* Horizontal wheel */, mouseButtons);
1170
pConsole->getMouse()->PutMouseEvent (pInputPoint->x - server->m_mousex,
1171
pInputPoint->y - server->m_mousey,
1172
iWheel, 0 /* Horizontal wheel */, mouseButtons);
1173
server->m_mousex = pInputPoint->x;
1174
server->m_mousey = pInputPoint->y;
1179
case VRDP_INPUT_CAD:
1181
pConsole->getKeyboard ()->PutCAD();
1184
case VRDP_INPUT_RESET:
1189
case VRDP_INPUT_SYNCH:
1191
if (cbInput == sizeof (VRDPINPUTSYNCH))
1193
IKeyboard *pKeyboard = pConsole->getKeyboard ();
1195
const VRDPINPUTSYNCH *pInputSynch = (VRDPINPUTSYNCH *)pvInput;
1197
server->m_InputSynch.fClientNumLock = (pInputSynch->uLockStatus & VRDP_INPUT_SYNCH_NUMLOCK) != 0;
1198
server->m_InputSynch.fClientCapsLock = (pInputSynch->uLockStatus & VRDP_INPUT_SYNCH_CAPITAL) != 0;
1199
server->m_InputSynch.fClientScrollLock = (pInputSynch->uLockStatus & VRDP_INPUT_SYNCH_SCROLL) != 0;
1201
/* The client initiated synchronization. Always make the guest to reflect the client state.
1202
* Than means, when the guest changes the state itself, it is forced to return to the client
1205
if (server->m_InputSynch.fClientNumLock != server->m_InputSynch.fGuestNumLock)
1207
server->m_InputSynch.cGuestNumLockAdaptions = 2;
1210
if (server->m_InputSynch.fClientCapsLock != server->m_InputSynch.fGuestCapsLock)
1212
server->m_InputSynch.cGuestCapsLockAdaptions = 2;
1215
fixKbdLockStatus (&server->m_InputSynch, pKeyboard);
1224
DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackVideoModeHint (void *pvCallback, unsigned cWidth, unsigned cHeight, unsigned cBitsPerPixel, unsigned uScreenId)
1226
ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1228
server->mConsole->getDisplay()->SetVideoModeHint(cWidth, cHeight, cBitsPerPixel, uScreenId);
1230
#endif /* VBOX_WITH_VRDP */
1232
ConsoleVRDPServer::ConsoleVRDPServer (Console *console)
1236
int rc = RTCritSectInit(&mCritSect);
1239
mcClipboardRefs = 0;
1240
mpfnClipboardCallback = NULL;
1242
#ifdef VBOX_WITH_USB
1243
mUSBBackends.pHead = NULL;
1244
mUSBBackends.pTail = NULL;
1246
mUSBBackends.thread = NIL_RTTHREAD;
1247
mUSBBackends.fThreadRunning = false;
1248
mUSBBackends.event = 0;
1251
#ifdef VBOX_WITH_VRDP
1254
m_fGuestWantsAbsolute = false;
1258
m_InputSynch.cGuestNumLockAdaptions = 2;
1259
m_InputSynch.cGuestCapsLockAdaptions = 2;
1261
m_InputSynch.fGuestNumLock = false;
1262
m_InputSynch.fGuestCapsLock = false;
1263
m_InputSynch.fGuestScrollLock = false;
1265
m_InputSynch.fClientNumLock = false;
1266
m_InputSynch.fClientCapsLock = false;
1267
m_InputSynch.fClientScrollLock = false;
1269
memset (maFramebuffers, 0, sizeof (maFramebuffers));
1271
mConsoleCallback = new VRDPConsoleCallback(this);
1272
mConsoleCallback->AddRef();
1273
console->RegisterCallback(mConsoleCallback);
1276
#endif /* VBOX_WITH_VRDP */
1281
ConsoleVRDPServer::~ConsoleVRDPServer ()
1285
#ifdef VBOX_WITH_VRDP
1286
if (mConsoleCallback)
1288
mConsole->UnregisterCallback(mConsoleCallback);
1289
mConsoleCallback->Release();
1290
mConsoleCallback = NULL;
1294
for (i = 0; i < RT_ELEMENTS(maFramebuffers); i++)
1296
if (maFramebuffers[i])
1298
maFramebuffers[i]->Release ();
1299
maFramebuffers[i] = NULL;
1302
#endif /* VBOX_WITH_VRDP */
1304
if (RTCritSectIsInitialized (&mCritSect))
1306
RTCritSectDelete (&mCritSect);
1307
memset (&mCritSect, 0, sizeof (mCritSect));
1311
int ConsoleVRDPServer::Launch (void)
1313
LogFlowThisFunc(("\n"));
1314
#ifdef VBOX_WITH_VRDP
1315
int rc = VINF_SUCCESS;
1316
IVRDPServer *vrdpserver = mConsole->getVRDPServer ();
1318
BOOL vrdpEnabled = FALSE;
1320
HRESULT rc2 = vrdpserver->COMGETTER(Enabled) (&vrdpEnabled);
1323
if (SUCCEEDED(rc2) && vrdpEnabled)
1325
if (loadVRDPLibrary ())
1327
rc = mpfnVRDPCreateServer (&mCallbacks.header, this, (VRDPINTERFACEHDR **)&mpEntryPoints, &mhServer);
1331
#ifdef VBOX_WITH_USB
1332
remoteUSBThreadStart ();
1333
#endif /* VBOX_WITH_USB */
1335
else if (rc != VERR_NET_ADDRESS_IN_USE)
1336
AssertMsgFailed(("Could not start VRDP server: rc = %Rrc\n", rc));
1340
AssertMsgFailed(("Could not load the VRDP library\n"));
1341
rc = VERR_FILE_NOT_FOUND;
1345
int rc = VERR_NOT_SUPPORTED;
1346
LogRel(("VRDP: this version does not include the VRDP server.\n"));
1347
#endif /* VBOX_WITH_VRDP */
1351
void ConsoleVRDPServer::EnableConnections (void)
1353
#ifdef VBOX_WITH_VRDP
1354
if (mpEntryPoints && mhServer)
1356
mpEntryPoints->VRDPEnableConnections (mhServer, true);
1358
#endif /* VBOX_WITH_VRDP */
1361
void ConsoleVRDPServer::DisconnectClient (uint32_t u32ClientId, bool fReconnect)
1363
#ifdef VBOX_WITH_VRDP
1364
if (mpEntryPoints && mhServer)
1366
mpEntryPoints->VRDPDisconnect (mhServer, u32ClientId, fReconnect);
1368
#endif /* VBOX_WITH_VRDP */
1371
void ConsoleVRDPServer::MousePointerUpdate (const VRDPCOLORPOINTER *pPointer)
1373
#ifdef VBOX_WITH_VRDP
1374
if (mpEntryPoints && mhServer)
1376
mpEntryPoints->VRDPColorPointer (mhServer, pPointer);
1378
#endif /* VBOX_WITH_VRDP */
1381
void ConsoleVRDPServer::MousePointerHide (void)
1383
#ifdef VBOX_WITH_VRDP
1384
if (mpEntryPoints && mhServer)
1386
mpEntryPoints->VRDPHidePointer (mhServer);
1388
#endif /* VBOX_WITH_VRDP */
1391
void ConsoleVRDPServer::Stop (void)
1393
Assert(VALID_PTR(this)); /** @todo r=bird: there are(/was) some odd cases where this buster was invalid on
1394
* linux. Just remove this when it's 100% sure that problem has been fixed. */
1395
#ifdef VBOX_WITH_VRDP
1398
HVRDPSERVER hServer = mhServer;
1400
/* Reset the handle to avoid further calls to the server. */
1403
if (mpEntryPoints && hServer)
1405
mpEntryPoints->VRDPDestroy (hServer);
1408
#endif /* VBOX_WITH_VRDP */
1410
#ifdef VBOX_WITH_USB
1411
remoteUSBThreadStop ();
1412
#endif /* VBOX_WITH_USB */
1414
mpfnAuthEntry = NULL;
1415
mpfnAuthEntry2 = NULL;
1419
RTLdrClose(mAuthLibrary);
1424
/* Worker thread for Remote USB. The thread polls the clients for
1425
* the list of attached USB devices.
1426
* The thread is also responsible for attaching/detaching devices
1429
* It is expected that attaching/detaching is not a frequent operation.
1431
* The thread is always running when the VRDP server is active.
1433
* The thread scans backends and requests the device list every 2 seconds.
1435
* When device list is available, the thread calls the Console to process it.
1438
#define VRDP_DEVICE_LIST_PERIOD_MS (2000)
1440
#ifdef VBOX_WITH_USB
1441
static DECLCALLBACK(int) threadRemoteUSB (RTTHREAD self, void *pvUser)
1443
ConsoleVRDPServer *pOwner = (ConsoleVRDPServer *)pvUser;
1445
LogFlow(("Console::threadRemoteUSB: start. owner = %p.\n", pOwner));
1447
pOwner->notifyRemoteUSBThreadRunning (self);
1449
while (pOwner->isRemoteUSBThreadRunning ())
1451
RemoteUSBBackend *pRemoteUSBBackend = NULL;
1453
while ((pRemoteUSBBackend = pOwner->usbBackendGetNext (pRemoteUSBBackend)) != NULL)
1455
pRemoteUSBBackend->PollRemoteDevices ();
1458
pOwner->waitRemoteUSBThreadEvent (VRDP_DEVICE_LIST_PERIOD_MS);
1460
LogFlow(("Console::threadRemoteUSB: iteration. owner = %p.\n", pOwner));
1463
return VINF_SUCCESS;
1466
void ConsoleVRDPServer::notifyRemoteUSBThreadRunning (RTTHREAD thread)
1468
mUSBBackends.thread = thread;
1469
mUSBBackends.fThreadRunning = true;
1470
int rc = RTThreadUserSignal (thread);
1474
bool ConsoleVRDPServer::isRemoteUSBThreadRunning (void)
1476
return mUSBBackends.fThreadRunning;
1479
void ConsoleVRDPServer::waitRemoteUSBThreadEvent (RTMSINTERVAL cMillies)
1481
int rc = RTSemEventWait (mUSBBackends.event, cMillies);
1482
Assert (RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1486
void ConsoleVRDPServer::remoteUSBThreadStart (void)
1488
int rc = RTSemEventCreate (&mUSBBackends.event);
1493
mUSBBackends.event = 0;
1498
rc = RTThreadCreate (&mUSBBackends.thread, threadRemoteUSB, this, 65536,
1499
RTTHREADTYPE_VRDP_IO, RTTHREADFLAGS_WAITABLE, "remote usb");
1504
LogRel(("Warning: could not start the remote USB thread, rc = %Rrc!!!\n", rc));
1505
mUSBBackends.thread = NIL_RTTHREAD;
1509
/* Wait until the thread is ready. */
1510
rc = RTThreadUserWait (mUSBBackends.thread, 60000);
1512
Assert (mUSBBackends.fThreadRunning || RT_FAILURE(rc));
1516
void ConsoleVRDPServer::remoteUSBThreadStop (void)
1518
mUSBBackends.fThreadRunning = false;
1520
if (mUSBBackends.thread != NIL_RTTHREAD)
1522
Assert (mUSBBackends.event != 0);
1524
RTSemEventSignal (mUSBBackends.event);
1526
int rc = RTThreadWait (mUSBBackends.thread, 60000, NULL);
1529
mUSBBackends.thread = NIL_RTTHREAD;
1532
if (mUSBBackends.event)
1534
RTSemEventDestroy (mUSBBackends.event);
1535
mUSBBackends.event = 0;
1538
#endif /* VBOX_WITH_USB */
1540
VRDPAuthResult ConsoleVRDPServer::Authenticate (const Guid &uuid, VRDPAuthGuestJudgement guestJudgement,
1541
const char *pszUser, const char *pszPassword, const char *pszDomain,
1542
uint32_t u32ClientId)
1544
VRDPAUTHUUID rawuuid;
1546
memcpy (rawuuid, ((Guid &)uuid).ptr (), sizeof (rawuuid));
1548
LogFlow(("ConsoleVRDPServer::Authenticate: uuid = %RTuuid, guestJudgement = %d, pszUser = %s, pszPassword = %s, pszDomain = %s, u32ClientId = %d\n",
1549
rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, u32ClientId));
1552
* Called only from VRDP input thread. So thread safety is not required.
1557
/* Load the external authentication library. */
1559
ComPtr<IMachine> machine;
1560
mConsole->COMGETTER(Machine)(machine.asOutParam());
1562
ComPtr<IVirtualBox> virtualBox;
1563
machine->COMGETTER(Parent)(virtualBox.asOutParam());
1565
ComPtr<ISystemProperties> systemProperties;
1566
virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
1569
systemProperties->COMGETTER(RemoteDisplayAuthLibrary)(authLibrary.asOutParam());
1571
Utf8Str filename = authLibrary;
1573
LogRel(("VRDPAUTH: ConsoleVRDPServer::Authenticate: loading external authentication library '%ls'\n", authLibrary.raw()));
1576
if (RTPathHavePath(filename.raw()))
1577
rc = RTLdrLoad(filename.raw(), &mAuthLibrary);
1579
rc = RTLdrLoadAppPriv(filename.raw(), &mAuthLibrary);
1582
LogRel(("VRDPAUTH: Failed to load external authentication library. Error code: %Rrc\n", rc));
1586
/* Get the entry point. */
1587
mpfnAuthEntry2 = NULL;
1588
int rc2 = RTLdrGetSymbol(mAuthLibrary, "VRDPAuth2", (void**)&mpfnAuthEntry2);
1589
if (RT_FAILURE(rc2))
1591
if (rc2 != VERR_SYMBOL_NOT_FOUND)
1593
LogRel(("VRDPAUTH: Could not resolve import '%s'. Error code: %Rrc\n", "VRDPAuth2", rc2));
1598
/* Get the entry point. */
1599
mpfnAuthEntry = NULL;
1600
rc2 = RTLdrGetSymbol(mAuthLibrary, "VRDPAuth", (void**)&mpfnAuthEntry);
1601
if (RT_FAILURE(rc2))
1603
if (rc2 != VERR_SYMBOL_NOT_FOUND)
1605
LogRel(("VRDPAUTH: Could not resolve import '%s'. Error code: %Rrc\n", "VRDPAuth", rc2));
1610
if (mpfnAuthEntry2 || mpfnAuthEntry)
1612
LogRel(("VRDPAUTH: Using entry point '%s'.\n", mpfnAuthEntry2? "VRDPAuth2": "VRDPAuth"));
1619
mConsole->reportAuthLibraryError(filename.raw(), rc);
1621
mpfnAuthEntry = NULL;
1622
mpfnAuthEntry2 = NULL;
1626
RTLdrClose(mAuthLibrary);
1630
return VRDPAuthAccessDenied;
1634
Assert (mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2));
1636
VRDPAuthResult result = mpfnAuthEntry2?
1637
mpfnAuthEntry2 (&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, true, u32ClientId):
1638
mpfnAuthEntry (&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain);
1642
case VRDPAuthAccessDenied:
1643
LogRel(("VRDPAUTH: external authentication module returned 'access denied'\n"));
1645
case VRDPAuthAccessGranted:
1646
LogRel(("VRDPAUTH: external authentication module returned 'access granted'\n"));
1648
case VRDPAuthDelegateToGuest:
1649
LogRel(("VRDPAUTH: external authentication module returned 'delegate request to guest'\n"));
1652
LogRel(("VRDPAUTH: external authentication module returned incorrect return code %d\n", result));
1653
result = VRDPAuthAccessDenied;
1656
LogFlow(("ConsoleVRDPServer::Authenticate: result = %d\n", result));
1661
void ConsoleVRDPServer::AuthDisconnect (const Guid &uuid, uint32_t u32ClientId)
1663
VRDPAUTHUUID rawuuid;
1665
memcpy (rawuuid, ((Guid &)uuid).ptr (), sizeof (rawuuid));
1667
LogFlow(("ConsoleVRDPServer::AuthDisconnect: uuid = %RTuuid, u32ClientId = %d\n",
1668
rawuuid, u32ClientId));
1670
Assert (mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2));
1673
mpfnAuthEntry2 (&rawuuid, VRDPAuthGuestNotAsked, NULL, NULL, NULL, false, u32ClientId);
1676
int ConsoleVRDPServer::lockConsoleVRDPServer (void)
1678
int rc = RTCritSectEnter (&mCritSect);
1683
void ConsoleVRDPServer::unlockConsoleVRDPServer (void)
1685
RTCritSectLeave (&mCritSect);
1688
DECLCALLBACK(int) ConsoleVRDPServer::ClipboardCallback (void *pvCallback,
1689
uint32_t u32ClientId,
1690
uint32_t u32Function,
1695
LogFlowFunc(("pvCallback = %p, u32ClientId = %d, u32Function = %d, u32Format = 0x%08X, pvData = %p, cbData = %d\n",
1696
pvCallback, u32ClientId, u32Function, u32Format, pvData, cbData));
1698
int rc = VINF_SUCCESS;
1700
ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvCallback);
1704
switch (u32Function)
1706
case VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE:
1708
if (pServer->mpfnClipboardCallback)
1710
pServer->mpfnClipboardCallback (VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE,
1717
case VRDP_CLIPBOARD_FUNCTION_DATA_READ:
1719
if (pServer->mpfnClipboardCallback)
1721
pServer->mpfnClipboardCallback (VBOX_CLIPBOARD_EXT_FN_DATA_READ,
1729
rc = VERR_NOT_SUPPORTED;
1735
DECLCALLBACK(int) ConsoleVRDPServer::ClipboardServiceExtension (void *pvExtension,
1736
uint32_t u32Function,
1740
LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
1741
pvExtension, u32Function, pvParms, cbParms));
1743
int rc = VINF_SUCCESS;
1745
#ifdef VBOX_WITH_VRDP
1746
ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvExtension);
1748
VBOXCLIPBOARDEXTPARMS *pParms = (VBOXCLIPBOARDEXTPARMS *)pvParms;
1750
switch (u32Function)
1752
case VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK:
1754
pServer->mpfnClipboardCallback = pParms->u.pfnCallback;
1757
case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
1759
/* The guest announces clipboard formats. This must be delivered to all clients. */
1760
if (mpEntryPoints && pServer->mhServer)
1762
mpEntryPoints->VRDPClipboard (pServer->mhServer,
1763
VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE,
1771
case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
1773
/* The clipboard service expects that the pvData buffer will be filled
1774
* with clipboard data. The server returns the data from the client that
1775
* announced the requested format most recently.
1777
if (mpEntryPoints && pServer->mhServer)
1779
mpEntryPoints->VRDPClipboard (pServer->mhServer,
1780
VRDP_CLIPBOARD_FUNCTION_DATA_READ,
1788
case VBOX_CLIPBOARD_EXT_FN_DATA_WRITE:
1790
if (mpEntryPoints && pServer->mhServer)
1792
mpEntryPoints->VRDPClipboard (pServer->mhServer,
1793
VRDP_CLIPBOARD_FUNCTION_DATA_WRITE,
1802
rc = VERR_NOT_SUPPORTED;
1804
#endif /* VBOX_WITH_VRDP */
1809
void ConsoleVRDPServer::ClipboardCreate (uint32_t u32ClientId)
1811
int rc = lockConsoleVRDPServer ();
1815
if (mcClipboardRefs == 0)
1817
rc = HGCMHostRegisterServiceExtension (&mhClipboard, "VBoxSharedClipboard", ClipboardServiceExtension, this);
1825
unlockConsoleVRDPServer ();
1829
void ConsoleVRDPServer::ClipboardDelete (uint32_t u32ClientId)
1831
int rc = lockConsoleVRDPServer ();
1837
if (mcClipboardRefs == 0)
1839
HGCMHostUnregisterServiceExtension (mhClipboard);
1842
unlockConsoleVRDPServer ();
1846
/* That is called on INPUT thread of the VRDP server.
1847
* The ConsoleVRDPServer keeps a list of created backend instances.
1849
void ConsoleVRDPServer::USBBackendCreate (uint32_t u32ClientId, void **ppvIntercept)
1851
#ifdef VBOX_WITH_USB
1852
LogFlow(("ConsoleVRDPServer::USBBackendCreate: u32ClientId = %d\n", u32ClientId));
1854
/* Create a new instance of the USB backend for the new client. */
1855
RemoteUSBBackend *pRemoteUSBBackend = new RemoteUSBBackend (mConsole, this, u32ClientId);
1857
if (pRemoteUSBBackend)
1859
pRemoteUSBBackend->AddRef (); /* 'Release' called in USBBackendDelete. */
1861
/* Append the new instance in the list. */
1862
int rc = lockConsoleVRDPServer ();
1866
pRemoteUSBBackend->pNext = mUSBBackends.pHead;
1867
if (mUSBBackends.pHead)
1869
mUSBBackends.pHead->pPrev = pRemoteUSBBackend;
1873
mUSBBackends.pTail = pRemoteUSBBackend;
1876
mUSBBackends.pHead = pRemoteUSBBackend;
1878
unlockConsoleVRDPServer ();
1882
*ppvIntercept = pRemoteUSBBackend;
1888
pRemoteUSBBackend->Release ();
1891
#endif /* VBOX_WITH_USB */
1894
void ConsoleVRDPServer::USBBackendDelete (uint32_t u32ClientId)
1896
#ifdef VBOX_WITH_USB
1897
LogFlow(("ConsoleVRDPServer::USBBackendDelete: u32ClientId = %d\n", u32ClientId));
1899
RemoteUSBBackend *pRemoteUSBBackend = NULL;
1901
/* Find the instance. */
1902
int rc = lockConsoleVRDPServer ();
1906
pRemoteUSBBackend = usbBackendFind (u32ClientId);
1908
if (pRemoteUSBBackend)
1910
/* Notify that it will be deleted. */
1911
pRemoteUSBBackend->NotifyDelete ();
1914
unlockConsoleVRDPServer ();
1917
if (pRemoteUSBBackend)
1919
/* Here the instance has been excluded from the list and can be dereferenced. */
1920
pRemoteUSBBackend->Release ();
1925
void *ConsoleVRDPServer::USBBackendRequestPointer (uint32_t u32ClientId, const Guid *pGuid)
1927
#ifdef VBOX_WITH_USB
1928
RemoteUSBBackend *pRemoteUSBBackend = NULL;
1930
/* Find the instance. */
1931
int rc = lockConsoleVRDPServer ();
1935
pRemoteUSBBackend = usbBackendFind (u32ClientId);
1937
if (pRemoteUSBBackend)
1939
/* Inform the backend instance that it is referenced by the Guid. */
1940
bool fAdded = pRemoteUSBBackend->addUUID (pGuid);
1944
/* Reference the instance because its pointer is being taken. */
1945
pRemoteUSBBackend->AddRef (); /* 'Release' is called in USBBackendReleasePointer. */
1949
pRemoteUSBBackend = NULL;
1953
unlockConsoleVRDPServer ();
1956
if (pRemoteUSBBackend)
1958
return pRemoteUSBBackend->GetBackendCallbackPointer ();
1965
void ConsoleVRDPServer::USBBackendReleasePointer (const Guid *pGuid)
1967
#ifdef VBOX_WITH_USB
1968
RemoteUSBBackend *pRemoteUSBBackend = NULL;
1970
/* Find the instance. */
1971
int rc = lockConsoleVRDPServer ();
1975
pRemoteUSBBackend = usbBackendFindByUUID (pGuid);
1977
if (pRemoteUSBBackend)
1979
pRemoteUSBBackend->removeUUID (pGuid);
1982
unlockConsoleVRDPServer ();
1984
if (pRemoteUSBBackend)
1986
pRemoteUSBBackend->Release ();
1992
RemoteUSBBackend *ConsoleVRDPServer::usbBackendGetNext (RemoteUSBBackend *pRemoteUSBBackend)
1994
LogFlow(("ConsoleVRDPServer::usbBackendGetNext: pBackend = %p\n", pRemoteUSBBackend));
1996
RemoteUSBBackend *pNextRemoteUSBBackend = NULL;
1997
#ifdef VBOX_WITH_USB
1999
int rc = lockConsoleVRDPServer ();
2003
if (pRemoteUSBBackend == NULL)
2005
/* The first backend in the list is requested. */
2006
pNextRemoteUSBBackend = mUSBBackends.pHead;
2010
/* Get pointer to the next backend. */
2011
pNextRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
2014
if (pNextRemoteUSBBackend)
2016
pNextRemoteUSBBackend->AddRef ();
2019
unlockConsoleVRDPServer ();
2021
if (pRemoteUSBBackend)
2023
pRemoteUSBBackend->Release ();
2028
return pNextRemoteUSBBackend;
2031
#ifdef VBOX_WITH_USB
2032
/* Internal method. Called under the ConsoleVRDPServerLock. */
2033
RemoteUSBBackend *ConsoleVRDPServer::usbBackendFind (uint32_t u32ClientId)
2035
RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
2037
while (pRemoteUSBBackend)
2039
if (pRemoteUSBBackend->ClientId () == u32ClientId)
2044
pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
2047
return pRemoteUSBBackend;
2050
/* Internal method. Called under the ConsoleVRDPServerLock. */
2051
RemoteUSBBackend *ConsoleVRDPServer::usbBackendFindByUUID (const Guid *pGuid)
2053
RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
2055
while (pRemoteUSBBackend)
2057
if (pRemoteUSBBackend->findUUID (pGuid))
2062
pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
2065
return pRemoteUSBBackend;
2069
/* Internal method. Called by the backend destructor. */
2070
void ConsoleVRDPServer::usbBackendRemoveFromList (RemoteUSBBackend *pRemoteUSBBackend)
2072
#ifdef VBOX_WITH_USB
2073
int rc = lockConsoleVRDPServer ();
2076
/* Exclude the found instance from the list. */
2077
if (pRemoteUSBBackend->pNext)
2079
pRemoteUSBBackend->pNext->pPrev = pRemoteUSBBackend->pPrev;
2083
mUSBBackends.pTail = (RemoteUSBBackend *)pRemoteUSBBackend->pPrev;
2086
if (pRemoteUSBBackend->pPrev)
2088
pRemoteUSBBackend->pPrev->pNext = pRemoteUSBBackend->pNext;
2092
mUSBBackends.pHead = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
2095
pRemoteUSBBackend->pNext = pRemoteUSBBackend->pPrev = NULL;
2097
unlockConsoleVRDPServer ();
2102
void ConsoleVRDPServer::SendUpdate (unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate) const
2104
#ifdef VBOX_WITH_VRDP
2105
if (mpEntryPoints && mhServer)
2107
mpEntryPoints->VRDPUpdate (mhServer, uScreenId, pvUpdate, cbUpdate);
2112
void ConsoleVRDPServer::SendResize (void) const
2114
#ifdef VBOX_WITH_VRDP
2115
if (mpEntryPoints && mhServer)
2117
mpEntryPoints->VRDPResize (mhServer);
2122
void ConsoleVRDPServer::SendUpdateBitmap (unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h) const
2124
#ifdef VBOX_WITH_VRDP
2125
VRDPORDERHDR update;
2130
if (mpEntryPoints && mhServer)
2132
mpEntryPoints->VRDPUpdate (mhServer, uScreenId, &update, sizeof (update));
2137
void ConsoleVRDPServer::SendAudioSamples (void *pvSamples, uint32_t cSamples, VRDPAUDIOFORMAT format) const
2139
#ifdef VBOX_WITH_VRDP
2140
if (mpEntryPoints && mhServer)
2142
mpEntryPoints->VRDPAudioSamples (mhServer, pvSamples, cSamples, format);
2147
void ConsoleVRDPServer::SendAudioVolume (uint16_t left, uint16_t right) const
2149
#ifdef VBOX_WITH_VRDP
2150
if (mpEntryPoints && mhServer)
2152
mpEntryPoints->VRDPAudioVolume (mhServer, left, right);
2157
void ConsoleVRDPServer::SendUSBRequest (uint32_t u32ClientId, void *pvParms, uint32_t cbParms) const
2159
#ifdef VBOX_WITH_VRDP
2160
if (mpEntryPoints && mhServer)
2162
mpEntryPoints->VRDPUSBRequest (mhServer, u32ClientId, pvParms, cbParms);
2167
void ConsoleVRDPServer::QueryInfo (uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const
2169
#ifdef VBOX_WITH_VRDP
2170
if (index == VRDP_QI_PORT)
2172
uint32_t cbOut = sizeof (int32_t);
2174
if (cbBuffer >= cbOut)
2177
*(int32_t *)pvBuffer = (int32_t)mVRDPBindPort;
2180
else if (mpEntryPoints && mhServer)
2182
mpEntryPoints->VRDPQueryInfo (mhServer, index, pvBuffer, cbBuffer, pcbOut);
2187
#ifdef VBOX_WITH_VRDP
2188
/* note: static function now! */
2189
bool ConsoleVRDPServer::loadVRDPLibrary (void)
2191
int rc = VINF_SUCCESS;
2195
rc = SUPR3HardenedLdrLoadAppPriv ("VBoxVRDP", &mVRDPLibrary);
2199
LogFlow(("VRDPServer::loadLibrary(): successfully loaded VRDP library.\n"));
2207
#define DEFSYMENTRY(a) { #a, (void**)&mpfn##a }
2209
static const struct SymbolEntry symbols[] =
2211
DEFSYMENTRY(VRDPCreateServer)
2216
for (unsigned i = 0; i < RT_ELEMENTS(symbols); i++)
2218
rc = RTLdrGetSymbol(mVRDPLibrary, symbols[i].name, symbols[i].ppfn);
2220
AssertMsgRC(rc, ("Error resolving VRDP symbol %s\n", symbols[i].name));
2230
LogRel(("VRDPServer::loadLibrary(): failed to load VRDP library! VRDP not available: rc = %Rrc\n", rc));
2231
mVRDPLibrary = NULL;
2240
RTLdrClose (mVRDPLibrary);
2241
mVRDPLibrary = NULL;
2245
return (mVRDPLibrary != NULL);
2247
#endif /* VBOX_WITH_VRDP */
2250
* IRemoteDisplayInfo implementation.
2252
// constructor / destructor
2253
/////////////////////////////////////////////////////////////////////////////
2255
RemoteDisplayInfo::RemoteDisplayInfo()
2260
RemoteDisplayInfo::~RemoteDisplayInfo()
2265
HRESULT RemoteDisplayInfo::FinalConstruct()
2270
void RemoteDisplayInfo::FinalRelease()
2275
// public methods only for internal purposes
2276
/////////////////////////////////////////////////////////////////////////////
2279
* Initializes the guest object.
2281
HRESULT RemoteDisplayInfo::init (Console *aParent)
2283
LogFlowThisFunc(("aParent=%p\n", aParent));
2285
ComAssertRet(aParent, E_INVALIDARG);
2287
/* Enclose the state transition NotReady->InInit->Ready */
2288
AutoInitSpan autoInitSpan(this);
2289
AssertReturn(autoInitSpan.isOk(), E_FAIL);
2291
unconst(mParent) = aParent;
2293
/* Confirm a successful initialization */
2294
autoInitSpan.setSucceeded();
2300
* Uninitializes the instance and sets the ready flag to FALSE.
2301
* Called either from FinalRelease() or by the parent when it gets destroyed.
2303
void RemoteDisplayInfo::uninit()
2305
LogFlowThisFunc(("\n"));
2307
/* Enclose the state transition Ready->InUninit->NotReady */
2308
AutoUninitSpan autoUninitSpan(this);
2309
if (autoUninitSpan.uninitDone())
2312
unconst(mParent) = NULL;
2315
// IRemoteDisplayInfo properties
2316
/////////////////////////////////////////////////////////////////////////////
2318
#define IMPL_GETTER_BOOL(_aType, _aName, _aIndex) \
2319
STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
2324
AutoCaller autoCaller(this); \
2325
if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2327
/* todo: Not sure if a AutoReadLock would be sufficient. */ \
2328
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2331
uint32_t cbOut = 0; \
2333
mParent->consoleVRDPServer ()->QueryInfo \
2334
(_aIndex, &value, sizeof (value), &cbOut); \
2336
*a##_aName = cbOut? !!value: FALSE; \
2340
extern void IMPL_GETTER_BOOL_DUMMY(void)
2342
#define IMPL_GETTER_SCALAR(_aType, _aName, _aIndex) \
2343
STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
2348
AutoCaller autoCaller(this); \
2349
if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2351
/* todo: Not sure if a AutoReadLock would be sufficient. */ \
2352
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2355
uint32_t cbOut = 0; \
2357
mParent->consoleVRDPServer ()->QueryInfo \
2358
(_aIndex, &value, sizeof (value), &cbOut); \
2360
*a##_aName = cbOut? value: 0; \
2364
extern void IMPL_GETTER_SCALAR_DUMMY(void)
2366
#define IMPL_GETTER_BSTR(_aType, _aName, _aIndex) \
2367
STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
2372
AutoCaller autoCaller(this); \
2373
if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2375
/* todo: Not sure if a AutoReadLock would be sufficient. */ \
2376
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2378
uint32_t cbOut = 0; \
2380
mParent->consoleVRDPServer ()->QueryInfo \
2381
(_aIndex, NULL, 0, &cbOut); \
2386
str.cloneTo(a##_aName); \
2390
char *pchBuffer = (char *)RTMemTmpAlloc (cbOut); \
2394
Log(("RemoteDisplayInfo::" \
2396
": Failed to allocate memory %d bytes\n", cbOut)); \
2397
return E_OUTOFMEMORY; \
2400
mParent->consoleVRDPServer ()->QueryInfo \
2401
(_aIndex, pchBuffer, cbOut, &cbOut); \
2403
Bstr str(pchBuffer); \
2405
str.cloneTo(a##_aName); \
2407
RTMemTmpFree (pchBuffer); \
2411
extern void IMPL_GETTER_BSTR_DUMMY(void)
2413
IMPL_GETTER_BOOL (BOOL, Active, VRDP_QI_ACTIVE);
2414
IMPL_GETTER_SCALAR (LONG, Port, VRDP_QI_PORT);
2415
IMPL_GETTER_SCALAR (ULONG, NumberOfClients, VRDP_QI_NUMBER_OF_CLIENTS);
2416
IMPL_GETTER_SCALAR (LONG64, BeginTime, VRDP_QI_BEGIN_TIME);
2417
IMPL_GETTER_SCALAR (LONG64, EndTime, VRDP_QI_END_TIME);
2418
IMPL_GETTER_SCALAR (ULONG64, BytesSent, VRDP_QI_BYTES_SENT);
2419
IMPL_GETTER_SCALAR (ULONG64, BytesSentTotal, VRDP_QI_BYTES_SENT_TOTAL);
2420
IMPL_GETTER_SCALAR (ULONG64, BytesReceived, VRDP_QI_BYTES_RECEIVED);
2421
IMPL_GETTER_SCALAR (ULONG64, BytesReceivedTotal, VRDP_QI_BYTES_RECEIVED_TOTAL);
2422
IMPL_GETTER_BSTR (BSTR, User, VRDP_QI_USER);
2423
IMPL_GETTER_BSTR (BSTR, Domain, VRDP_QI_DOMAIN);
2424
IMPL_GETTER_BSTR (BSTR, ClientName, VRDP_QI_CLIENT_NAME);
2425
IMPL_GETTER_BSTR (BSTR, ClientIP, VRDP_QI_CLIENT_IP);
2426
IMPL_GETTER_SCALAR (ULONG, ClientVersion, VRDP_QI_CLIENT_VERSION);
2427
IMPL_GETTER_SCALAR (ULONG, EncryptionStyle, VRDP_QI_ENCRYPTION_STYLE);
2429
#undef IMPL_GETTER_BSTR
2430
#undef IMPL_GETTER_SCALAR
2431
#undef IMPL_GETTER_BOOL
2432
/* vi: set tabstop=4 shiftwidth=4 expandtab: */