VirtualBox

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

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