VirtualBox

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

Last change on this file since 5991 was 5991, checked in by vboxsync, 17 years ago

VRDP cleanup: OSE fix.

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