VirtualBox

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

Last change on this file since 26497 was 26235, checked in by vboxsync, 15 years ago

Main: coding style

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