VirtualBox

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

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

Drop existing RDP connection and allow the new client to connect, configurable, default off.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use