VirtualBox

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

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

scm cleanup

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 72.5 KB
Line 
1/* $Id: ConsoleVRDPServer.cpp 32431 2010-09-11 18:02:17Z 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_QP_FEATURE:
758 {
759 if (cbBuffer < sizeof(VRDPFEATURE))
760 {
761 rc = VERR_INVALID_PARAMETER;
762 break;
763 }
764
765 size_t cbInfo = cbBuffer - RT_OFFSETOF(VRDPFEATURE, achInfo);
766
767 VRDPFEATURE *pFeature = (VRDPFEATURE *)pvBuffer;
768
769 size_t cchInfo = 0;
770 rc = RTStrNLenEx(pFeature->achInfo, cbInfo, &cchInfo);
771
772 if (RT_FAILURE(rc))
773 {
774 rc = VERR_INVALID_PARAMETER;
775 break;
776 }
777
778 /* features are mapped to "VRDP/Feature/NAME" extra data. */
779 com::Utf8Str extraData("VRDP/Feature/");
780 extraData += pFeature->achInfo;
781
782 com::Bstr bstrValue;
783
784 /* @todo these features should be per client. */
785 NOREF(pFeature->u32ClientId);
786
787 if ( RTStrICmp(pFeature->achInfo, "Client/DisableDisplay") == 0
788 || RTStrICmp(pFeature->achInfo, "Client/DisableInput") == 0
789 || RTStrICmp(pFeature->achInfo, "Client/DisableAudio") == 0
790 || RTStrICmp(pFeature->achInfo, "Client/DisableUSB") == 0
791 || RTStrICmp(pFeature->achInfo, "Client/DisableClipboard") == 0
792 )
793 {
794 HRESULT hrc = server->mConsole->machine ()->GetExtraData(com::Bstr(extraData), bstrValue.asOutParam());
795 if (hrc == S_OK && !bstrValue.isEmpty())
796 {
797 rc = VINF_SUCCESS;
798 }
799 }
800 else
801 {
802 rc = VERR_NOT_SUPPORTED;
803 }
804
805 /* Copy the value string to the callers buffer. */
806 if (rc == VINF_SUCCESS)
807 {
808 com::Utf8Str value = bstrValue;
809
810 size_t cb = value.length() + 1;
811
812 if ((size_t)cbInfo >= cb)
813 {
814 memcpy(pFeature->achInfo, value.c_str(), cb);
815 }
816 else
817 {
818 rc = VINF_BUFFER_OVERFLOW;
819 }
820
821 *pcbOut = (uint32_t)cb;
822 }
823 } break;
824
825 case VRDP_SP_NETWORK_BIND_PORT:
826 {
827 if (cbBuffer != sizeof(uint32_t))
828 {
829 rc = VERR_INVALID_PARAMETER;
830 break;
831 }
832
833 ULONG port = *(uint32_t *)pvBuffer;
834
835 server->mVRDPBindPort = port;
836
837 rc = VINF_SUCCESS;
838
839 if (pcbOut)
840 {
841 *pcbOut = sizeof(uint32_t);
842 }
843
844 server->mConsole->onRemoteDisplayInfoChange();
845 } break;
846
847 default:
848 break;
849 }
850
851 return rc;
852}
853
854DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClientLogon(void *pvCallback, uint32_t u32ClientId, const char *pszUser, const char *pszPassword, const char *pszDomain)
855{
856 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
857
858 return server->mConsole->VRDPClientLogon (u32ClientId, pszUser, pszPassword, pszDomain);
859}
860
861DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientConnect (void *pvCallback, uint32_t u32ClientId)
862{
863 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
864
865 server->mConsole->VRDPClientConnect (u32ClientId);
866}
867
868DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientDisconnect (void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercepted)
869{
870 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
871
872 server->mConsole->VRDPClientDisconnect (u32ClientId, fu32Intercepted);
873}
874
875DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackIntercept (void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercept, void **ppvIntercept)
876{
877 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
878
879 LogFlowFunc(("%x\n", fu32Intercept));
880
881 int rc = VERR_NOT_SUPPORTED;
882
883 switch (fu32Intercept)
884 {
885 case VRDP_CLIENT_INTERCEPT_AUDIO:
886 {
887 server->mConsole->VRDPInterceptAudio (u32ClientId);
888 if (ppvIntercept)
889 {
890 *ppvIntercept = server;
891 }
892 rc = VINF_SUCCESS;
893 } break;
894
895 case VRDP_CLIENT_INTERCEPT_USB:
896 {
897 server->mConsole->VRDPInterceptUSB (u32ClientId, ppvIntercept);
898 rc = VINF_SUCCESS;
899 } break;
900
901 case VRDP_CLIENT_INTERCEPT_CLIPBOARD:
902 {
903 server->mConsole->VRDPInterceptClipboard (u32ClientId);
904 if (ppvIntercept)
905 {
906 *ppvIntercept = server;
907 }
908 rc = VINF_SUCCESS;
909 } break;
910
911 default:
912 break;
913 }
914
915 return rc;
916}
917
918DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackUSB (void *pvCallback, void *pvIntercept, uint32_t u32ClientId, uint8_t u8Code, const void *pvRet, uint32_t cbRet)
919{
920#ifdef VBOX_WITH_USB
921 return USBClientResponseCallback (pvIntercept, u32ClientId, u8Code, pvRet, cbRet);
922#else
923 return VERR_NOT_SUPPORTED;
924#endif
925}
926
927DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClipboard (void *pvCallback, void *pvIntercept, uint32_t u32ClientId, uint32_t u32Function, uint32_t u32Format, const void *pvData, uint32_t cbData)
928{
929 return ClipboardCallback (pvIntercept, u32ClientId, u32Function, u32Format, pvData, cbData);
930}
931
932DECLCALLBACK(bool) ConsoleVRDPServer::VRDPCallbackFramebufferQuery (void *pvCallback, unsigned uScreenId, VRDPFRAMEBUFFERINFO *pInfo)
933{
934 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
935
936 bool fAvailable = false;
937
938 IFramebuffer *pfb = NULL;
939 LONG xOrigin = 0;
940 LONG yOrigin = 0;
941
942 server->mConsole->getDisplay ()->GetFramebuffer (uScreenId, &pfb, &xOrigin, &yOrigin);
943
944 if (pfb)
945 {
946 pfb->Lock ();
947
948 /* Query framebuffer parameters. */
949 ULONG lineSize = 0;
950 pfb->COMGETTER(BytesPerLine) (&lineSize);
951
952 ULONG bitsPerPixel = 0;
953 pfb->COMGETTER(BitsPerPixel) (&bitsPerPixel);
954
955 BYTE *address = NULL;
956 pfb->COMGETTER(Address) (&address);
957
958 ULONG height = 0;
959 pfb->COMGETTER(Height) (&height);
960
961 ULONG width = 0;
962 pfb->COMGETTER(Width) (&width);
963
964 /* Now fill the information as requested by the caller. */
965 pInfo->pu8Bits = address;
966 pInfo->xOrigin = xOrigin;
967 pInfo->yOrigin = yOrigin;
968 pInfo->cWidth = width;
969 pInfo->cHeight = height;
970 pInfo->cBitsPerPixel = bitsPerPixel;
971 pInfo->cbLine = lineSize;
972
973 pfb->Unlock ();
974
975 fAvailable = true;
976 }
977
978 if (server->maFramebuffers[uScreenId])
979 {
980 server->maFramebuffers[uScreenId]->Release ();
981 }
982 server->maFramebuffers[uScreenId] = pfb;
983
984 return fAvailable;
985}
986
987DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferLock (void *pvCallback, unsigned uScreenId)
988{
989 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
990
991 if (server->maFramebuffers[uScreenId])
992 {
993 server->maFramebuffers[uScreenId]->Lock ();
994 }
995}
996
997DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferUnlock (void *pvCallback, unsigned uScreenId)
998{
999 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1000
1001 if (server->maFramebuffers[uScreenId])
1002 {
1003 server->maFramebuffers[uScreenId]->Unlock ();
1004 }
1005}
1006
1007static void fixKbdLockStatus (VRDPInputSynch *pInputSynch, IKeyboard *pKeyboard)
1008{
1009 if ( pInputSynch->cGuestNumLockAdaptions
1010 && (pInputSynch->fGuestNumLock != pInputSynch->fClientNumLock))
1011 {
1012 pInputSynch->cGuestNumLockAdaptions--;
1013 pKeyboard->PutScancode(0x45);
1014 pKeyboard->PutScancode(0x45 | 0x80);
1015 }
1016 if ( pInputSynch->cGuestCapsLockAdaptions
1017 && (pInputSynch->fGuestCapsLock != pInputSynch->fClientCapsLock))
1018 {
1019 pInputSynch->cGuestCapsLockAdaptions--;
1020 pKeyboard->PutScancode(0x3a);
1021 pKeyboard->PutScancode(0x3a | 0x80);
1022 }
1023}
1024
1025DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackInput (void *pvCallback, int type, const void *pvInput, unsigned cbInput)
1026{
1027 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1028 Console *pConsole = server->mConsole;
1029
1030 switch (type)
1031 {
1032 case VRDP_INPUT_SCANCODE:
1033 {
1034 if (cbInput == sizeof (VRDPINPUTSCANCODE))
1035 {
1036 IKeyboard *pKeyboard = pConsole->getKeyboard ();
1037
1038 const VRDPINPUTSCANCODE *pInputScancode = (VRDPINPUTSCANCODE *)pvInput;
1039
1040 /* Track lock keys. */
1041 if (pInputScancode->uScancode == 0x45)
1042 {
1043 server->m_InputSynch.fClientNumLock = !server->m_InputSynch.fClientNumLock;
1044 }
1045 else if (pInputScancode->uScancode == 0x3a)
1046 {
1047 server->m_InputSynch.fClientCapsLock = !server->m_InputSynch.fClientCapsLock;
1048 }
1049 else if (pInputScancode->uScancode == 0x46)
1050 {
1051 server->m_InputSynch.fClientScrollLock = !server->m_InputSynch.fClientScrollLock;
1052 }
1053 else if ((pInputScancode->uScancode & 0x80) == 0)
1054 {
1055 /* Key pressed. */
1056 fixKbdLockStatus (&server->m_InputSynch, pKeyboard);
1057 }
1058
1059 pKeyboard->PutScancode((LONG)pInputScancode->uScancode);
1060 }
1061 } break;
1062
1063 case VRDP_INPUT_POINT:
1064 {
1065 if (cbInput == sizeof (VRDPINPUTPOINT))
1066 {
1067 const VRDPINPUTPOINT *pInputPoint = (VRDPINPUTPOINT *)pvInput;
1068
1069 int mouseButtons = 0;
1070 int iWheel = 0;
1071
1072 if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON1)
1073 {
1074 mouseButtons |= MouseButtonState_LeftButton;
1075 }
1076 if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON2)
1077 {
1078 mouseButtons |= MouseButtonState_RightButton;
1079 }
1080 if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON3)
1081 {
1082 mouseButtons |= MouseButtonState_MiddleButton;
1083 }
1084 if (pInputPoint->uButtons & VRDP_INPUT_POINT_WHEEL_UP)
1085 {
1086 mouseButtons |= MouseButtonState_WheelUp;
1087 iWheel = -1;
1088 }
1089 if (pInputPoint->uButtons & VRDP_INPUT_POINT_WHEEL_DOWN)
1090 {
1091 mouseButtons |= MouseButtonState_WheelDown;
1092 iWheel = 1;
1093 }
1094
1095 if (server->m_fGuestWantsAbsolute)
1096 {
1097 pConsole->getMouse()->PutMouseEventAbsolute (pInputPoint->x + 1, pInputPoint->y + 1, iWheel, 0 /* Horizontal wheel */, mouseButtons);
1098 } else
1099 {
1100 pConsole->getMouse()->PutMouseEvent (pInputPoint->x - server->m_mousex,
1101 pInputPoint->y - server->m_mousey,
1102 iWheel, 0 /* Horizontal wheel */, mouseButtons);
1103 server->m_mousex = pInputPoint->x;
1104 server->m_mousey = pInputPoint->y;
1105 }
1106 }
1107 } break;
1108
1109 case VRDP_INPUT_CAD:
1110 {
1111 pConsole->getKeyboard ()->PutCAD();
1112 } break;
1113
1114 case VRDP_INPUT_RESET:
1115 {
1116 pConsole->Reset();
1117 } break;
1118
1119 case VRDP_INPUT_SYNCH:
1120 {
1121 if (cbInput == sizeof (VRDPINPUTSYNCH))
1122 {
1123 IKeyboard *pKeyboard = pConsole->getKeyboard ();
1124
1125 const VRDPINPUTSYNCH *pInputSynch = (VRDPINPUTSYNCH *)pvInput;
1126
1127 server->m_InputSynch.fClientNumLock = (pInputSynch->uLockStatus & VRDP_INPUT_SYNCH_NUMLOCK) != 0;
1128 server->m_InputSynch.fClientCapsLock = (pInputSynch->uLockStatus & VRDP_INPUT_SYNCH_CAPITAL) != 0;
1129 server->m_InputSynch.fClientScrollLock = (pInputSynch->uLockStatus & VRDP_INPUT_SYNCH_SCROLL) != 0;
1130
1131 /* The client initiated synchronization. Always make the guest to reflect the client state.
1132 * Than means, when the guest changes the state itself, it is forced to return to the client
1133 * state.
1134 */
1135 if (server->m_InputSynch.fClientNumLock != server->m_InputSynch.fGuestNumLock)
1136 {
1137 server->m_InputSynch.cGuestNumLockAdaptions = 2;
1138 }
1139
1140 if (server->m_InputSynch.fClientCapsLock != server->m_InputSynch.fGuestCapsLock)
1141 {
1142 server->m_InputSynch.cGuestCapsLockAdaptions = 2;
1143 }
1144
1145 fixKbdLockStatus (&server->m_InputSynch, pKeyboard);
1146 }
1147 } break;
1148
1149 default:
1150 break;
1151 }
1152}
1153
1154DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackVideoModeHint (void *pvCallback, unsigned cWidth, unsigned cHeight, unsigned cBitsPerPixel, unsigned uScreenId)
1155{
1156 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1157
1158 server->mConsole->getDisplay()->SetVideoModeHint(cWidth, cHeight, cBitsPerPixel, uScreenId);
1159}
1160#endif /* VBOX_WITH_VRDP */
1161
1162ConsoleVRDPServer::ConsoleVRDPServer (Console *console)
1163{
1164 mConsole = console;
1165
1166 int rc = RTCritSectInit(&mCritSect);
1167 AssertRC(rc);
1168
1169 mcClipboardRefs = 0;
1170 mpfnClipboardCallback = NULL;
1171
1172#ifdef VBOX_WITH_USB
1173 mUSBBackends.pHead = NULL;
1174 mUSBBackends.pTail = NULL;
1175
1176 mUSBBackends.thread = NIL_RTTHREAD;
1177 mUSBBackends.fThreadRunning = false;
1178 mUSBBackends.event = 0;
1179#endif
1180
1181#ifdef VBOX_WITH_VRDP
1182 mhServer = 0;
1183
1184 m_fGuestWantsAbsolute = false;
1185 m_mousex = 0;
1186 m_mousey = 0;
1187
1188 m_InputSynch.cGuestNumLockAdaptions = 2;
1189 m_InputSynch.cGuestCapsLockAdaptions = 2;
1190
1191 m_InputSynch.fGuestNumLock = false;
1192 m_InputSynch.fGuestCapsLock = false;
1193 m_InputSynch.fGuestScrollLock = false;
1194
1195 m_InputSynch.fClientNumLock = false;
1196 m_InputSynch.fClientCapsLock = false;
1197 m_InputSynch.fClientScrollLock = false;
1198
1199 memset (maFramebuffers, 0, sizeof (maFramebuffers));
1200
1201 {
1202 ComPtr<IEventSource> es;
1203 console->COMGETTER(EventSource)(es.asOutParam());
1204 mConsoleListener = new VRDPConsoleListener(this);
1205 mConsoleListener->AddRef();
1206 com::SafeArray <VBoxEventType_T> eventTypes;
1207 eventTypes.push_back(VBoxEventType_OnMousePointerShapeChanged);
1208 eventTypes.push_back(VBoxEventType_OnMouseCapabilityChanged);
1209 eventTypes.push_back(VBoxEventType_OnKeyboardLedsChanged);
1210 es->RegisterListener(mConsoleListener, ComSafeArrayAsInParam(eventTypes), true);
1211 }
1212
1213 mVRDPBindPort = -1;
1214#endif /* VBOX_WITH_VRDP */
1215
1216 mAuthLibrary = 0;
1217}
1218
1219ConsoleVRDPServer::~ConsoleVRDPServer ()
1220{
1221 Stop ();
1222
1223#ifdef VBOX_WITH_VRDP
1224 if (mConsoleListener)
1225 {
1226 ComPtr<IEventSource> es;
1227 mConsole->COMGETTER(EventSource)(es.asOutParam());
1228 es->UnregisterListener(mConsoleListener);
1229 mConsoleListener->Release();
1230 mConsoleListener = NULL;
1231 }
1232
1233 unsigned i;
1234 for (i = 0; i < RT_ELEMENTS(maFramebuffers); i++)
1235 {
1236 if (maFramebuffers[i])
1237 {
1238 maFramebuffers[i]->Release ();
1239 maFramebuffers[i] = NULL;
1240 }
1241 }
1242#endif /* VBOX_WITH_VRDP */
1243
1244 if (RTCritSectIsInitialized (&mCritSect))
1245 {
1246 RTCritSectDelete (&mCritSect);
1247 memset (&mCritSect, 0, sizeof (mCritSect));
1248 }
1249}
1250
1251int ConsoleVRDPServer::Launch (void)
1252{
1253 LogFlowThisFunc(("\n"));
1254#ifdef VBOX_WITH_VRDP
1255 int rc = VINF_SUCCESS;
1256 IVRDPServer *vrdpserver = mConsole->getVRDPServer ();
1257 Assert(vrdpserver);
1258 BOOL vrdpEnabled = FALSE;
1259
1260 HRESULT rc2 = vrdpserver->COMGETTER(Enabled) (&vrdpEnabled);
1261 AssertComRC(rc2);
1262
1263 if (SUCCEEDED(rc2) && vrdpEnabled)
1264 {
1265 if (loadVRDPLibrary ())
1266 {
1267 rc = mpfnVRDPCreateServer (&mCallbacks.header, this, (VRDPINTERFACEHDR **)&mpEntryPoints, &mhServer);
1268
1269 if (RT_SUCCESS(rc))
1270 {
1271#ifdef VBOX_WITH_USB
1272 remoteUSBThreadStart ();
1273#endif /* VBOX_WITH_USB */
1274 }
1275 else if (rc != VERR_NET_ADDRESS_IN_USE)
1276 AssertMsgFailed(("Could not start VRDP server: rc = %Rrc\n", rc));
1277 }
1278 else
1279 {
1280 AssertMsgFailed(("Could not load the VRDP library\n"));
1281 rc = VERR_FILE_NOT_FOUND;
1282 }
1283 }
1284#else
1285 int rc = VERR_NOT_SUPPORTED;
1286 LogRel(("VRDP: this version does not include the VRDP server.\n"));
1287#endif /* VBOX_WITH_VRDP */
1288 return rc;
1289}
1290
1291void ConsoleVRDPServer::EnableConnections (void)
1292{
1293#ifdef VBOX_WITH_VRDP
1294 if (mpEntryPoints && mhServer)
1295 {
1296 mpEntryPoints->VRDPEnableConnections (mhServer, true);
1297 }
1298#endif /* VBOX_WITH_VRDP */
1299}
1300
1301void ConsoleVRDPServer::DisconnectClient (uint32_t u32ClientId, bool fReconnect)
1302{
1303#ifdef VBOX_WITH_VRDP
1304 if (mpEntryPoints && mhServer)
1305 {
1306 mpEntryPoints->VRDPDisconnect (mhServer, u32ClientId, fReconnect);
1307 }
1308#endif /* VBOX_WITH_VRDP */
1309}
1310
1311void ConsoleVRDPServer::MousePointerUpdate (const VRDPCOLORPOINTER *pPointer)
1312{
1313#ifdef VBOX_WITH_VRDP
1314 if (mpEntryPoints && mhServer)
1315 {
1316 mpEntryPoints->VRDPColorPointer (mhServer, pPointer);
1317 }
1318#endif /* VBOX_WITH_VRDP */
1319}
1320
1321void ConsoleVRDPServer::MousePointerHide (void)
1322{
1323#ifdef VBOX_WITH_VRDP
1324 if (mpEntryPoints && mhServer)
1325 {
1326 mpEntryPoints->VRDPHidePointer (mhServer);
1327 }
1328#endif /* VBOX_WITH_VRDP */
1329}
1330
1331void ConsoleVRDPServer::Stop (void)
1332{
1333 Assert(VALID_PTR(this)); /** @todo r=bird: there are(/was) some odd cases where this buster was invalid on
1334 * linux. Just remove this when it's 100% sure that problem has been fixed. */
1335#ifdef VBOX_WITH_VRDP
1336 if (mhServer)
1337 {
1338 HVRDPSERVER hServer = mhServer;
1339
1340 /* Reset the handle to avoid further calls to the server. */
1341 mhServer = 0;
1342
1343 if (mpEntryPoints && hServer)
1344 {
1345 mpEntryPoints->VRDPDestroy (hServer);
1346 }
1347 }
1348#endif /* VBOX_WITH_VRDP */
1349
1350#ifdef VBOX_WITH_USB
1351 remoteUSBThreadStop ();
1352#endif /* VBOX_WITH_USB */
1353
1354 mpfnAuthEntry = NULL;
1355 mpfnAuthEntry2 = NULL;
1356
1357 if (mAuthLibrary)
1358 {
1359 RTLdrClose(mAuthLibrary);
1360 mAuthLibrary = 0;
1361 }
1362}
1363
1364/* Worker thread for Remote USB. The thread polls the clients for
1365 * the list of attached USB devices.
1366 * The thread is also responsible for attaching/detaching devices
1367 * to/from the VM.
1368 *
1369 * It is expected that attaching/detaching is not a frequent operation.
1370 *
1371 * The thread is always running when the VRDP server is active.
1372 *
1373 * The thread scans backends and requests the device list every 2 seconds.
1374 *
1375 * When device list is available, the thread calls the Console to process it.
1376 *
1377 */
1378#define VRDP_DEVICE_LIST_PERIOD_MS (2000)
1379
1380#ifdef VBOX_WITH_USB
1381static DECLCALLBACK(int) threadRemoteUSB (RTTHREAD self, void *pvUser)
1382{
1383 ConsoleVRDPServer *pOwner = (ConsoleVRDPServer *)pvUser;
1384
1385 LogFlow(("Console::threadRemoteUSB: start. owner = %p.\n", pOwner));
1386
1387 pOwner->notifyRemoteUSBThreadRunning (self);
1388
1389 while (pOwner->isRemoteUSBThreadRunning ())
1390 {
1391 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1392
1393 while ((pRemoteUSBBackend = pOwner->usbBackendGetNext (pRemoteUSBBackend)) != NULL)
1394 {
1395 pRemoteUSBBackend->PollRemoteDevices ();
1396 }
1397
1398 pOwner->waitRemoteUSBThreadEvent (VRDP_DEVICE_LIST_PERIOD_MS);
1399
1400 LogFlow(("Console::threadRemoteUSB: iteration. owner = %p.\n", pOwner));
1401 }
1402
1403 return VINF_SUCCESS;
1404}
1405
1406void ConsoleVRDPServer::notifyRemoteUSBThreadRunning (RTTHREAD thread)
1407{
1408 mUSBBackends.thread = thread;
1409 mUSBBackends.fThreadRunning = true;
1410 int rc = RTThreadUserSignal (thread);
1411 AssertRC(rc);
1412}
1413
1414bool ConsoleVRDPServer::isRemoteUSBThreadRunning (void)
1415{
1416 return mUSBBackends.fThreadRunning;
1417}
1418
1419void ConsoleVRDPServer::waitRemoteUSBThreadEvent (RTMSINTERVAL cMillies)
1420{
1421 int rc = RTSemEventWait (mUSBBackends.event, cMillies);
1422 Assert (RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1423 NOREF(rc);
1424}
1425
1426void ConsoleVRDPServer::remoteUSBThreadStart (void)
1427{
1428 int rc = RTSemEventCreate (&mUSBBackends.event);
1429
1430 if (RT_FAILURE(rc))
1431 {
1432 AssertFailed ();
1433 mUSBBackends.event = 0;
1434 }
1435
1436 if (RT_SUCCESS(rc))
1437 {
1438 rc = RTThreadCreate (&mUSBBackends.thread, threadRemoteUSB, this, 65536,
1439 RTTHREADTYPE_VRDP_IO, RTTHREADFLAGS_WAITABLE, "remote usb");
1440 }
1441
1442 if (RT_FAILURE(rc))
1443 {
1444 LogRel(("Warning: could not start the remote USB thread, rc = %Rrc!!!\n", rc));
1445 mUSBBackends.thread = NIL_RTTHREAD;
1446 }
1447 else
1448 {
1449 /* Wait until the thread is ready. */
1450 rc = RTThreadUserWait (mUSBBackends.thread, 60000);
1451 AssertRC(rc);
1452 Assert (mUSBBackends.fThreadRunning || RT_FAILURE(rc));
1453 }
1454}
1455
1456void ConsoleVRDPServer::remoteUSBThreadStop (void)
1457{
1458 mUSBBackends.fThreadRunning = false;
1459
1460 if (mUSBBackends.thread != NIL_RTTHREAD)
1461 {
1462 Assert (mUSBBackends.event != 0);
1463
1464 RTSemEventSignal (mUSBBackends.event);
1465
1466 int rc = RTThreadWait (mUSBBackends.thread, 60000, NULL);
1467 AssertRC(rc);
1468
1469 mUSBBackends.thread = NIL_RTTHREAD;
1470 }
1471
1472 if (mUSBBackends.event)
1473 {
1474 RTSemEventDestroy (mUSBBackends.event);
1475 mUSBBackends.event = 0;
1476 }
1477}
1478#endif /* VBOX_WITH_USB */
1479
1480VRDPAuthResult ConsoleVRDPServer::Authenticate (const Guid &uuid, VRDPAuthGuestJudgement guestJudgement,
1481 const char *pszUser, const char *pszPassword, const char *pszDomain,
1482 uint32_t u32ClientId)
1483{
1484 VRDPAUTHUUID rawuuid;
1485
1486 memcpy (rawuuid, ((Guid &)uuid).ptr (), sizeof (rawuuid));
1487
1488 LogFlow(("ConsoleVRDPServer::Authenticate: uuid = %RTuuid, guestJudgement = %d, pszUser = %s, pszPassword = %s, pszDomain = %s, u32ClientId = %d\n",
1489 rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, u32ClientId));
1490
1491 /*
1492 * Called only from VRDP input thread. So thread safety is not required.
1493 */
1494
1495 if (!mAuthLibrary)
1496 {
1497 /* Load the external authentication library. */
1498
1499 ComPtr<IMachine> machine;
1500 mConsole->COMGETTER(Machine)(machine.asOutParam());
1501
1502 ComPtr<IVirtualBox> virtualBox;
1503 machine->COMGETTER(Parent)(virtualBox.asOutParam());
1504
1505 ComPtr<ISystemProperties> systemProperties;
1506 virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
1507
1508 Bstr authLibrary;
1509 systemProperties->COMGETTER(RemoteDisplayAuthLibrary)(authLibrary.asOutParam());
1510
1511 Utf8Str filename = authLibrary;
1512
1513 LogRel(("VRDPAUTH: ConsoleVRDPServer::Authenticate: loading external authentication library '%ls'\n", authLibrary.raw()));
1514
1515 int rc;
1516 if (RTPathHavePath(filename.c_str()))
1517 rc = RTLdrLoad(filename.c_str(), &mAuthLibrary);
1518 else
1519 rc = RTLdrLoadAppPriv(filename.c_str(), &mAuthLibrary);
1520
1521 if (RT_FAILURE(rc))
1522 LogRel(("VRDPAUTH: Failed to load external authentication library. Error code: %Rrc\n", rc));
1523
1524 if (RT_SUCCESS(rc))
1525 {
1526 /* Get the entry point. */
1527 mpfnAuthEntry2 = NULL;
1528 int rc2 = RTLdrGetSymbol(mAuthLibrary, "VRDPAuth2", (void**)&mpfnAuthEntry2);
1529 if (RT_FAILURE(rc2))
1530 {
1531 if (rc2 != VERR_SYMBOL_NOT_FOUND)
1532 {
1533 LogRel(("VRDPAUTH: Could not resolve import '%s'. Error code: %Rrc\n", "VRDPAuth2", rc2));
1534 }
1535 rc = rc2;
1536 }
1537
1538 /* Get the entry point. */
1539 mpfnAuthEntry = NULL;
1540 rc2 = RTLdrGetSymbol(mAuthLibrary, "VRDPAuth", (void**)&mpfnAuthEntry);
1541 if (RT_FAILURE(rc2))
1542 {
1543 if (rc2 != VERR_SYMBOL_NOT_FOUND)
1544 {
1545 LogRel(("VRDPAUTH: Could not resolve import '%s'. Error code: %Rrc\n", "VRDPAuth", rc2));
1546 }
1547 rc = rc2;
1548 }
1549
1550 if (mpfnAuthEntry2 || mpfnAuthEntry)
1551 {
1552 LogRel(("VRDPAUTH: Using entry point '%s'.\n", mpfnAuthEntry2? "VRDPAuth2": "VRDPAuth"));
1553 rc = VINF_SUCCESS;
1554 }
1555 }
1556
1557 if (RT_FAILURE(rc))
1558 {
1559 mConsole->setError(E_FAIL,
1560 mConsole->tr("Could not load the external authentication library '%s' (%Rrc)"),
1561 filename.c_str(),
1562 rc);
1563
1564 mpfnAuthEntry = NULL;
1565 mpfnAuthEntry2 = NULL;
1566
1567 if (mAuthLibrary)
1568 {
1569 RTLdrClose(mAuthLibrary);
1570 mAuthLibrary = 0;
1571 }
1572
1573 return VRDPAuthAccessDenied;
1574 }
1575 }
1576
1577 Assert (mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2));
1578
1579 VRDPAuthResult result = mpfnAuthEntry2?
1580 mpfnAuthEntry2 (&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, true, u32ClientId):
1581 mpfnAuthEntry (&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain);
1582
1583 switch (result)
1584 {
1585 case VRDPAuthAccessDenied:
1586 LogRel(("VRDPAUTH: external authentication module returned 'access denied'\n"));
1587 break;
1588 case VRDPAuthAccessGranted:
1589 LogRel(("VRDPAUTH: external authentication module returned 'access granted'\n"));
1590 break;
1591 case VRDPAuthDelegateToGuest:
1592 LogRel(("VRDPAUTH: external authentication module returned 'delegate request to guest'\n"));
1593 break;
1594 default:
1595 LogRel(("VRDPAUTH: external authentication module returned incorrect return code %d\n", result));
1596 result = VRDPAuthAccessDenied;
1597 }
1598
1599 LogFlow(("ConsoleVRDPServer::Authenticate: result = %d\n", result));
1600
1601 return result;
1602}
1603
1604void ConsoleVRDPServer::AuthDisconnect (const Guid &uuid, uint32_t u32ClientId)
1605{
1606 VRDPAUTHUUID rawuuid;
1607
1608 memcpy (rawuuid, ((Guid &)uuid).ptr (), sizeof (rawuuid));
1609
1610 LogFlow(("ConsoleVRDPServer::AuthDisconnect: uuid = %RTuuid, u32ClientId = %d\n",
1611 rawuuid, u32ClientId));
1612
1613 Assert (mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2));
1614
1615 if (mpfnAuthEntry2)
1616 mpfnAuthEntry2 (&rawuuid, VRDPAuthGuestNotAsked, NULL, NULL, NULL, false, u32ClientId);
1617}
1618
1619int ConsoleVRDPServer::lockConsoleVRDPServer (void)
1620{
1621 int rc = RTCritSectEnter (&mCritSect);
1622 AssertRC(rc);
1623 return rc;
1624}
1625
1626void ConsoleVRDPServer::unlockConsoleVRDPServer (void)
1627{
1628 RTCritSectLeave (&mCritSect);
1629}
1630
1631DECLCALLBACK(int) ConsoleVRDPServer::ClipboardCallback (void *pvCallback,
1632 uint32_t u32ClientId,
1633 uint32_t u32Function,
1634 uint32_t u32Format,
1635 const void *pvData,
1636 uint32_t cbData)
1637{
1638 LogFlowFunc(("pvCallback = %p, u32ClientId = %d, u32Function = %d, u32Format = 0x%08X, pvData = %p, cbData = %d\n",
1639 pvCallback, u32ClientId, u32Function, u32Format, pvData, cbData));
1640
1641 int rc = VINF_SUCCESS;
1642
1643 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvCallback);
1644
1645 NOREF(u32ClientId);
1646
1647 switch (u32Function)
1648 {
1649 case VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE:
1650 {
1651 if (pServer->mpfnClipboardCallback)
1652 {
1653 pServer->mpfnClipboardCallback (VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE,
1654 u32Format,
1655 (void *)pvData,
1656 cbData);
1657 }
1658 } break;
1659
1660 case VRDP_CLIPBOARD_FUNCTION_DATA_READ:
1661 {
1662 if (pServer->mpfnClipboardCallback)
1663 {
1664 pServer->mpfnClipboardCallback (VBOX_CLIPBOARD_EXT_FN_DATA_READ,
1665 u32Format,
1666 (void *)pvData,
1667 cbData);
1668 }
1669 } break;
1670
1671 default:
1672 rc = VERR_NOT_SUPPORTED;
1673 }
1674
1675 return rc;
1676}
1677
1678DECLCALLBACK(int) ConsoleVRDPServer::ClipboardServiceExtension (void *pvExtension,
1679 uint32_t u32Function,
1680 void *pvParms,
1681 uint32_t cbParms)
1682{
1683 LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
1684 pvExtension, u32Function, pvParms, cbParms));
1685
1686 int rc = VINF_SUCCESS;
1687
1688#ifdef VBOX_WITH_VRDP
1689 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvExtension);
1690
1691 VBOXCLIPBOARDEXTPARMS *pParms = (VBOXCLIPBOARDEXTPARMS *)pvParms;
1692
1693 switch (u32Function)
1694 {
1695 case VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK:
1696 {
1697 pServer->mpfnClipboardCallback = pParms->u.pfnCallback;
1698 } break;
1699
1700 case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
1701 {
1702 /* The guest announces clipboard formats. This must be delivered to all clients. */
1703 if (mpEntryPoints && pServer->mhServer)
1704 {
1705 mpEntryPoints->VRDPClipboard (pServer->mhServer,
1706 VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE,
1707 pParms->u32Format,
1708 NULL,
1709 0,
1710 NULL);
1711 }
1712 } break;
1713
1714 case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
1715 {
1716 /* The clipboard service expects that the pvData buffer will be filled
1717 * with clipboard data. The server returns the data from the client that
1718 * announced the requested format most recently.
1719 */
1720 if (mpEntryPoints && pServer->mhServer)
1721 {
1722 mpEntryPoints->VRDPClipboard (pServer->mhServer,
1723 VRDP_CLIPBOARD_FUNCTION_DATA_READ,
1724 pParms->u32Format,
1725 pParms->u.pvData,
1726 pParms->cbData,
1727 &pParms->cbData);
1728 }
1729 } break;
1730
1731 case VBOX_CLIPBOARD_EXT_FN_DATA_WRITE:
1732 {
1733 if (mpEntryPoints && pServer->mhServer)
1734 {
1735 mpEntryPoints->VRDPClipboard (pServer->mhServer,
1736 VRDP_CLIPBOARD_FUNCTION_DATA_WRITE,
1737 pParms->u32Format,
1738 pParms->u.pvData,
1739 pParms->cbData,
1740 NULL);
1741 }
1742 } break;
1743
1744 default:
1745 rc = VERR_NOT_SUPPORTED;
1746 }
1747#endif /* VBOX_WITH_VRDP */
1748
1749 return rc;
1750}
1751
1752void ConsoleVRDPServer::ClipboardCreate (uint32_t u32ClientId)
1753{
1754 int rc = lockConsoleVRDPServer ();
1755
1756 if (RT_SUCCESS(rc))
1757 {
1758 if (mcClipboardRefs == 0)
1759 {
1760 rc = HGCMHostRegisterServiceExtension (&mhClipboard, "VBoxSharedClipboard", ClipboardServiceExtension, this);
1761
1762 if (RT_SUCCESS(rc))
1763 {
1764 mcClipboardRefs++;
1765 }
1766 }
1767
1768 unlockConsoleVRDPServer ();
1769 }
1770}
1771
1772void ConsoleVRDPServer::ClipboardDelete (uint32_t u32ClientId)
1773{
1774 int rc = lockConsoleVRDPServer ();
1775
1776 if (RT_SUCCESS(rc))
1777 {
1778 mcClipboardRefs--;
1779
1780 if (mcClipboardRefs == 0)
1781 {
1782 HGCMHostUnregisterServiceExtension (mhClipboard);
1783 }
1784
1785 unlockConsoleVRDPServer ();
1786 }
1787}
1788
1789/* That is called on INPUT thread of the VRDP server.
1790 * The ConsoleVRDPServer keeps a list of created backend instances.
1791 */
1792void ConsoleVRDPServer::USBBackendCreate (uint32_t u32ClientId, void **ppvIntercept)
1793{
1794#ifdef VBOX_WITH_USB
1795 LogFlow(("ConsoleVRDPServer::USBBackendCreate: u32ClientId = %d\n", u32ClientId));
1796
1797 /* Create a new instance of the USB backend for the new client. */
1798 RemoteUSBBackend *pRemoteUSBBackend = new RemoteUSBBackend (mConsole, this, u32ClientId);
1799
1800 if (pRemoteUSBBackend)
1801 {
1802 pRemoteUSBBackend->AddRef (); /* 'Release' called in USBBackendDelete. */
1803
1804 /* Append the new instance in the list. */
1805 int rc = lockConsoleVRDPServer ();
1806
1807 if (RT_SUCCESS(rc))
1808 {
1809 pRemoteUSBBackend->pNext = mUSBBackends.pHead;
1810 if (mUSBBackends.pHead)
1811 {
1812 mUSBBackends.pHead->pPrev = pRemoteUSBBackend;
1813 }
1814 else
1815 {
1816 mUSBBackends.pTail = pRemoteUSBBackend;
1817 }
1818
1819 mUSBBackends.pHead = pRemoteUSBBackend;
1820
1821 unlockConsoleVRDPServer ();
1822
1823 if (ppvIntercept)
1824 {
1825 *ppvIntercept = pRemoteUSBBackend;
1826 }
1827 }
1828
1829 if (RT_FAILURE(rc))
1830 {
1831 pRemoteUSBBackend->Release ();
1832 }
1833 }
1834#endif /* VBOX_WITH_USB */
1835}
1836
1837void ConsoleVRDPServer::USBBackendDelete (uint32_t u32ClientId)
1838{
1839#ifdef VBOX_WITH_USB
1840 LogFlow(("ConsoleVRDPServer::USBBackendDelete: u32ClientId = %d\n", u32ClientId));
1841
1842 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1843
1844 /* Find the instance. */
1845 int rc = lockConsoleVRDPServer ();
1846
1847 if (RT_SUCCESS(rc))
1848 {
1849 pRemoteUSBBackend = usbBackendFind (u32ClientId);
1850
1851 if (pRemoteUSBBackend)
1852 {
1853 /* Notify that it will be deleted. */
1854 pRemoteUSBBackend->NotifyDelete ();
1855 }
1856
1857 unlockConsoleVRDPServer ();
1858 }
1859
1860 if (pRemoteUSBBackend)
1861 {
1862 /* Here the instance has been excluded from the list and can be dereferenced. */
1863 pRemoteUSBBackend->Release ();
1864 }
1865#endif
1866}
1867
1868void *ConsoleVRDPServer::USBBackendRequestPointer (uint32_t u32ClientId, const Guid *pGuid)
1869{
1870#ifdef VBOX_WITH_USB
1871 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1872
1873 /* Find the instance. */
1874 int rc = lockConsoleVRDPServer ();
1875
1876 if (RT_SUCCESS(rc))
1877 {
1878 pRemoteUSBBackend = usbBackendFind (u32ClientId);
1879
1880 if (pRemoteUSBBackend)
1881 {
1882 /* Inform the backend instance that it is referenced by the Guid. */
1883 bool fAdded = pRemoteUSBBackend->addUUID (pGuid);
1884
1885 if (fAdded)
1886 {
1887 /* Reference the instance because its pointer is being taken. */
1888 pRemoteUSBBackend->AddRef (); /* 'Release' is called in USBBackendReleasePointer. */
1889 }
1890 else
1891 {
1892 pRemoteUSBBackend = NULL;
1893 }
1894 }
1895
1896 unlockConsoleVRDPServer ();
1897 }
1898
1899 if (pRemoteUSBBackend)
1900 {
1901 return pRemoteUSBBackend->GetBackendCallbackPointer ();
1902 }
1903
1904#endif
1905 return NULL;
1906}
1907
1908void ConsoleVRDPServer::USBBackendReleasePointer (const Guid *pGuid)
1909{
1910#ifdef VBOX_WITH_USB
1911 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1912
1913 /* Find the instance. */
1914 int rc = lockConsoleVRDPServer ();
1915
1916 if (RT_SUCCESS(rc))
1917 {
1918 pRemoteUSBBackend = usbBackendFindByUUID (pGuid);
1919
1920 if (pRemoteUSBBackend)
1921 {
1922 pRemoteUSBBackend->removeUUID (pGuid);
1923 }
1924
1925 unlockConsoleVRDPServer ();
1926
1927 if (pRemoteUSBBackend)
1928 {
1929 pRemoteUSBBackend->Release ();
1930 }
1931 }
1932#endif
1933}
1934
1935RemoteUSBBackend *ConsoleVRDPServer::usbBackendGetNext (RemoteUSBBackend *pRemoteUSBBackend)
1936{
1937 LogFlow(("ConsoleVRDPServer::usbBackendGetNext: pBackend = %p\n", pRemoteUSBBackend));
1938
1939 RemoteUSBBackend *pNextRemoteUSBBackend = NULL;
1940#ifdef VBOX_WITH_USB
1941
1942 int rc = lockConsoleVRDPServer ();
1943
1944 if (RT_SUCCESS(rc))
1945 {
1946 if (pRemoteUSBBackend == NULL)
1947 {
1948 /* The first backend in the list is requested. */
1949 pNextRemoteUSBBackend = mUSBBackends.pHead;
1950 }
1951 else
1952 {
1953 /* Get pointer to the next backend. */
1954 pNextRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1955 }
1956
1957 if (pNextRemoteUSBBackend)
1958 {
1959 pNextRemoteUSBBackend->AddRef ();
1960 }
1961
1962 unlockConsoleVRDPServer ();
1963
1964 if (pRemoteUSBBackend)
1965 {
1966 pRemoteUSBBackend->Release ();
1967 }
1968 }
1969#endif
1970
1971 return pNextRemoteUSBBackend;
1972}
1973
1974#ifdef VBOX_WITH_USB
1975/* Internal method. Called under the ConsoleVRDPServerLock. */
1976RemoteUSBBackend *ConsoleVRDPServer::usbBackendFind (uint32_t u32ClientId)
1977{
1978 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
1979
1980 while (pRemoteUSBBackend)
1981 {
1982 if (pRemoteUSBBackend->ClientId () == u32ClientId)
1983 {
1984 break;
1985 }
1986
1987 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1988 }
1989
1990 return pRemoteUSBBackend;
1991}
1992
1993/* Internal method. Called under the ConsoleVRDPServerLock. */
1994RemoteUSBBackend *ConsoleVRDPServer::usbBackendFindByUUID (const Guid *pGuid)
1995{
1996 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
1997
1998 while (pRemoteUSBBackend)
1999 {
2000 if (pRemoteUSBBackend->findUUID (pGuid))
2001 {
2002 break;
2003 }
2004
2005 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
2006 }
2007
2008 return pRemoteUSBBackend;
2009}
2010#endif
2011
2012/* Internal method. Called by the backend destructor. */
2013void ConsoleVRDPServer::usbBackendRemoveFromList (RemoteUSBBackend *pRemoteUSBBackend)
2014{
2015#ifdef VBOX_WITH_USB
2016 int rc = lockConsoleVRDPServer ();
2017 AssertRC(rc);
2018
2019 /* Exclude the found instance from the list. */
2020 if (pRemoteUSBBackend->pNext)
2021 {
2022 pRemoteUSBBackend->pNext->pPrev = pRemoteUSBBackend->pPrev;
2023 }
2024 else
2025 {
2026 mUSBBackends.pTail = (RemoteUSBBackend *)pRemoteUSBBackend->pPrev;
2027 }
2028
2029 if (pRemoteUSBBackend->pPrev)
2030 {
2031 pRemoteUSBBackend->pPrev->pNext = pRemoteUSBBackend->pNext;
2032 }
2033 else
2034 {
2035 mUSBBackends.pHead = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
2036 }
2037
2038 pRemoteUSBBackend->pNext = pRemoteUSBBackend->pPrev = NULL;
2039
2040 unlockConsoleVRDPServer ();
2041#endif
2042}
2043
2044
2045void ConsoleVRDPServer::SendUpdate (unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate) const
2046{
2047#ifdef VBOX_WITH_VRDP
2048 if (mpEntryPoints && mhServer)
2049 {
2050 mpEntryPoints->VRDPUpdate (mhServer, uScreenId, pvUpdate, cbUpdate);
2051 }
2052#endif
2053}
2054
2055void ConsoleVRDPServer::SendResize (void) const
2056{
2057#ifdef VBOX_WITH_VRDP
2058 if (mpEntryPoints && mhServer)
2059 {
2060 mpEntryPoints->VRDPResize (mhServer);
2061 }
2062#endif
2063}
2064
2065void ConsoleVRDPServer::SendUpdateBitmap (unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h) const
2066{
2067#ifdef VBOX_WITH_VRDP
2068 VRDPORDERHDR update;
2069 update.x = x;
2070 update.y = y;
2071 update.w = w;
2072 update.h = h;
2073 if (mpEntryPoints && mhServer)
2074 {
2075 mpEntryPoints->VRDPUpdate (mhServer, uScreenId, &update, sizeof (update));
2076 }
2077#endif
2078}
2079
2080void ConsoleVRDPServer::SendAudioSamples (void *pvSamples, uint32_t cSamples, VRDPAUDIOFORMAT format) const
2081{
2082#ifdef VBOX_WITH_VRDP
2083 if (mpEntryPoints && mhServer)
2084 {
2085 mpEntryPoints->VRDPAudioSamples (mhServer, pvSamples, cSamples, format);
2086 }
2087#endif
2088}
2089
2090void ConsoleVRDPServer::SendAudioVolume (uint16_t left, uint16_t right) const
2091{
2092#ifdef VBOX_WITH_VRDP
2093 if (mpEntryPoints && mhServer)
2094 {
2095 mpEntryPoints->VRDPAudioVolume (mhServer, left, right);
2096 }
2097#endif
2098}
2099
2100void ConsoleVRDPServer::SendUSBRequest (uint32_t u32ClientId, void *pvParms, uint32_t cbParms) const
2101{
2102#ifdef VBOX_WITH_VRDP
2103 if (mpEntryPoints && mhServer)
2104 {
2105 mpEntryPoints->VRDPUSBRequest (mhServer, u32ClientId, pvParms, cbParms);
2106 }
2107#endif
2108}
2109
2110void ConsoleVRDPServer::QueryInfo (uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const
2111{
2112#ifdef VBOX_WITH_VRDP
2113 if (index == VRDP_QI_PORT)
2114 {
2115 uint32_t cbOut = sizeof (int32_t);
2116
2117 if (cbBuffer >= cbOut)
2118 {
2119 *pcbOut = cbOut;
2120 *(int32_t *)pvBuffer = (int32_t)mVRDPBindPort;
2121 }
2122 }
2123 else if (mpEntryPoints && mhServer)
2124 {
2125 mpEntryPoints->VRDPQueryInfo (mhServer, index, pvBuffer, cbBuffer, pcbOut);
2126 }
2127#endif
2128}
2129
2130#ifdef VBOX_WITH_VRDP
2131/* note: static function now! */
2132bool ConsoleVRDPServer::loadVRDPLibrary (void)
2133{
2134 int rc = VINF_SUCCESS;
2135
2136 if (!mVRDPLibrary)
2137 {
2138 rc = SUPR3HardenedLdrLoadAppPriv ("VBoxVRDP", &mVRDPLibrary);
2139
2140 if (RT_SUCCESS(rc))
2141 {
2142 LogFlow(("VRDPServer::loadLibrary(): successfully loaded VRDP library.\n"));
2143
2144 struct SymbolEntry
2145 {
2146 const char *name;
2147 void **ppfn;
2148 };
2149
2150 #define DEFSYMENTRY(a) { #a, (void**)&mpfn##a }
2151
2152 static const struct SymbolEntry symbols[] =
2153 {
2154 DEFSYMENTRY(VRDPCreateServer)
2155 };
2156
2157 #undef DEFSYMENTRY
2158
2159 for (unsigned i = 0; i < RT_ELEMENTS(symbols); i++)
2160 {
2161 rc = RTLdrGetSymbol(mVRDPLibrary, symbols[i].name, symbols[i].ppfn);
2162
2163 AssertMsgRC(rc, ("Error resolving VRDP symbol %s\n", symbols[i].name));
2164
2165 if (RT_FAILURE(rc))
2166 {
2167 break;
2168 }
2169 }
2170 }
2171 else
2172 {
2173 LogRel(("VRDPServer::loadLibrary(): failed to load VRDP library! VRDP not available: rc = %Rrc\n", rc));
2174 mVRDPLibrary = NULL;
2175 }
2176 }
2177
2178 // just to be safe
2179 if (RT_FAILURE(rc))
2180 {
2181 if (mVRDPLibrary)
2182 {
2183 RTLdrClose (mVRDPLibrary);
2184 mVRDPLibrary = NULL;
2185 }
2186 }
2187
2188 return (mVRDPLibrary != NULL);
2189}
2190#endif /* VBOX_WITH_VRDP */
2191
2192/*
2193 * IRemoteDisplayInfo implementation.
2194 */
2195// constructor / destructor
2196/////////////////////////////////////////////////////////////////////////////
2197
2198RemoteDisplayInfo::RemoteDisplayInfo()
2199 : mParent(NULL)
2200{
2201}
2202
2203RemoteDisplayInfo::~RemoteDisplayInfo()
2204{
2205}
2206
2207
2208HRESULT RemoteDisplayInfo::FinalConstruct()
2209{
2210 return S_OK;
2211}
2212
2213void RemoteDisplayInfo::FinalRelease()
2214{
2215 uninit ();
2216}
2217
2218// public methods only for internal purposes
2219/////////////////////////////////////////////////////////////////////////////
2220
2221/**
2222 * Initializes the guest object.
2223 */
2224HRESULT RemoteDisplayInfo::init (Console *aParent)
2225{
2226 LogFlowThisFunc(("aParent=%p\n", aParent));
2227
2228 ComAssertRet(aParent, E_INVALIDARG);
2229
2230 /* Enclose the state transition NotReady->InInit->Ready */
2231 AutoInitSpan autoInitSpan(this);
2232 AssertReturn(autoInitSpan.isOk(), E_FAIL);
2233
2234 unconst(mParent) = aParent;
2235
2236 /* Confirm a successful initialization */
2237 autoInitSpan.setSucceeded();
2238
2239 return S_OK;
2240}
2241
2242/**
2243 * Uninitializes the instance and sets the ready flag to FALSE.
2244 * Called either from FinalRelease() or by the parent when it gets destroyed.
2245 */
2246void RemoteDisplayInfo::uninit()
2247{
2248 LogFlowThisFunc(("\n"));
2249
2250 /* Enclose the state transition Ready->InUninit->NotReady */
2251 AutoUninitSpan autoUninitSpan(this);
2252 if (autoUninitSpan.uninitDone())
2253 return;
2254
2255 unconst(mParent) = NULL;
2256}
2257
2258// IRemoteDisplayInfo properties
2259/////////////////////////////////////////////////////////////////////////////
2260
2261#define IMPL_GETTER_BOOL(_aType, _aName, _aIndex) \
2262 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
2263 { \
2264 if (!a##_aName) \
2265 return E_POINTER; \
2266 \
2267 AutoCaller autoCaller(this); \
2268 if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2269 \
2270 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
2271 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2272 \
2273 uint32_t value; \
2274 uint32_t cbOut = 0; \
2275 \
2276 mParent->consoleVRDPServer ()->QueryInfo \
2277 (_aIndex, &value, sizeof (value), &cbOut); \
2278 \
2279 *a##_aName = cbOut? !!value: FALSE; \
2280 \
2281 return S_OK; \
2282 } \
2283 extern void IMPL_GETTER_BOOL_DUMMY(void)
2284
2285#define IMPL_GETTER_SCALAR(_aType, _aName, _aIndex, _aValueMask) \
2286 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
2287 { \
2288 if (!a##_aName) \
2289 return E_POINTER; \
2290 \
2291 AutoCaller autoCaller(this); \
2292 if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2293 \
2294 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
2295 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2296 \
2297 _aType value; \
2298 uint32_t cbOut = 0; \
2299 \
2300 mParent->consoleVRDPServer ()->QueryInfo \
2301 (_aIndex, &value, sizeof (value), &cbOut); \
2302 \
2303 if (_aValueMask) value &= (_aValueMask); \
2304 *a##_aName = cbOut? value: 0; \
2305 \
2306 return S_OK; \
2307 } \
2308 extern void IMPL_GETTER_SCALAR_DUMMY(void)
2309
2310#define IMPL_GETTER_BSTR(_aType, _aName, _aIndex) \
2311 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
2312 { \
2313 if (!a##_aName) \
2314 return E_POINTER; \
2315 \
2316 AutoCaller autoCaller(this); \
2317 if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2318 \
2319 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
2320 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2321 \
2322 uint32_t cbOut = 0; \
2323 \
2324 mParent->consoleVRDPServer ()->QueryInfo \
2325 (_aIndex, NULL, 0, &cbOut); \
2326 \
2327 if (cbOut == 0) \
2328 { \
2329 Bstr str(""); \
2330 str.cloneTo(a##_aName); \
2331 return S_OK; \
2332 } \
2333 \
2334 char *pchBuffer = (char *)RTMemTmpAlloc (cbOut); \
2335 \
2336 if (!pchBuffer) \
2337 { \
2338 Log(("RemoteDisplayInfo::" \
2339 #_aName \
2340 ": Failed to allocate memory %d bytes\n", cbOut)); \
2341 return E_OUTOFMEMORY; \
2342 } \
2343 \
2344 mParent->consoleVRDPServer ()->QueryInfo \
2345 (_aIndex, pchBuffer, cbOut, &cbOut); \
2346 \
2347 Bstr str(pchBuffer); \
2348 \
2349 str.cloneTo(a##_aName); \
2350 \
2351 RTMemTmpFree (pchBuffer); \
2352 \
2353 return S_OK; \
2354 } \
2355 extern void IMPL_GETTER_BSTR_DUMMY(void)
2356
2357IMPL_GETTER_BOOL (BOOL, Active, VRDP_QI_ACTIVE);
2358IMPL_GETTER_SCALAR (LONG, Port, VRDP_QI_PORT, 0);
2359IMPL_GETTER_SCALAR (ULONG, NumberOfClients, VRDP_QI_NUMBER_OF_CLIENTS, 0);
2360IMPL_GETTER_SCALAR (LONG64, BeginTime, VRDP_QI_BEGIN_TIME, 0);
2361IMPL_GETTER_SCALAR (LONG64, EndTime, VRDP_QI_END_TIME, 0);
2362IMPL_GETTER_SCALAR (LONG64, BytesSent, VRDP_QI_BYTES_SENT, INT64_MAX);
2363IMPL_GETTER_SCALAR (LONG64, BytesSentTotal, VRDP_QI_BYTES_SENT_TOTAL, INT64_MAX);
2364IMPL_GETTER_SCALAR (LONG64, BytesReceived, VRDP_QI_BYTES_RECEIVED, INT64_MAX);
2365IMPL_GETTER_SCALAR (LONG64, BytesReceivedTotal, VRDP_QI_BYTES_RECEIVED_TOTAL, INT64_MAX);
2366IMPL_GETTER_BSTR (BSTR, User, VRDP_QI_USER);
2367IMPL_GETTER_BSTR (BSTR, Domain, VRDP_QI_DOMAIN);
2368IMPL_GETTER_BSTR (BSTR, ClientName, VRDP_QI_CLIENT_NAME);
2369IMPL_GETTER_BSTR (BSTR, ClientIP, VRDP_QI_CLIENT_IP);
2370IMPL_GETTER_SCALAR (ULONG, ClientVersion, VRDP_QI_CLIENT_VERSION, 0);
2371IMPL_GETTER_SCALAR (ULONG, EncryptionStyle, VRDP_QI_ENCRYPTION_STYLE, 0);
2372
2373#undef IMPL_GETTER_BSTR
2374#undef IMPL_GETTER_SCALAR
2375#undef IMPL_GETTER_BOOL
2376/* 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