VirtualBox

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

Last change on this file since 14981 was 14772, checked in by vboxsync, 16 years ago

Added vim modelines to aid following coding guidelines, like no tabs,
similar to what is already in the xidl file.

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