VirtualBox

source: vbox/trunk/src/VBox/Main/ConsoleVRDPServer.cpp@ 31812

Last change on this file since 31812 was 31747, checked in by vboxsync, 14 years ago

ConsoleVRDPServer.cpp: An academical correctness exercise related to r64842..

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 70.4 KB
Line 
1/* $Id: ConsoleVRDPServer.cpp 31747 2010-08-18 10:10:54Z vboxsync $ */
2/** @file
3 * VBox Console VRDP Helper class
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
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.
16 */
17
18#include "ConsoleVRDPServer.h"
19#include "ConsoleImpl.h"
20#include "DisplayImpl.h"
21#include "KeyboardImpl.h"
22#include "MouseImpl.h"
23
24#include "AutoCaller.h"
25#include "Logging.h"
26
27#include <iprt/asm.h>
28#include <iprt/ldr.h>
29#include <iprt/param.h>
30#include <iprt/path.h>
31#include <iprt/alloca.h>
32#include <iprt/cpp/utils.h>
33
34#include <VBox/err.h>
35#ifdef VBOX_WITH_VRDP
36#include <VBox/VRDPOrders.h>
37#endif /* VBOX_WITH_VRDP */
38
39class VRDPConsoleListener :
40 VBOX_SCRIPTABLE_IMPL(IEventListener)
41{
42public:
43 VRDPConsoleListener(ConsoleVRDPServer *server)
44 : m_server(server)
45 {
46#ifndef VBOX_WITH_XPCOM
47 refcnt = 0;
48#endif /* !VBOX_WITH_XPCOM */
49 }
50
51 virtual ~VRDPConsoleListener() {}
52
53 NS_DECL_ISUPPORTS
54
55#ifndef VBOX_WITH_XPCOM
56 STDMETHOD_(ULONG, AddRef)() {
57 return ::InterlockedIncrement(&refcnt);
58 }
59 STDMETHOD_(ULONG, Release)()
60 {
61 long cnt = ::InterlockedDecrement(&refcnt);
62 if (cnt == 0)
63 delete this;
64 return cnt;
65 }
66 STDMETHOD(QueryInterface)(REFIID riid , void **ppObj)
67 {
68 if (riid == IID_IUnknown) {
69 *ppObj = (IUnknown*)this;
70 AddRef();
71 return S_OK;
72 }
73 if (riid == IID_IEventListener) {
74 *ppObj = (IEventListener*)this;
75 AddRef();
76 return S_OK;
77 }
78 *ppObj = NULL;
79 return E_NOINTERFACE;
80 }
81#endif /* !VBOX_WITH_XPCOM */
82
83
84 STDMETHOD(HandleEvent)(IEvent * aEvent)
85 {
86 VBoxEventType_T aType = VBoxEventType_Invalid;
87
88 aEvent->COMGETTER(Type)(&aType);
89 switch (aType)
90 {
91 case VBoxEventType_OnMousePointerShapeChanged:
92 {
93 ComPtr<IMousePointerShapeChangedEvent> mpscev = aEvent;
94 Assert(mpscev);
95 BOOL visible, alpha;
96 ULONG xHot, yHot, width, height;
97 com::SafeArray <BYTE> shape;
98
99 mpscev->COMGETTER(Visible)(&visible);
100 mpscev->COMGETTER(Alpha)(&alpha);
101 mpscev->COMGETTER(Xhot)(&xHot);
102 mpscev->COMGETTER(Yhot)(&yHot);
103 mpscev->COMGETTER(Width)(&width);
104 mpscev->COMGETTER(Height)(&height);
105 mpscev->COMGETTER(Shape)(ComSafeArrayAsOutParam(shape));
106
107 OnMousePointerShapeChange(visible, alpha, xHot, yHot, width, height, ComSafeArrayAsInParam(shape));
108 break;
109 }
110 case VBoxEventType_OnMouseCapabilityChanged:
111 {
112 ComPtr<IMouseCapabilityChangedEvent> mccev = aEvent;
113 Assert(mccev);
114 if (m_server)
115 {
116 BOOL fAbsoluteMouse;
117 mccev->COMGETTER(SupportsAbsolute)(&fAbsoluteMouse);
118 m_server->NotifyAbsoluteMouse(!!fAbsoluteMouse);
119 }
120 break;
121 }
122 case VBoxEventType_OnKeyboardLedsChanged:
123 {
124 ComPtr<IKeyboardLedsChangedEvent> klcev = aEvent;
125 Assert(klcev);
126
127 if (m_server)
128 {
129 BOOL fNumLock, fCapsLock, fScrollLock;
130 klcev->COMGETTER(NumLock)(&fNumLock);
131 klcev->COMGETTER(CapsLock)(&fCapsLock);
132 klcev->COMGETTER(ScrollLock)(&fScrollLock);
133 m_server->NotifyKeyboardLedsChange(fNumLock, fCapsLock, fScrollLock);
134 }
135 break;
136 }
137
138 default:
139 AssertFailed();
140 }
141
142 return S_OK;
143 }
144
145private:
146 STDMETHOD(OnMousePointerShapeChange)(BOOL visible, BOOL alpha, ULONG xHot, ULONG yHot,
147 ULONG width, ULONG height, ComSafeArrayIn(BYTE,shape));
148 ConsoleVRDPServer *m_server;
149#ifndef VBOX_WITH_XPCOM
150 long refcnt;
151#endif /* !VBOX_WITH_XPCOM */
152};
153
154#ifdef VBOX_WITH_XPCOM
155#include <nsMemory.h>
156NS_DECL_CLASSINFO(VRDPConsoleListener)
157NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VRDPConsoleListener, IEventListener)
158#endif /* VBOX_WITH_XPCOM */
159
160#ifdef DEBUG_sunlover
161#define LOGDUMPPTR Log
162void dumpPointer(const uint8_t *pu8Shape, uint32_t width, uint32_t height, bool fXorMaskRGB32)
163{
164 unsigned i;
165
166 const uint8_t *pu8And = pu8Shape;
167
168 for (i = 0; i < height; i++)
169 {
170 unsigned j;
171 LOGDUMPPTR(("%p: ", pu8And));
172 for (j = 0; j < (width + 7) / 8; j++)
173 {
174 unsigned k;
175 for (k = 0; k < 8; k++)
176 {
177 LOGDUMPPTR(("%d", ((*pu8And) & (1 << (7 - k)))? 1: 0));
178 }
179
180 pu8And++;
181 }
182 LOGDUMPPTR(("\n"));
183 }
184
185 if (fXorMaskRGB32)
186 {
187 uint32_t *pu32Xor = (uint32_t*)(pu8Shape + ((((width + 7) / 8) * height + 3) & ~3));
188
189 for (i = 0; i < height; i++)
190 {
191 unsigned j;
192 LOGDUMPPTR(("%p: ", pu32Xor));
193 for (j = 0; j < width; j++)
194 {
195 LOGDUMPPTR(("%08X", *pu32Xor++));
196 }
197 LOGDUMPPTR(("\n"));
198 }
199 }
200 else
201 {
202 /* RDP 24 bit RGB mask. */
203 uint8_t *pu8Xor = (uint8_t*)(pu8Shape + ((((width + 7) / 8) * height + 3) & ~3));
204 for (i = 0; i < height; i++)
205 {
206 unsigned j;
207 LOGDUMPPTR(("%p: ", pu8Xor));
208 for (j = 0; j < width; j++)
209 {
210 LOGDUMPPTR(("%02X%02X%02X", pu8Xor[2], pu8Xor[1], pu8Xor[0]));
211 pu8Xor += 3;
212 }
213 LOGDUMPPTR(("\n"));
214 }
215 }
216}
217#else
218#define dumpPointer(a, b, c, d) do {} while (0)
219#endif /* DEBUG_sunlover */
220
221static void findTopLeftBorder(const uint8_t *pu8AndMask, const uint8_t *pu8XorMask, uint32_t width, uint32_t height, uint32_t *pxSkip, uint32_t *pySkip)
222{
223 /*
224 * Find the top border of the AND mask. First assign to special value.
225 */
226 uint32_t ySkipAnd = ~0;
227
228 const uint8_t *pu8And = pu8AndMask;
229 const uint32_t cbAndRow = (width + 7) / 8;
230 const uint8_t maskLastByte = (uint8_t)( 0xFF << (cbAndRow * 8 - width) );
231
232 Assert(cbAndRow > 0);
233
234 unsigned y;
235 unsigned x;
236
237 for (y = 0; y < height && ySkipAnd == ~(uint32_t)0; y++, pu8And += cbAndRow)
238 {
239 /* For each complete byte in the row. */
240 for (x = 0; x < cbAndRow - 1; x++)
241 {
242 if (pu8And[x] != 0xFF)
243 {
244 ySkipAnd = y;
245 break;
246 }
247 }
248
249 if (ySkipAnd == ~(uint32_t)0)
250 {
251 /* Last byte. */
252 if ((pu8And[cbAndRow - 1] & maskLastByte) != maskLastByte)
253 {
254 ySkipAnd = y;
255 }
256 }
257 }
258
259 if (ySkipAnd == ~(uint32_t)0)
260 {
261 ySkipAnd = 0;
262 }
263
264 /*
265 * Find the left border of the AND mask.
266 */
267 uint32_t xSkipAnd = ~0;
268
269 /* For all bit columns. */
270 for (x = 0; x < width && xSkipAnd == ~(uint32_t)0; x++)
271 {
272 pu8And = pu8AndMask + x/8; /* Currently checking byte. */
273 uint8_t mask = 1 << (7 - x%8); /* Currently checking bit in the byte. */
274
275 for (y = ySkipAnd; y < height; y++, pu8And += cbAndRow)
276 {
277 if ((*pu8And & mask) == 0)
278 {
279 xSkipAnd = x;
280 break;
281 }
282 }
283 }
284
285 if (xSkipAnd == ~(uint32_t)0)
286 {
287 xSkipAnd = 0;
288 }
289
290 /*
291 * Find the XOR mask top border.
292 */
293 uint32_t ySkipXor = ~0;
294
295 uint32_t *pu32XorStart = (uint32_t *)pu8XorMask;
296
297 uint32_t *pu32Xor = pu32XorStart;
298
299 for (y = 0; y < height && ySkipXor == ~(uint32_t)0; y++, pu32Xor += width)
300 {
301 for (x = 0; x < width; x++)
302 {
303 if (pu32Xor[x] != 0)
304 {
305 ySkipXor = y;
306 break;
307 }
308 }
309 }
310
311 if (ySkipXor == ~(uint32_t)0)
312 {
313 ySkipXor = 0;
314 }
315
316 /*
317 * Find the left border of the XOR mask.
318 */
319 uint32_t xSkipXor = ~(uint32_t)0;
320
321 /* For all columns. */
322 for (x = 0; x < width && xSkipXor == ~(uint32_t)0; x++)
323 {
324 pu32Xor = pu32XorStart + x; /* Currently checking dword. */
325
326 for (y = ySkipXor; y < height; y++, pu32Xor += width)
327 {
328 if (*pu32Xor != 0)
329 {
330 xSkipXor = x;
331 break;
332 }
333 }
334 }
335
336 if (xSkipXor == ~(uint32_t)0)
337 {
338 xSkipXor = 0;
339 }
340
341 *pxSkip = RT_MIN(xSkipAnd, xSkipXor);
342 *pySkip = RT_MIN(ySkipAnd, ySkipXor);
343}
344
345/* Generate an AND mask for alpha pointers here, because
346 * guest driver does not do that correctly for Vista pointers.
347 * Similar fix, changing the alpha threshold, could be applied
348 * for the guest driver, but then additions reinstall would be
349 * necessary, which we try to avoid.
350 */
351static void mousePointerGenerateANDMask(uint8_t *pu8DstAndMask, int cbDstAndMask, const uint8_t *pu8SrcAlpha, int w, int h)
352{
353 memset(pu8DstAndMask, 0xFF, cbDstAndMask);
354
355 int y;
356 for (y = 0; y < h; y++)
357 {
358 uint8_t bitmask = 0x80;
359
360 int x;
361 for (x = 0; x < w; x++, bitmask >>= 1)
362 {
363 if (bitmask == 0)
364 {
365 bitmask = 0x80;
366 }
367
368 /* Whether alpha channel value is not transparent enough for the pixel to be seen. */
369 if (pu8SrcAlpha[x * 4 + 3] > 0x7f)
370 {
371 pu8DstAndMask[x / 8] &= ~bitmask;
372 }
373 }
374
375 /* Point to next source and dest scans. */
376 pu8SrcAlpha += w * 4;
377 pu8DstAndMask += (w + 7) / 8;
378 }
379}
380
381STDMETHODIMP VRDPConsoleListener::OnMousePointerShapeChange(BOOL visible,
382 BOOL alpha,
383 ULONG xHot,
384 ULONG yHot,
385 ULONG width,
386 ULONG height,
387 ComSafeArrayIn(BYTE,inShape))
388{
389 LogSunlover(("VRDPConsoleListener::OnMousePointerShapeChange: %d, %d, %lux%lu, @%lu,%lu\n", visible, alpha, width, height, xHot, yHot));
390
391 if (m_server)
392 {
393 com::SafeArray <BYTE> aShape(ComSafeArrayInArg (inShape));
394 if (aShape.size() == 0)
395 {
396 if (!visible)
397 {
398 m_server->MousePointerHide();
399 }
400 }
401 else if (width != 0 && height != 0)
402 {
403 /* Pointer consists of 1 bpp AND and 24 BPP XOR masks.
404 * 'shape' AND mask followed by XOR mask.
405 * XOR mask contains 32 bit (lsb)BGR0(msb) values.
406 *
407 * We convert this to RDP color format which consist of
408 * one bpp AND mask and 24 BPP (BGR) color XOR image.
409 *
410 * RDP clients expect 8 aligned width and height of
411 * pointer (preferably 32x32).
412 *
413 * They even contain bugs which do not appear for
414 * 32x32 pointers but would appear for a 41x32 one.
415 *
416 * So set pointer size to 32x32. This can be done safely
417 * because most pointers are 32x32.
418 */
419 uint8_t* shape = aShape.raw();
420
421 dumpPointer(shape, width, height, true);
422
423 int cbDstAndMask = (((width + 7) / 8) * height + 3) & ~3;
424
425 uint8_t *pu8AndMask = shape;
426 uint8_t *pu8XorMask = shape + cbDstAndMask;
427
428 if (alpha)
429 {
430 pu8AndMask = (uint8_t*)alloca(cbDstAndMask);
431
432 mousePointerGenerateANDMask(pu8AndMask, cbDstAndMask, pu8XorMask, width, height);
433 }
434
435 /* Windows guest alpha pointers are wider than 32 pixels.
436 * Try to find out the top-left border of the pointer and
437 * then copy only meaningful bits. All complete top rows
438 * and all complete left columns where (AND == 1 && XOR == 0)
439 * are skipped. Hot spot is adjusted.
440 */
441 uint32_t ySkip = 0; /* How many rows to skip at the top. */
442 uint32_t xSkip = 0; /* How many columns to skip at the left. */
443
444 findTopLeftBorder(pu8AndMask, pu8XorMask, width, height, &xSkip, &ySkip);
445
446 /* Must not skip the hot spot. */
447 xSkip = RT_MIN(xSkip, xHot);
448 ySkip = RT_MIN(ySkip, yHot);
449
450 /*
451 * Compute size and allocate memory for the pointer.
452 */
453 const uint32_t dstwidth = 32;
454 const uint32_t dstheight = 32;
455
456 VRDPCOLORPOINTER *pointer = NULL;
457
458 uint32_t dstmaskwidth = (dstwidth + 7) / 8;
459
460 uint32_t rdpmaskwidth = dstmaskwidth;
461 uint32_t rdpmasklen = dstheight * rdpmaskwidth;
462
463 uint32_t rdpdatawidth = dstwidth * 3;
464 uint32_t rdpdatalen = dstheight * rdpdatawidth;
465
466 pointer = (VRDPCOLORPOINTER *)RTMemTmpAlloc(sizeof(VRDPCOLORPOINTER) + rdpmasklen + rdpdatalen);
467
468 if (pointer)
469 {
470 uint8_t *maskarray = (uint8_t*)pointer + sizeof(VRDPCOLORPOINTER);
471 uint8_t *dataarray = maskarray + rdpmasklen;
472
473 memset(maskarray, 0xFF, rdpmasklen);
474 memset(dataarray, 0x00, rdpdatalen);
475
476 uint32_t srcmaskwidth = (width + 7) / 8;
477 uint32_t srcdatawidth = width * 4;
478
479 /* Copy AND mask. */
480 uint8_t *src = pu8AndMask + ySkip * srcmaskwidth;
481 uint8_t *dst = maskarray + (dstheight - 1) * rdpmaskwidth;
482
483 uint32_t minheight = RT_MIN(height - ySkip, dstheight);
484 uint32_t minwidth = RT_MIN(width - xSkip, dstwidth);
485
486 unsigned x, y;
487
488 for (y = 0; y < minheight; y++)
489 {
490 for (x = 0; x < minwidth; x++)
491 {
492 uint32_t byteIndex = (x + xSkip) / 8;
493 uint32_t bitIndex = (x + xSkip) % 8;
494
495 bool bit = (src[byteIndex] & (1 << (7 - bitIndex))) != 0;
496
497 if (!bit)
498 {
499 byteIndex = x / 8;
500 bitIndex = x % 8;
501
502 dst[byteIndex] &= ~(1 << (7 - bitIndex));
503 }
504 }
505
506 src += srcmaskwidth;
507 dst -= rdpmaskwidth;
508 }
509
510 /* Point src to XOR mask */
511 src = pu8XorMask + ySkip * srcdatawidth;
512 dst = dataarray + (dstheight - 1) * rdpdatawidth;
513
514 for (y = 0; y < minheight ; y++)
515 {
516 for (x = 0; x < minwidth; x++)
517 {
518 memcpy(dst + x * 3, &src[4 * (x + xSkip)], 3);
519 }
520
521 src += srcdatawidth;
522 dst -= rdpdatawidth;
523 }
524
525 pointer->u16HotX = (uint16_t)(xHot - xSkip);
526 pointer->u16HotY = (uint16_t)(yHot - ySkip);
527
528 pointer->u16Width = (uint16_t)dstwidth;
529 pointer->u16Height = (uint16_t)dstheight;
530
531 pointer->u16MaskLen = (uint16_t)rdpmasklen;
532 pointer->u16DataLen = (uint16_t)rdpdatalen;
533
534 dumpPointer((uint8_t*)pointer + sizeof(*pointer), dstwidth, dstheight, false);
535
536 m_server->MousePointerUpdate(pointer);
537
538 RTMemTmpFree(pointer);
539 }
540 }
541 }
542
543 return S_OK;
544}
545
546
547// ConsoleVRDPServer
548////////////////////////////////////////////////////////////////////////////////
549
550#ifdef VBOX_WITH_VRDP
551RTLDRMOD ConsoleVRDPServer::mVRDPLibrary;
552
553PFNVRDPCREATESERVER ConsoleVRDPServer::mpfnVRDPCreateServer = NULL;
554
555VRDPENTRYPOINTS_1 *ConsoleVRDPServer::mpEntryPoints = NULL;
556
557VRDPCALLBACKS_1 ConsoleVRDPServer::mCallbacks =
558{
559 { VRDP_INTERFACE_VERSION_1, sizeof(VRDPCALLBACKS_1) },
560 ConsoleVRDPServer::VRDPCallbackQueryProperty,
561 ConsoleVRDPServer::VRDPCallbackClientLogon,
562 ConsoleVRDPServer::VRDPCallbackClientConnect,
563 ConsoleVRDPServer::VRDPCallbackClientDisconnect,
564 ConsoleVRDPServer::VRDPCallbackIntercept,
565 ConsoleVRDPServer::VRDPCallbackUSB,
566 ConsoleVRDPServer::VRDPCallbackClipboard,
567 ConsoleVRDPServer::VRDPCallbackFramebufferQuery,
568 ConsoleVRDPServer::VRDPCallbackFramebufferLock,
569 ConsoleVRDPServer::VRDPCallbackFramebufferUnlock,
570 ConsoleVRDPServer::VRDPCallbackInput,
571 ConsoleVRDPServer::VRDPCallbackVideoModeHint
572};
573
574DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackQueryProperty(void *pvCallback, uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut)
575{
576 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
577
578 int rc = VERR_NOT_SUPPORTED;
579
580 switch (index)
581 {
582 case VRDP_QP_NETWORK_PORT:
583 {
584 /* This is obsolete, the VRDP server uses VRDP_QP_NETWORK_PORT_RANGE instead. */
585 ULONG port = 0;
586
587 if (cbBuffer >= sizeof(uint32_t))
588 {
589 *(uint32_t *)pvBuffer = (uint32_t)port;
590 rc = VINF_SUCCESS;
591 }
592 else
593 {
594 rc = VINF_BUFFER_OVERFLOW;
595 }
596
597 *pcbOut = sizeof(uint32_t);
598 } break;
599
600 case VRDP_QP_NETWORK_ADDRESS:
601 {
602 com::Bstr bstr;
603 server->mConsole->getVRDPServer()->COMGETTER(NetAddress)(bstr.asOutParam());
604
605 /* The server expects UTF8. */
606 com::Utf8Str address = bstr;
607
608 size_t cbAddress = address.length() + 1;
609
610 if (cbAddress >= 0x10000)
611 {
612 /* More than 64K seems to be an invalid address. */
613 rc = VERR_TOO_MUCH_DATA;
614 break;
615 }
616
617 if ((size_t)cbBuffer >= cbAddress)
618 {
619 memcpy(pvBuffer, address.c_str(), cbAddress);
620 rc = VINF_SUCCESS;
621 }
622 else
623 {
624 rc = VINF_BUFFER_OVERFLOW;
625 }
626
627 *pcbOut = (uint32_t)cbAddress;
628 } break;
629
630 case VRDP_QP_NUMBER_MONITORS:
631 {
632 ULONG cMonitors = 1;
633
634 server->mConsole->machine()->COMGETTER(MonitorCount)(&cMonitors);
635
636 if (cbBuffer >= sizeof(uint32_t))
637 {
638 *(uint32_t *)pvBuffer = (uint32_t)cMonitors;
639 rc = VINF_SUCCESS;
640 }
641 else
642 {
643 rc = VINF_BUFFER_OVERFLOW;
644 }
645
646 *pcbOut = sizeof(uint32_t);
647 } break;
648
649 case VRDP_QP_NETWORK_PORT_RANGE:
650 {
651 com::Bstr bstr;
652 HRESULT hrc = server->mConsole->getVRDPServer()->COMGETTER(Ports)(bstr.asOutParam());
653
654 if (hrc != S_OK)
655 {
656 bstr = "";
657 }
658
659 if (bstr == "0")
660 {
661 bstr = "3389";
662 }
663
664 /* The server expects UTF8. */
665 com::Utf8Str portRange = bstr;
666
667 size_t cbPortRange = portRange.length () + 1;
668
669 if (cbPortRange >= 0x10000)
670 {
671 /* More than 64K seems to be an invalid port range string. */
672 rc = VERR_TOO_MUCH_DATA;
673 break;
674 }
675
676 if ((size_t)cbBuffer >= cbPortRange)
677 {
678 memcpy(pvBuffer, portRange.c_str(), cbPortRange);
679 rc = VINF_SUCCESS;
680 }
681 else
682 {
683 rc = VINF_BUFFER_OVERFLOW;
684 }
685
686 *pcbOut = (uint32_t)cbPortRange;
687 } break;
688
689#ifdef VBOX_WITH_VRDP_VIDEO_CHANNEL
690 case VRDP_QP_VIDEO_CHANNEL:
691 {
692 BOOL fVideoEnabled = FALSE;
693
694 server->mConsole->getVRDPServer()->COMGETTER(VideoChannel)(&fVideoEnabled);
695
696 if (cbBuffer >= sizeof(uint32_t))
697 {
698 *(uint32_t *)pvBuffer = (uint32_t)fVideoEnabled;
699 rc = VINF_SUCCESS;
700 }
701 else
702 {
703 rc = VINF_BUFFER_OVERFLOW;
704 }
705
706 *pcbOut = sizeof(uint32_t);
707 } break;
708
709 case VRDP_QP_VIDEO_CHANNEL_QUALITY:
710 {
711 ULONG ulQuality = 0;
712
713 server->mConsole->getVRDPServer()->COMGETTER(VideoChannelQuality)(&ulQuality);
714
715 if (cbBuffer >= sizeof(uint32_t))
716 {
717 *(uint32_t *)pvBuffer = (uint32_t)ulQuality;
718 rc = VINF_SUCCESS;
719 }
720 else
721 {
722 rc = VINF_BUFFER_OVERFLOW;
723 }
724
725 *pcbOut = sizeof(uint32_t);
726 } break;
727
728 case VRDP_QP_VIDEO_CHANNEL_SUNFLSH:
729 {
730 ULONG ulSunFlsh = 1;
731
732 com::Bstr bstr;
733 HRESULT hrc = server->mConsole->machine ()->GetExtraData(Bstr("VRDP/SunFlsh"), bstr.asOutParam());
734 if (hrc == S_OK && !bstr.isEmpty())
735 {
736 com::Utf8Str sunFlsh = bstr;
737 if (!sunFlsh.isEmpty())
738 {
739 ulSunFlsh = sunFlsh.toUInt32();
740 }
741 }
742
743 if (cbBuffer >= sizeof(uint32_t))
744 {
745 *(uint32_t *)pvBuffer = (uint32_t)ulSunFlsh;
746 rc = VINF_SUCCESS;
747 }
748 else
749 {
750 rc = VINF_BUFFER_OVERFLOW;
751 }
752
753 *pcbOut = sizeof(uint32_t);
754 } break;
755#endif /* VBOX_WITH_VRDP_VIDEO_CHANNEL */
756
757 case VRDP_SP_NETWORK_BIND_PORT:
758 {
759 if (cbBuffer != sizeof(uint32_t))
760 {
761 rc = VERR_INVALID_PARAMETER;
762 break;
763 }
764
765 ULONG port = *(uint32_t *)pvBuffer;
766
767 server->mVRDPBindPort = port;
768
769 rc = VINF_SUCCESS;
770
771 if (pcbOut)
772 {
773 *pcbOut = sizeof(uint32_t);
774 }
775
776 server->mConsole->onRemoteDisplayInfoChange();
777 } break;
778
779 default:
780 break;
781 }
782
783 return rc;
784}
785
786DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClientLogon(void *pvCallback, uint32_t u32ClientId, const char *pszUser, const char *pszPassword, const char *pszDomain)
787{
788 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
789
790 return server->mConsole->VRDPClientLogon (u32ClientId, pszUser, pszPassword, pszDomain);
791}
792
793DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientConnect (void *pvCallback, uint32_t u32ClientId)
794{
795 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
796
797 server->mConsole->VRDPClientConnect (u32ClientId);
798}
799
800DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientDisconnect (void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercepted)
801{
802 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
803
804 server->mConsole->VRDPClientDisconnect (u32ClientId, fu32Intercepted);
805}
806
807DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackIntercept (void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercept, void **ppvIntercept)
808{
809 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
810
811 LogFlowFunc(("%x\n", fu32Intercept));
812
813 int rc = VERR_NOT_SUPPORTED;
814
815 switch (fu32Intercept)
816 {
817 case VRDP_CLIENT_INTERCEPT_AUDIO:
818 {
819 server->mConsole->VRDPInterceptAudio (u32ClientId);
820 if (ppvIntercept)
821 {
822 *ppvIntercept = server;
823 }
824 rc = VINF_SUCCESS;
825 } break;
826
827 case VRDP_CLIENT_INTERCEPT_USB:
828 {
829 server->mConsole->VRDPInterceptUSB (u32ClientId, ppvIntercept);
830 rc = VINF_SUCCESS;
831 } break;
832
833 case VRDP_CLIENT_INTERCEPT_CLIPBOARD:
834 {
835 server->mConsole->VRDPInterceptClipboard (u32ClientId);
836 if (ppvIntercept)
837 {
838 *ppvIntercept = server;
839 }
840 rc = VINF_SUCCESS;
841 } break;
842
843 default:
844 break;
845 }
846
847 return rc;
848}
849
850DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackUSB (void *pvCallback, void *pvIntercept, uint32_t u32ClientId, uint8_t u8Code, const void *pvRet, uint32_t cbRet)
851{
852#ifdef VBOX_WITH_USB
853 return USBClientResponseCallback (pvIntercept, u32ClientId, u8Code, pvRet, cbRet);
854#else
855 return VERR_NOT_SUPPORTED;
856#endif
857}
858
859DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClipboard (void *pvCallback, void *pvIntercept, uint32_t u32ClientId, uint32_t u32Function, uint32_t u32Format, const void *pvData, uint32_t cbData)
860{
861 return ClipboardCallback (pvIntercept, u32ClientId, u32Function, u32Format, pvData, cbData);
862}
863
864DECLCALLBACK(bool) ConsoleVRDPServer::VRDPCallbackFramebufferQuery (void *pvCallback, unsigned uScreenId, VRDPFRAMEBUFFERINFO *pInfo)
865{
866 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
867
868 bool fAvailable = false;
869
870 IFramebuffer *pfb = NULL;
871 LONG xOrigin = 0;
872 LONG yOrigin = 0;
873
874 server->mConsole->getDisplay ()->GetFramebuffer (uScreenId, &pfb, &xOrigin, &yOrigin);
875
876 if (pfb)
877 {
878 pfb->Lock ();
879
880 /* Query framebuffer parameters. */
881 ULONG lineSize = 0;
882 pfb->COMGETTER(BytesPerLine) (&lineSize);
883
884 ULONG bitsPerPixel = 0;
885 pfb->COMGETTER(BitsPerPixel) (&bitsPerPixel);
886
887 BYTE *address = NULL;
888 pfb->COMGETTER(Address) (&address);
889
890 ULONG height = 0;
891 pfb->COMGETTER(Height) (&height);
892
893 ULONG width = 0;
894 pfb->COMGETTER(Width) (&width);
895
896 /* Now fill the information as requested by the caller. */
897 pInfo->pu8Bits = address;
898 pInfo->xOrigin = xOrigin;
899 pInfo->yOrigin = yOrigin;
900 pInfo->cWidth = width;
901 pInfo->cHeight = height;
902 pInfo->cBitsPerPixel = bitsPerPixel;
903 pInfo->cbLine = lineSize;
904
905 pfb->Unlock ();
906
907 fAvailable = true;
908 }
909
910 if (server->maFramebuffers[uScreenId])
911 {
912 server->maFramebuffers[uScreenId]->Release ();
913 }
914 server->maFramebuffers[uScreenId] = pfb;
915
916 return fAvailable;
917}
918
919DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferLock (void *pvCallback, unsigned uScreenId)
920{
921 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
922
923 if (server->maFramebuffers[uScreenId])
924 {
925 server->maFramebuffers[uScreenId]->Lock ();
926 }
927}
928
929DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferUnlock (void *pvCallback, unsigned uScreenId)
930{
931 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
932
933 if (server->maFramebuffers[uScreenId])
934 {
935 server->maFramebuffers[uScreenId]->Unlock ();
936 }
937}
938
939static void fixKbdLockStatus (VRDPInputSynch *pInputSynch, IKeyboard *pKeyboard)
940{
941 if ( pInputSynch->cGuestNumLockAdaptions
942 && (pInputSynch->fGuestNumLock != pInputSynch->fClientNumLock))
943 {
944 pInputSynch->cGuestNumLockAdaptions--;
945 pKeyboard->PutScancode(0x45);
946 pKeyboard->PutScancode(0x45 | 0x80);
947 }
948 if ( pInputSynch->cGuestCapsLockAdaptions
949 && (pInputSynch->fGuestCapsLock != pInputSynch->fClientCapsLock))
950 {
951 pInputSynch->cGuestCapsLockAdaptions--;
952 pKeyboard->PutScancode(0x3a);
953 pKeyboard->PutScancode(0x3a | 0x80);
954 }
955}
956
957DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackInput (void *pvCallback, int type, const void *pvInput, unsigned cbInput)
958{
959 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
960 Console *pConsole = server->mConsole;
961
962 switch (type)
963 {
964 case VRDP_INPUT_SCANCODE:
965 {
966 if (cbInput == sizeof (VRDPINPUTSCANCODE))
967 {
968 IKeyboard *pKeyboard = pConsole->getKeyboard ();
969
970 const VRDPINPUTSCANCODE *pInputScancode = (VRDPINPUTSCANCODE *)pvInput;
971
972 /* Track lock keys. */
973 if (pInputScancode->uScancode == 0x45)
974 {
975 server->m_InputSynch.fClientNumLock = !server->m_InputSynch.fClientNumLock;
976 }
977 else if (pInputScancode->uScancode == 0x3a)
978 {
979 server->m_InputSynch.fClientCapsLock = !server->m_InputSynch.fClientCapsLock;
980 }
981 else if (pInputScancode->uScancode == 0x46)
982 {
983 server->m_InputSynch.fClientScrollLock = !server->m_InputSynch.fClientScrollLock;
984 }
985 else if ((pInputScancode->uScancode & 0x80) == 0)
986 {
987 /* Key pressed. */
988 fixKbdLockStatus (&server->m_InputSynch, pKeyboard);
989 }
990
991 pKeyboard->PutScancode((LONG)pInputScancode->uScancode);
992 }
993 } break;
994
995 case VRDP_INPUT_POINT:
996 {
997 if (cbInput == sizeof (VRDPINPUTPOINT))
998 {
999 const VRDPINPUTPOINT *pInputPoint = (VRDPINPUTPOINT *)pvInput;
1000
1001 int mouseButtons = 0;
1002 int iWheel = 0;
1003
1004 if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON1)
1005 {
1006 mouseButtons |= MouseButtonState_LeftButton;
1007 }
1008 if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON2)
1009 {
1010 mouseButtons |= MouseButtonState_RightButton;
1011 }
1012 if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON3)
1013 {
1014 mouseButtons |= MouseButtonState_MiddleButton;
1015 }
1016 if (pInputPoint->uButtons & VRDP_INPUT_POINT_WHEEL_UP)
1017 {
1018 mouseButtons |= MouseButtonState_WheelUp;
1019 iWheel = -1;
1020 }
1021 if (pInputPoint->uButtons & VRDP_INPUT_POINT_WHEEL_DOWN)
1022 {
1023 mouseButtons |= MouseButtonState_WheelDown;
1024 iWheel = 1;
1025 }
1026
1027 if (server->m_fGuestWantsAbsolute)
1028 {
1029 pConsole->getMouse()->PutMouseEventAbsolute (pInputPoint->x + 1, pInputPoint->y + 1, iWheel, 0 /* Horizontal wheel */, mouseButtons);
1030 } else
1031 {
1032 pConsole->getMouse()->PutMouseEvent (pInputPoint->x - server->m_mousex,
1033 pInputPoint->y - server->m_mousey,
1034 iWheel, 0 /* Horizontal wheel */, mouseButtons);
1035 server->m_mousex = pInputPoint->x;
1036 server->m_mousey = pInputPoint->y;
1037 }
1038 }
1039 } break;
1040
1041 case VRDP_INPUT_CAD:
1042 {
1043 pConsole->getKeyboard ()->PutCAD();
1044 } break;
1045
1046 case VRDP_INPUT_RESET:
1047 {
1048 pConsole->Reset();
1049 } break;
1050
1051 case VRDP_INPUT_SYNCH:
1052 {
1053 if (cbInput == sizeof (VRDPINPUTSYNCH))
1054 {
1055 IKeyboard *pKeyboard = pConsole->getKeyboard ();
1056
1057 const VRDPINPUTSYNCH *pInputSynch = (VRDPINPUTSYNCH *)pvInput;
1058
1059 server->m_InputSynch.fClientNumLock = (pInputSynch->uLockStatus & VRDP_INPUT_SYNCH_NUMLOCK) != 0;
1060 server->m_InputSynch.fClientCapsLock = (pInputSynch->uLockStatus & VRDP_INPUT_SYNCH_CAPITAL) != 0;
1061 server->m_InputSynch.fClientScrollLock = (pInputSynch->uLockStatus & VRDP_INPUT_SYNCH_SCROLL) != 0;
1062
1063 /* The client initiated synchronization. Always make the guest to reflect the client state.
1064 * Than means, when the guest changes the state itself, it is forced to return to the client
1065 * state.
1066 */
1067 if (server->m_InputSynch.fClientNumLock != server->m_InputSynch.fGuestNumLock)
1068 {
1069 server->m_InputSynch.cGuestNumLockAdaptions = 2;
1070 }
1071
1072 if (server->m_InputSynch.fClientCapsLock != server->m_InputSynch.fGuestCapsLock)
1073 {
1074 server->m_InputSynch.cGuestCapsLockAdaptions = 2;
1075 }
1076
1077 fixKbdLockStatus (&server->m_InputSynch, pKeyboard);
1078 }
1079 } break;
1080
1081 default:
1082 break;
1083 }
1084}
1085
1086DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackVideoModeHint (void *pvCallback, unsigned cWidth, unsigned cHeight, unsigned cBitsPerPixel, unsigned uScreenId)
1087{
1088 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1089
1090 server->mConsole->getDisplay()->SetVideoModeHint(cWidth, cHeight, cBitsPerPixel, uScreenId);
1091}
1092#endif /* VBOX_WITH_VRDP */
1093
1094ConsoleVRDPServer::ConsoleVRDPServer (Console *console)
1095{
1096 mConsole = console;
1097
1098 int rc = RTCritSectInit(&mCritSect);
1099 AssertRC(rc);
1100
1101 mcClipboardRefs = 0;
1102 mpfnClipboardCallback = NULL;
1103
1104#ifdef VBOX_WITH_USB
1105 mUSBBackends.pHead = NULL;
1106 mUSBBackends.pTail = NULL;
1107
1108 mUSBBackends.thread = NIL_RTTHREAD;
1109 mUSBBackends.fThreadRunning = false;
1110 mUSBBackends.event = 0;
1111#endif
1112
1113#ifdef VBOX_WITH_VRDP
1114 mhServer = 0;
1115
1116 m_fGuestWantsAbsolute = false;
1117 m_mousex = 0;
1118 m_mousey = 0;
1119
1120 m_InputSynch.cGuestNumLockAdaptions = 2;
1121 m_InputSynch.cGuestCapsLockAdaptions = 2;
1122
1123 m_InputSynch.fGuestNumLock = false;
1124 m_InputSynch.fGuestCapsLock = false;
1125 m_InputSynch.fGuestScrollLock = false;
1126
1127 m_InputSynch.fClientNumLock = false;
1128 m_InputSynch.fClientCapsLock = false;
1129 m_InputSynch.fClientScrollLock = false;
1130
1131 memset (maFramebuffers, 0, sizeof (maFramebuffers));
1132
1133 {
1134 ComPtr<IEventSource> es;
1135 console->COMGETTER(EventSource)(es.asOutParam());
1136 mConsoleListener = new VRDPConsoleListener(this);
1137 mConsoleListener->AddRef();
1138 com::SafeArray <VBoxEventType_T> eventTypes;
1139 eventTypes.push_back(VBoxEventType_OnMousePointerShapeChanged);
1140 eventTypes.push_back(VBoxEventType_OnMouseCapabilityChanged);
1141 eventTypes.push_back(VBoxEventType_OnKeyboardLedsChanged);
1142 es->RegisterListener(mConsoleListener, ComSafeArrayAsInParam(eventTypes), true);
1143 }
1144
1145 mVRDPBindPort = -1;
1146#endif /* VBOX_WITH_VRDP */
1147
1148 mAuthLibrary = 0;
1149}
1150
1151ConsoleVRDPServer::~ConsoleVRDPServer ()
1152{
1153 Stop ();
1154
1155#ifdef VBOX_WITH_VRDP
1156 if (mConsoleListener)
1157 {
1158 ComPtr<IEventSource> es;
1159 mConsole->COMGETTER(EventSource)(es.asOutParam());
1160 es->UnregisterListener(mConsoleListener);
1161 mConsoleListener->Release();
1162 mConsoleListener = NULL;
1163 }
1164
1165 unsigned i;
1166 for (i = 0; i < RT_ELEMENTS(maFramebuffers); i++)
1167 {
1168 if (maFramebuffers[i])
1169 {
1170 maFramebuffers[i]->Release ();
1171 maFramebuffers[i] = NULL;
1172 }
1173 }
1174#endif /* VBOX_WITH_VRDP */
1175
1176 if (RTCritSectIsInitialized (&mCritSect))
1177 {
1178 RTCritSectDelete (&mCritSect);
1179 memset (&mCritSect, 0, sizeof (mCritSect));
1180 }
1181}
1182
1183int ConsoleVRDPServer::Launch (void)
1184{
1185 LogFlowThisFunc(("\n"));
1186#ifdef VBOX_WITH_VRDP
1187 int rc = VINF_SUCCESS;
1188 IVRDPServer *vrdpserver = mConsole->getVRDPServer ();
1189 Assert(vrdpserver);
1190 BOOL vrdpEnabled = FALSE;
1191
1192 HRESULT rc2 = vrdpserver->COMGETTER(Enabled) (&vrdpEnabled);
1193 AssertComRC(rc2);
1194
1195 if (SUCCEEDED(rc2) && vrdpEnabled)
1196 {
1197 if (loadVRDPLibrary ())
1198 {
1199 rc = mpfnVRDPCreateServer (&mCallbacks.header, this, (VRDPINTERFACEHDR **)&mpEntryPoints, &mhServer);
1200
1201 if (RT_SUCCESS(rc))
1202 {
1203#ifdef VBOX_WITH_USB
1204 remoteUSBThreadStart ();
1205#endif /* VBOX_WITH_USB */
1206 }
1207 else if (rc != VERR_NET_ADDRESS_IN_USE)
1208 AssertMsgFailed(("Could not start VRDP server: rc = %Rrc\n", rc));
1209 }
1210 else
1211 {
1212 AssertMsgFailed(("Could not load the VRDP library\n"));
1213 rc = VERR_FILE_NOT_FOUND;
1214 }
1215 }
1216#else
1217 int rc = VERR_NOT_SUPPORTED;
1218 LogRel(("VRDP: this version does not include the VRDP server.\n"));
1219#endif /* VBOX_WITH_VRDP */
1220 return rc;
1221}
1222
1223void ConsoleVRDPServer::EnableConnections (void)
1224{
1225#ifdef VBOX_WITH_VRDP
1226 if (mpEntryPoints && mhServer)
1227 {
1228 mpEntryPoints->VRDPEnableConnections (mhServer, true);
1229 }
1230#endif /* VBOX_WITH_VRDP */
1231}
1232
1233void ConsoleVRDPServer::DisconnectClient (uint32_t u32ClientId, bool fReconnect)
1234{
1235#ifdef VBOX_WITH_VRDP
1236 if (mpEntryPoints && mhServer)
1237 {
1238 mpEntryPoints->VRDPDisconnect (mhServer, u32ClientId, fReconnect);
1239 }
1240#endif /* VBOX_WITH_VRDP */
1241}
1242
1243void ConsoleVRDPServer::MousePointerUpdate (const VRDPCOLORPOINTER *pPointer)
1244{
1245#ifdef VBOX_WITH_VRDP
1246 if (mpEntryPoints && mhServer)
1247 {
1248 mpEntryPoints->VRDPColorPointer (mhServer, pPointer);
1249 }
1250#endif /* VBOX_WITH_VRDP */
1251}
1252
1253void ConsoleVRDPServer::MousePointerHide (void)
1254{
1255#ifdef VBOX_WITH_VRDP
1256 if (mpEntryPoints && mhServer)
1257 {
1258 mpEntryPoints->VRDPHidePointer (mhServer);
1259 }
1260#endif /* VBOX_WITH_VRDP */
1261}
1262
1263void ConsoleVRDPServer::Stop (void)
1264{
1265 Assert(VALID_PTR(this)); /** @todo r=bird: there are(/was) some odd cases where this buster was invalid on
1266 * linux. Just remove this when it's 100% sure that problem has been fixed. */
1267#ifdef VBOX_WITH_VRDP
1268 if (mhServer)
1269 {
1270 HVRDPSERVER hServer = mhServer;
1271
1272 /* Reset the handle to avoid further calls to the server. */
1273 mhServer = 0;
1274
1275 if (mpEntryPoints && hServer)
1276 {
1277 mpEntryPoints->VRDPDestroy (hServer);
1278 }
1279 }
1280#endif /* VBOX_WITH_VRDP */
1281
1282#ifdef VBOX_WITH_USB
1283 remoteUSBThreadStop ();
1284#endif /* VBOX_WITH_USB */
1285
1286 mpfnAuthEntry = NULL;
1287 mpfnAuthEntry2 = NULL;
1288
1289 if (mAuthLibrary)
1290 {
1291 RTLdrClose(mAuthLibrary);
1292 mAuthLibrary = 0;
1293 }
1294}
1295
1296/* Worker thread for Remote USB. The thread polls the clients for
1297 * the list of attached USB devices.
1298 * The thread is also responsible for attaching/detaching devices
1299 * to/from the VM.
1300 *
1301 * It is expected that attaching/detaching is not a frequent operation.
1302 *
1303 * The thread is always running when the VRDP server is active.
1304 *
1305 * The thread scans backends and requests the device list every 2 seconds.
1306 *
1307 * When device list is available, the thread calls the Console to process it.
1308 *
1309 */
1310#define VRDP_DEVICE_LIST_PERIOD_MS (2000)
1311
1312#ifdef VBOX_WITH_USB
1313static DECLCALLBACK(int) threadRemoteUSB (RTTHREAD self, void *pvUser)
1314{
1315 ConsoleVRDPServer *pOwner = (ConsoleVRDPServer *)pvUser;
1316
1317 LogFlow(("Console::threadRemoteUSB: start. owner = %p.\n", pOwner));
1318
1319 pOwner->notifyRemoteUSBThreadRunning (self);
1320
1321 while (pOwner->isRemoteUSBThreadRunning ())
1322 {
1323 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1324
1325 while ((pRemoteUSBBackend = pOwner->usbBackendGetNext (pRemoteUSBBackend)) != NULL)
1326 {
1327 pRemoteUSBBackend->PollRemoteDevices ();
1328 }
1329
1330 pOwner->waitRemoteUSBThreadEvent (VRDP_DEVICE_LIST_PERIOD_MS);
1331
1332 LogFlow(("Console::threadRemoteUSB: iteration. owner = %p.\n", pOwner));
1333 }
1334
1335 return VINF_SUCCESS;
1336}
1337
1338void ConsoleVRDPServer::notifyRemoteUSBThreadRunning (RTTHREAD thread)
1339{
1340 mUSBBackends.thread = thread;
1341 mUSBBackends.fThreadRunning = true;
1342 int rc = RTThreadUserSignal (thread);
1343 AssertRC(rc);
1344}
1345
1346bool ConsoleVRDPServer::isRemoteUSBThreadRunning (void)
1347{
1348 return mUSBBackends.fThreadRunning;
1349}
1350
1351void ConsoleVRDPServer::waitRemoteUSBThreadEvent (RTMSINTERVAL cMillies)
1352{
1353 int rc = RTSemEventWait (mUSBBackends.event, cMillies);
1354 Assert (RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1355 NOREF(rc);
1356}
1357
1358void ConsoleVRDPServer::remoteUSBThreadStart (void)
1359{
1360 int rc = RTSemEventCreate (&mUSBBackends.event);
1361
1362 if (RT_FAILURE(rc))
1363 {
1364 AssertFailed ();
1365 mUSBBackends.event = 0;
1366 }
1367
1368 if (RT_SUCCESS(rc))
1369 {
1370 rc = RTThreadCreate (&mUSBBackends.thread, threadRemoteUSB, this, 65536,
1371 RTTHREADTYPE_VRDP_IO, RTTHREADFLAGS_WAITABLE, "remote usb");
1372 }
1373
1374 if (RT_FAILURE(rc))
1375 {
1376 LogRel(("Warning: could not start the remote USB thread, rc = %Rrc!!!\n", rc));
1377 mUSBBackends.thread = NIL_RTTHREAD;
1378 }
1379 else
1380 {
1381 /* Wait until the thread is ready. */
1382 rc = RTThreadUserWait (mUSBBackends.thread, 60000);
1383 AssertRC(rc);
1384 Assert (mUSBBackends.fThreadRunning || RT_FAILURE(rc));
1385 }
1386}
1387
1388void ConsoleVRDPServer::remoteUSBThreadStop (void)
1389{
1390 mUSBBackends.fThreadRunning = false;
1391
1392 if (mUSBBackends.thread != NIL_RTTHREAD)
1393 {
1394 Assert (mUSBBackends.event != 0);
1395
1396 RTSemEventSignal (mUSBBackends.event);
1397
1398 int rc = RTThreadWait (mUSBBackends.thread, 60000, NULL);
1399 AssertRC(rc);
1400
1401 mUSBBackends.thread = NIL_RTTHREAD;
1402 }
1403
1404 if (mUSBBackends.event)
1405 {
1406 RTSemEventDestroy (mUSBBackends.event);
1407 mUSBBackends.event = 0;
1408 }
1409}
1410#endif /* VBOX_WITH_USB */
1411
1412VRDPAuthResult ConsoleVRDPServer::Authenticate (const Guid &uuid, VRDPAuthGuestJudgement guestJudgement,
1413 const char *pszUser, const char *pszPassword, const char *pszDomain,
1414 uint32_t u32ClientId)
1415{
1416 VRDPAUTHUUID rawuuid;
1417
1418 memcpy (rawuuid, ((Guid &)uuid).ptr (), sizeof (rawuuid));
1419
1420 LogFlow(("ConsoleVRDPServer::Authenticate: uuid = %RTuuid, guestJudgement = %d, pszUser = %s, pszPassword = %s, pszDomain = %s, u32ClientId = %d\n",
1421 rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, u32ClientId));
1422
1423 /*
1424 * Called only from VRDP input thread. So thread safety is not required.
1425 */
1426
1427 if (!mAuthLibrary)
1428 {
1429 /* Load the external authentication library. */
1430
1431 ComPtr<IMachine> machine;
1432 mConsole->COMGETTER(Machine)(machine.asOutParam());
1433
1434 ComPtr<IVirtualBox> virtualBox;
1435 machine->COMGETTER(Parent)(virtualBox.asOutParam());
1436
1437 ComPtr<ISystemProperties> systemProperties;
1438 virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
1439
1440 Bstr authLibrary;
1441 systemProperties->COMGETTER(RemoteDisplayAuthLibrary)(authLibrary.asOutParam());
1442
1443 Utf8Str filename = authLibrary;
1444
1445 LogRel(("VRDPAUTH: ConsoleVRDPServer::Authenticate: loading external authentication library '%ls'\n", authLibrary.raw()));
1446
1447 int rc;
1448 if (RTPathHavePath(filename.c_str()))
1449 rc = RTLdrLoad(filename.c_str(), &mAuthLibrary);
1450 else
1451 rc = RTLdrLoadAppPriv(filename.c_str(), &mAuthLibrary);
1452
1453 if (RT_FAILURE(rc))
1454 LogRel(("VRDPAUTH: Failed to load external authentication library. Error code: %Rrc\n", rc));
1455
1456 if (RT_SUCCESS(rc))
1457 {
1458 /* Get the entry point. */
1459 mpfnAuthEntry2 = NULL;
1460 int rc2 = RTLdrGetSymbol(mAuthLibrary, "VRDPAuth2", (void**)&mpfnAuthEntry2);
1461 if (RT_FAILURE(rc2))
1462 {
1463 if (rc2 != VERR_SYMBOL_NOT_FOUND)
1464 {
1465 LogRel(("VRDPAUTH: Could not resolve import '%s'. Error code: %Rrc\n", "VRDPAuth2", rc2));
1466 }
1467 rc = rc2;
1468 }
1469
1470 /* Get the entry point. */
1471 mpfnAuthEntry = NULL;
1472 rc2 = RTLdrGetSymbol(mAuthLibrary, "VRDPAuth", (void**)&mpfnAuthEntry);
1473 if (RT_FAILURE(rc2))
1474 {
1475 if (rc2 != VERR_SYMBOL_NOT_FOUND)
1476 {
1477 LogRel(("VRDPAUTH: Could not resolve import '%s'. Error code: %Rrc\n", "VRDPAuth", rc2));
1478 }
1479 rc = rc2;
1480 }
1481
1482 if (mpfnAuthEntry2 || mpfnAuthEntry)
1483 {
1484 LogRel(("VRDPAUTH: Using entry point '%s'.\n", mpfnAuthEntry2? "VRDPAuth2": "VRDPAuth"));
1485 rc = VINF_SUCCESS;
1486 }
1487 }
1488
1489 if (RT_FAILURE(rc))
1490 {
1491 mConsole->setError(E_FAIL,
1492 mConsole->tr("Could not load the external authentication library '%s' (%Rrc)"),
1493 filename.c_str(),
1494 rc);
1495
1496 mpfnAuthEntry = NULL;
1497 mpfnAuthEntry2 = NULL;
1498
1499 if (mAuthLibrary)
1500 {
1501 RTLdrClose(mAuthLibrary);
1502 mAuthLibrary = 0;
1503 }
1504
1505 return VRDPAuthAccessDenied;
1506 }
1507 }
1508
1509 Assert (mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2));
1510
1511 VRDPAuthResult result = mpfnAuthEntry2?
1512 mpfnAuthEntry2 (&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, true, u32ClientId):
1513 mpfnAuthEntry (&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain);
1514
1515 switch (result)
1516 {
1517 case VRDPAuthAccessDenied:
1518 LogRel(("VRDPAUTH: external authentication module returned 'access denied'\n"));
1519 break;
1520 case VRDPAuthAccessGranted:
1521 LogRel(("VRDPAUTH: external authentication module returned 'access granted'\n"));
1522 break;
1523 case VRDPAuthDelegateToGuest:
1524 LogRel(("VRDPAUTH: external authentication module returned 'delegate request to guest'\n"));
1525 break;
1526 default:
1527 LogRel(("VRDPAUTH: external authentication module returned incorrect return code %d\n", result));
1528 result = VRDPAuthAccessDenied;
1529 }
1530
1531 LogFlow(("ConsoleVRDPServer::Authenticate: result = %d\n", result));
1532
1533 return result;
1534}
1535
1536void ConsoleVRDPServer::AuthDisconnect (const Guid &uuid, uint32_t u32ClientId)
1537{
1538 VRDPAUTHUUID rawuuid;
1539
1540 memcpy (rawuuid, ((Guid &)uuid).ptr (), sizeof (rawuuid));
1541
1542 LogFlow(("ConsoleVRDPServer::AuthDisconnect: uuid = %RTuuid, u32ClientId = %d\n",
1543 rawuuid, u32ClientId));
1544
1545 Assert (mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2));
1546
1547 if (mpfnAuthEntry2)
1548 mpfnAuthEntry2 (&rawuuid, VRDPAuthGuestNotAsked, NULL, NULL, NULL, false, u32ClientId);
1549}
1550
1551int ConsoleVRDPServer::lockConsoleVRDPServer (void)
1552{
1553 int rc = RTCritSectEnter (&mCritSect);
1554 AssertRC(rc);
1555 return rc;
1556}
1557
1558void ConsoleVRDPServer::unlockConsoleVRDPServer (void)
1559{
1560 RTCritSectLeave (&mCritSect);
1561}
1562
1563DECLCALLBACK(int) ConsoleVRDPServer::ClipboardCallback (void *pvCallback,
1564 uint32_t u32ClientId,
1565 uint32_t u32Function,
1566 uint32_t u32Format,
1567 const void *pvData,
1568 uint32_t cbData)
1569{
1570 LogFlowFunc(("pvCallback = %p, u32ClientId = %d, u32Function = %d, u32Format = 0x%08X, pvData = %p, cbData = %d\n",
1571 pvCallback, u32ClientId, u32Function, u32Format, pvData, cbData));
1572
1573 int rc = VINF_SUCCESS;
1574
1575 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvCallback);
1576
1577 NOREF(u32ClientId);
1578
1579 switch (u32Function)
1580 {
1581 case VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE:
1582 {
1583 if (pServer->mpfnClipboardCallback)
1584 {
1585 pServer->mpfnClipboardCallback (VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE,
1586 u32Format,
1587 (void *)pvData,
1588 cbData);
1589 }
1590 } break;
1591
1592 case VRDP_CLIPBOARD_FUNCTION_DATA_READ:
1593 {
1594 if (pServer->mpfnClipboardCallback)
1595 {
1596 pServer->mpfnClipboardCallback (VBOX_CLIPBOARD_EXT_FN_DATA_READ,
1597 u32Format,
1598 (void *)pvData,
1599 cbData);
1600 }
1601 } break;
1602
1603 default:
1604 rc = VERR_NOT_SUPPORTED;
1605 }
1606
1607 return rc;
1608}
1609
1610DECLCALLBACK(int) ConsoleVRDPServer::ClipboardServiceExtension (void *pvExtension,
1611 uint32_t u32Function,
1612 void *pvParms,
1613 uint32_t cbParms)
1614{
1615 LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
1616 pvExtension, u32Function, pvParms, cbParms));
1617
1618 int rc = VINF_SUCCESS;
1619
1620#ifdef VBOX_WITH_VRDP
1621 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvExtension);
1622
1623 VBOXCLIPBOARDEXTPARMS *pParms = (VBOXCLIPBOARDEXTPARMS *)pvParms;
1624
1625 switch (u32Function)
1626 {
1627 case VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK:
1628 {
1629 pServer->mpfnClipboardCallback = pParms->u.pfnCallback;
1630 } break;
1631
1632 case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
1633 {
1634 /* The guest announces clipboard formats. This must be delivered to all clients. */
1635 if (mpEntryPoints && pServer->mhServer)
1636 {
1637 mpEntryPoints->VRDPClipboard (pServer->mhServer,
1638 VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE,
1639 pParms->u32Format,
1640 NULL,
1641 0,
1642 NULL);
1643 }
1644 } break;
1645
1646 case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
1647 {
1648 /* The clipboard service expects that the pvData buffer will be filled
1649 * with clipboard data. The server returns the data from the client that
1650 * announced the requested format most recently.
1651 */
1652 if (mpEntryPoints && pServer->mhServer)
1653 {
1654 mpEntryPoints->VRDPClipboard (pServer->mhServer,
1655 VRDP_CLIPBOARD_FUNCTION_DATA_READ,
1656 pParms->u32Format,
1657 pParms->u.pvData,
1658 pParms->cbData,
1659 &pParms->cbData);
1660 }
1661 } break;
1662
1663 case VBOX_CLIPBOARD_EXT_FN_DATA_WRITE:
1664 {
1665 if (mpEntryPoints && pServer->mhServer)
1666 {
1667 mpEntryPoints->VRDPClipboard (pServer->mhServer,
1668 VRDP_CLIPBOARD_FUNCTION_DATA_WRITE,
1669 pParms->u32Format,
1670 pParms->u.pvData,
1671 pParms->cbData,
1672 NULL);
1673 }
1674 } break;
1675
1676 default:
1677 rc = VERR_NOT_SUPPORTED;
1678 }
1679#endif /* VBOX_WITH_VRDP */
1680
1681 return rc;
1682}
1683
1684void ConsoleVRDPServer::ClipboardCreate (uint32_t u32ClientId)
1685{
1686 int rc = lockConsoleVRDPServer ();
1687
1688 if (RT_SUCCESS(rc))
1689 {
1690 if (mcClipboardRefs == 0)
1691 {
1692 rc = HGCMHostRegisterServiceExtension (&mhClipboard, "VBoxSharedClipboard", ClipboardServiceExtension, this);
1693
1694 if (RT_SUCCESS(rc))
1695 {
1696 mcClipboardRefs++;
1697 }
1698 }
1699
1700 unlockConsoleVRDPServer ();
1701 }
1702}
1703
1704void ConsoleVRDPServer::ClipboardDelete (uint32_t u32ClientId)
1705{
1706 int rc = lockConsoleVRDPServer ();
1707
1708 if (RT_SUCCESS(rc))
1709 {
1710 mcClipboardRefs--;
1711
1712 if (mcClipboardRefs == 0)
1713 {
1714 HGCMHostUnregisterServiceExtension (mhClipboard);
1715 }
1716
1717 unlockConsoleVRDPServer ();
1718 }
1719}
1720
1721/* That is called on INPUT thread of the VRDP server.
1722 * The ConsoleVRDPServer keeps a list of created backend instances.
1723 */
1724void ConsoleVRDPServer::USBBackendCreate (uint32_t u32ClientId, void **ppvIntercept)
1725{
1726#ifdef VBOX_WITH_USB
1727 LogFlow(("ConsoleVRDPServer::USBBackendCreate: u32ClientId = %d\n", u32ClientId));
1728
1729 /* Create a new instance of the USB backend for the new client. */
1730 RemoteUSBBackend *pRemoteUSBBackend = new RemoteUSBBackend (mConsole, this, u32ClientId);
1731
1732 if (pRemoteUSBBackend)
1733 {
1734 pRemoteUSBBackend->AddRef (); /* 'Release' called in USBBackendDelete. */
1735
1736 /* Append the new instance in the list. */
1737 int rc = lockConsoleVRDPServer ();
1738
1739 if (RT_SUCCESS(rc))
1740 {
1741 pRemoteUSBBackend->pNext = mUSBBackends.pHead;
1742 if (mUSBBackends.pHead)
1743 {
1744 mUSBBackends.pHead->pPrev = pRemoteUSBBackend;
1745 }
1746 else
1747 {
1748 mUSBBackends.pTail = pRemoteUSBBackend;
1749 }
1750
1751 mUSBBackends.pHead = pRemoteUSBBackend;
1752
1753 unlockConsoleVRDPServer ();
1754
1755 if (ppvIntercept)
1756 {
1757 *ppvIntercept = pRemoteUSBBackend;
1758 }
1759 }
1760
1761 if (RT_FAILURE(rc))
1762 {
1763 pRemoteUSBBackend->Release ();
1764 }
1765 }
1766#endif /* VBOX_WITH_USB */
1767}
1768
1769void ConsoleVRDPServer::USBBackendDelete (uint32_t u32ClientId)
1770{
1771#ifdef VBOX_WITH_USB
1772 LogFlow(("ConsoleVRDPServer::USBBackendDelete: u32ClientId = %d\n", u32ClientId));
1773
1774 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1775
1776 /* Find the instance. */
1777 int rc = lockConsoleVRDPServer ();
1778
1779 if (RT_SUCCESS(rc))
1780 {
1781 pRemoteUSBBackend = usbBackendFind (u32ClientId);
1782
1783 if (pRemoteUSBBackend)
1784 {
1785 /* Notify that it will be deleted. */
1786 pRemoteUSBBackend->NotifyDelete ();
1787 }
1788
1789 unlockConsoleVRDPServer ();
1790 }
1791
1792 if (pRemoteUSBBackend)
1793 {
1794 /* Here the instance has been excluded from the list and can be dereferenced. */
1795 pRemoteUSBBackend->Release ();
1796 }
1797#endif
1798}
1799
1800void *ConsoleVRDPServer::USBBackendRequestPointer (uint32_t u32ClientId, const Guid *pGuid)
1801{
1802#ifdef VBOX_WITH_USB
1803 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1804
1805 /* Find the instance. */
1806 int rc = lockConsoleVRDPServer ();
1807
1808 if (RT_SUCCESS(rc))
1809 {
1810 pRemoteUSBBackend = usbBackendFind (u32ClientId);
1811
1812 if (pRemoteUSBBackend)
1813 {
1814 /* Inform the backend instance that it is referenced by the Guid. */
1815 bool fAdded = pRemoteUSBBackend->addUUID (pGuid);
1816
1817 if (fAdded)
1818 {
1819 /* Reference the instance because its pointer is being taken. */
1820 pRemoteUSBBackend->AddRef (); /* 'Release' is called in USBBackendReleasePointer. */
1821 }
1822 else
1823 {
1824 pRemoteUSBBackend = NULL;
1825 }
1826 }
1827
1828 unlockConsoleVRDPServer ();
1829 }
1830
1831 if (pRemoteUSBBackend)
1832 {
1833 return pRemoteUSBBackend->GetBackendCallbackPointer ();
1834 }
1835
1836#endif
1837 return NULL;
1838}
1839
1840void ConsoleVRDPServer::USBBackendReleasePointer (const Guid *pGuid)
1841{
1842#ifdef VBOX_WITH_USB
1843 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1844
1845 /* Find the instance. */
1846 int rc = lockConsoleVRDPServer ();
1847
1848 if (RT_SUCCESS(rc))
1849 {
1850 pRemoteUSBBackend = usbBackendFindByUUID (pGuid);
1851
1852 if (pRemoteUSBBackend)
1853 {
1854 pRemoteUSBBackend->removeUUID (pGuid);
1855 }
1856
1857 unlockConsoleVRDPServer ();
1858
1859 if (pRemoteUSBBackend)
1860 {
1861 pRemoteUSBBackend->Release ();
1862 }
1863 }
1864#endif
1865}
1866
1867RemoteUSBBackend *ConsoleVRDPServer::usbBackendGetNext (RemoteUSBBackend *pRemoteUSBBackend)
1868{
1869 LogFlow(("ConsoleVRDPServer::usbBackendGetNext: pBackend = %p\n", pRemoteUSBBackend));
1870
1871 RemoteUSBBackend *pNextRemoteUSBBackend = NULL;
1872#ifdef VBOX_WITH_USB
1873
1874 int rc = lockConsoleVRDPServer ();
1875
1876 if (RT_SUCCESS(rc))
1877 {
1878 if (pRemoteUSBBackend == NULL)
1879 {
1880 /* The first backend in the list is requested. */
1881 pNextRemoteUSBBackend = mUSBBackends.pHead;
1882 }
1883 else
1884 {
1885 /* Get pointer to the next backend. */
1886 pNextRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1887 }
1888
1889 if (pNextRemoteUSBBackend)
1890 {
1891 pNextRemoteUSBBackend->AddRef ();
1892 }
1893
1894 unlockConsoleVRDPServer ();
1895
1896 if (pRemoteUSBBackend)
1897 {
1898 pRemoteUSBBackend->Release ();
1899 }
1900 }
1901#endif
1902
1903 return pNextRemoteUSBBackend;
1904}
1905
1906#ifdef VBOX_WITH_USB
1907/* Internal method. Called under the ConsoleVRDPServerLock. */
1908RemoteUSBBackend *ConsoleVRDPServer::usbBackendFind (uint32_t u32ClientId)
1909{
1910 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
1911
1912 while (pRemoteUSBBackend)
1913 {
1914 if (pRemoteUSBBackend->ClientId () == u32ClientId)
1915 {
1916 break;
1917 }
1918
1919 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1920 }
1921
1922 return pRemoteUSBBackend;
1923}
1924
1925/* Internal method. Called under the ConsoleVRDPServerLock. */
1926RemoteUSBBackend *ConsoleVRDPServer::usbBackendFindByUUID (const Guid *pGuid)
1927{
1928 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
1929
1930 while (pRemoteUSBBackend)
1931 {
1932 if (pRemoteUSBBackend->findUUID (pGuid))
1933 {
1934 break;
1935 }
1936
1937 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1938 }
1939
1940 return pRemoteUSBBackend;
1941}
1942#endif
1943
1944/* Internal method. Called by the backend destructor. */
1945void ConsoleVRDPServer::usbBackendRemoveFromList (RemoteUSBBackend *pRemoteUSBBackend)
1946{
1947#ifdef VBOX_WITH_USB
1948 int rc = lockConsoleVRDPServer ();
1949 AssertRC(rc);
1950
1951 /* Exclude the found instance from the list. */
1952 if (pRemoteUSBBackend->pNext)
1953 {
1954 pRemoteUSBBackend->pNext->pPrev = pRemoteUSBBackend->pPrev;
1955 }
1956 else
1957 {
1958 mUSBBackends.pTail = (RemoteUSBBackend *)pRemoteUSBBackend->pPrev;
1959 }
1960
1961 if (pRemoteUSBBackend->pPrev)
1962 {
1963 pRemoteUSBBackend->pPrev->pNext = pRemoteUSBBackend->pNext;
1964 }
1965 else
1966 {
1967 mUSBBackends.pHead = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1968 }
1969
1970 pRemoteUSBBackend->pNext = pRemoteUSBBackend->pPrev = NULL;
1971
1972 unlockConsoleVRDPServer ();
1973#endif
1974}
1975
1976
1977void ConsoleVRDPServer::SendUpdate (unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate) const
1978{
1979#ifdef VBOX_WITH_VRDP
1980 if (mpEntryPoints && mhServer)
1981 {
1982 mpEntryPoints->VRDPUpdate (mhServer, uScreenId, pvUpdate, cbUpdate);
1983 }
1984#endif
1985}
1986
1987void ConsoleVRDPServer::SendResize (void) const
1988{
1989#ifdef VBOX_WITH_VRDP
1990 if (mpEntryPoints && mhServer)
1991 {
1992 mpEntryPoints->VRDPResize (mhServer);
1993 }
1994#endif
1995}
1996
1997void ConsoleVRDPServer::SendUpdateBitmap (unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h) const
1998{
1999#ifdef VBOX_WITH_VRDP
2000 VRDPORDERHDR update;
2001 update.x = x;
2002 update.y = y;
2003 update.w = w;
2004 update.h = h;
2005 if (mpEntryPoints && mhServer)
2006 {
2007 mpEntryPoints->VRDPUpdate (mhServer, uScreenId, &update, sizeof (update));
2008 }
2009#endif
2010}
2011
2012void ConsoleVRDPServer::SendAudioSamples (void *pvSamples, uint32_t cSamples, VRDPAUDIOFORMAT format) const
2013{
2014#ifdef VBOX_WITH_VRDP
2015 if (mpEntryPoints && mhServer)
2016 {
2017 mpEntryPoints->VRDPAudioSamples (mhServer, pvSamples, cSamples, format);
2018 }
2019#endif
2020}
2021
2022void ConsoleVRDPServer::SendAudioVolume (uint16_t left, uint16_t right) const
2023{
2024#ifdef VBOX_WITH_VRDP
2025 if (mpEntryPoints && mhServer)
2026 {
2027 mpEntryPoints->VRDPAudioVolume (mhServer, left, right);
2028 }
2029#endif
2030}
2031
2032void ConsoleVRDPServer::SendUSBRequest (uint32_t u32ClientId, void *pvParms, uint32_t cbParms) const
2033{
2034#ifdef VBOX_WITH_VRDP
2035 if (mpEntryPoints && mhServer)
2036 {
2037 mpEntryPoints->VRDPUSBRequest (mhServer, u32ClientId, pvParms, cbParms);
2038 }
2039#endif
2040}
2041
2042void ConsoleVRDPServer::QueryInfo (uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const
2043{
2044#ifdef VBOX_WITH_VRDP
2045 if (index == VRDP_QI_PORT)
2046 {
2047 uint32_t cbOut = sizeof (int32_t);
2048
2049 if (cbBuffer >= cbOut)
2050 {
2051 *pcbOut = cbOut;
2052 *(int32_t *)pvBuffer = (int32_t)mVRDPBindPort;
2053 }
2054 }
2055 else if (mpEntryPoints && mhServer)
2056 {
2057 mpEntryPoints->VRDPQueryInfo (mhServer, index, pvBuffer, cbBuffer, pcbOut);
2058 }
2059#endif
2060}
2061
2062#ifdef VBOX_WITH_VRDP
2063/* note: static function now! */
2064bool ConsoleVRDPServer::loadVRDPLibrary (void)
2065{
2066 int rc = VINF_SUCCESS;
2067
2068 if (!mVRDPLibrary)
2069 {
2070 rc = SUPR3HardenedLdrLoadAppPriv ("VBoxVRDP", &mVRDPLibrary);
2071
2072 if (RT_SUCCESS(rc))
2073 {
2074 LogFlow(("VRDPServer::loadLibrary(): successfully loaded VRDP library.\n"));
2075
2076 struct SymbolEntry
2077 {
2078 const char *name;
2079 void **ppfn;
2080 };
2081
2082 #define DEFSYMENTRY(a) { #a, (void**)&mpfn##a }
2083
2084 static const struct SymbolEntry symbols[] =
2085 {
2086 DEFSYMENTRY(VRDPCreateServer)
2087 };
2088
2089 #undef DEFSYMENTRY
2090
2091 for (unsigned i = 0; i < RT_ELEMENTS(symbols); i++)
2092 {
2093 rc = RTLdrGetSymbol(mVRDPLibrary, symbols[i].name, symbols[i].ppfn);
2094
2095 AssertMsgRC(rc, ("Error resolving VRDP symbol %s\n", symbols[i].name));
2096
2097 if (RT_FAILURE(rc))
2098 {
2099 break;
2100 }
2101 }
2102 }
2103 else
2104 {
2105 LogRel(("VRDPServer::loadLibrary(): failed to load VRDP library! VRDP not available: rc = %Rrc\n", rc));
2106 mVRDPLibrary = NULL;
2107 }
2108 }
2109
2110 // just to be safe
2111 if (RT_FAILURE(rc))
2112 {
2113 if (mVRDPLibrary)
2114 {
2115 RTLdrClose (mVRDPLibrary);
2116 mVRDPLibrary = NULL;
2117 }
2118 }
2119
2120 return (mVRDPLibrary != NULL);
2121}
2122#endif /* VBOX_WITH_VRDP */
2123
2124/*
2125 * IRemoteDisplayInfo implementation.
2126 */
2127// constructor / destructor
2128/////////////////////////////////////////////////////////////////////////////
2129
2130RemoteDisplayInfo::RemoteDisplayInfo()
2131 : mParent(NULL)
2132{
2133}
2134
2135RemoteDisplayInfo::~RemoteDisplayInfo()
2136{
2137}
2138
2139
2140HRESULT RemoteDisplayInfo::FinalConstruct()
2141{
2142 return S_OK;
2143}
2144
2145void RemoteDisplayInfo::FinalRelease()
2146{
2147 uninit ();
2148}
2149
2150// public methods only for internal purposes
2151/////////////////////////////////////////////////////////////////////////////
2152
2153/**
2154 * Initializes the guest object.
2155 */
2156HRESULT RemoteDisplayInfo::init (Console *aParent)
2157{
2158 LogFlowThisFunc(("aParent=%p\n", aParent));
2159
2160 ComAssertRet(aParent, E_INVALIDARG);
2161
2162 /* Enclose the state transition NotReady->InInit->Ready */
2163 AutoInitSpan autoInitSpan(this);
2164 AssertReturn(autoInitSpan.isOk(), E_FAIL);
2165
2166 unconst(mParent) = aParent;
2167
2168 /* Confirm a successful initialization */
2169 autoInitSpan.setSucceeded();
2170
2171 return S_OK;
2172}
2173
2174/**
2175 * Uninitializes the instance and sets the ready flag to FALSE.
2176 * Called either from FinalRelease() or by the parent when it gets destroyed.
2177 */
2178void RemoteDisplayInfo::uninit()
2179{
2180 LogFlowThisFunc(("\n"));
2181
2182 /* Enclose the state transition Ready->InUninit->NotReady */
2183 AutoUninitSpan autoUninitSpan(this);
2184 if (autoUninitSpan.uninitDone())
2185 return;
2186
2187 unconst(mParent) = NULL;
2188}
2189
2190// IRemoteDisplayInfo properties
2191/////////////////////////////////////////////////////////////////////////////
2192
2193#define IMPL_GETTER_BOOL(_aType, _aName, _aIndex) \
2194 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
2195 { \
2196 if (!a##_aName) \
2197 return E_POINTER; \
2198 \
2199 AutoCaller autoCaller(this); \
2200 if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2201 \
2202 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
2203 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2204 \
2205 uint32_t value; \
2206 uint32_t cbOut = 0; \
2207 \
2208 mParent->consoleVRDPServer ()->QueryInfo \
2209 (_aIndex, &value, sizeof (value), &cbOut); \
2210 \
2211 *a##_aName = cbOut? !!value: FALSE; \
2212 \
2213 return S_OK; \
2214 } \
2215 extern void IMPL_GETTER_BOOL_DUMMY(void)
2216
2217#define IMPL_GETTER_SCALAR(_aType, _aName, _aIndex, _aValueMask) \
2218 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
2219 { \
2220 if (!a##_aName) \
2221 return E_POINTER; \
2222 \
2223 AutoCaller autoCaller(this); \
2224 if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2225 \
2226 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
2227 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2228 \
2229 _aType value; \
2230 uint32_t cbOut = 0; \
2231 \
2232 mParent->consoleVRDPServer ()->QueryInfo \
2233 (_aIndex, &value, sizeof (value), &cbOut); \
2234 \
2235 if (_aValueMask) value &= (_aValueMask); \
2236 *a##_aName = cbOut? value: 0; \
2237 \
2238 return S_OK; \
2239 } \
2240 extern void IMPL_GETTER_SCALAR_DUMMY(void)
2241
2242#define IMPL_GETTER_BSTR(_aType, _aName, _aIndex) \
2243 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
2244 { \
2245 if (!a##_aName) \
2246 return E_POINTER; \
2247 \
2248 AutoCaller autoCaller(this); \
2249 if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2250 \
2251 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
2252 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2253 \
2254 uint32_t cbOut = 0; \
2255 \
2256 mParent->consoleVRDPServer ()->QueryInfo \
2257 (_aIndex, NULL, 0, &cbOut); \
2258 \
2259 if (cbOut == 0) \
2260 { \
2261 Bstr str(""); \
2262 str.cloneTo(a##_aName); \
2263 return S_OK; \
2264 } \
2265 \
2266 char *pchBuffer = (char *)RTMemTmpAlloc (cbOut); \
2267 \
2268 if (!pchBuffer) \
2269 { \
2270 Log(("RemoteDisplayInfo::" \
2271 #_aName \
2272 ": Failed to allocate memory %d bytes\n", cbOut)); \
2273 return E_OUTOFMEMORY; \
2274 } \
2275 \
2276 mParent->consoleVRDPServer ()->QueryInfo \
2277 (_aIndex, pchBuffer, cbOut, &cbOut); \
2278 \
2279 Bstr str(pchBuffer); \
2280 \
2281 str.cloneTo(a##_aName); \
2282 \
2283 RTMemTmpFree (pchBuffer); \
2284 \
2285 return S_OK; \
2286 } \
2287 extern void IMPL_GETTER_BSTR_DUMMY(void)
2288
2289IMPL_GETTER_BOOL (BOOL, Active, VRDP_QI_ACTIVE);
2290IMPL_GETTER_SCALAR (LONG, Port, VRDP_QI_PORT, 0);
2291IMPL_GETTER_SCALAR (ULONG, NumberOfClients, VRDP_QI_NUMBER_OF_CLIENTS, 0);
2292IMPL_GETTER_SCALAR (LONG64, BeginTime, VRDP_QI_BEGIN_TIME, 0);
2293IMPL_GETTER_SCALAR (LONG64, EndTime, VRDP_QI_END_TIME, 0);
2294IMPL_GETTER_SCALAR (LONG64, BytesSent, VRDP_QI_BYTES_SENT, INT64_MAX);
2295IMPL_GETTER_SCALAR (LONG64, BytesSentTotal, VRDP_QI_BYTES_SENT_TOTAL, INT64_MAX);
2296IMPL_GETTER_SCALAR (LONG64, BytesReceived, VRDP_QI_BYTES_RECEIVED, INT64_MAX);
2297IMPL_GETTER_SCALAR (LONG64, BytesReceivedTotal, VRDP_QI_BYTES_RECEIVED_TOTAL, INT64_MAX);
2298IMPL_GETTER_BSTR (BSTR, User, VRDP_QI_USER);
2299IMPL_GETTER_BSTR (BSTR, Domain, VRDP_QI_DOMAIN);
2300IMPL_GETTER_BSTR (BSTR, ClientName, VRDP_QI_CLIENT_NAME);
2301IMPL_GETTER_BSTR (BSTR, ClientIP, VRDP_QI_CLIENT_IP);
2302IMPL_GETTER_SCALAR (ULONG, ClientVersion, VRDP_QI_CLIENT_VERSION, 0);
2303IMPL_GETTER_SCALAR (ULONG, EncryptionStyle, VRDP_QI_ENCRYPTION_STYLE, 0);
2304
2305#undef IMPL_GETTER_BSTR
2306#undef IMPL_GETTER_SCALAR
2307#undef IMPL_GETTER_BOOL
2308/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette