VirtualBox

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

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

scm cleanup run.

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