VirtualBox

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

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

Removed obsolete VRDP server interface that used COM.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.4 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
849static void fixKbdLockStatus (VRDPInputSynch *pInputSynch, IKeyboard *pKeyboard)
850{
851 if ( pInputSynch->cGuestNumLockAdaptions
852 && (pInputSynch->fGuestNumLock != pInputSynch->fClientNumLock))
853 {
854 pInputSynch->cGuestNumLockAdaptions--;
855 pKeyboard->PutScancode(0x45);
856 pKeyboard->PutScancode(0x45 | 0x80);
857 }
858 if ( pInputSynch->cGuestCapsLockAdaptions
859 && (pInputSynch->fGuestCapsLock != pInputSynch->fClientCapsLock))
860 {
861 pInputSynch->cGuestCapsLockAdaptions--;
862 pKeyboard->PutScancode(0x3a);
863 pKeyboard->PutScancode(0x3a | 0x80);
864 }
865}
866
867DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackInput (void *pvCallback, int type, const void *pvInput, unsigned cbInput)
868{
869 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
870 Console *pConsole = server->mConsole;
871
872 switch (type)
873 {
874 case VRDP_INPUT_SCANCODE:
875 {
876 if (cbInput == sizeof (VRDPINPUTSCANCODE))
877 {
878 IKeyboard *pKeyboard = pConsole->getKeyboard ();
879
880 const VRDPINPUTSCANCODE *pInputScancode = (VRDPINPUTSCANCODE *)pvInput;
881
882 /* Track lock keys. */
883 if (pInputScancode->uScancode == 0x45)
884 {
885 server->m_InputSynch.fClientNumLock = !server->m_InputSynch.fClientNumLock;
886 }
887 else if (pInputScancode->uScancode == 0x3a)
888 {
889 server->m_InputSynch.fClientCapsLock = !server->m_InputSynch.fClientCapsLock;
890 }
891 else if (pInputScancode->uScancode == 0x46)
892 {
893 server->m_InputSynch.fClientScrollLock = !server->m_InputSynch.fClientScrollLock;
894 }
895 else if ((pInputScancode->uScancode & 0x80) == 0)
896 {
897 /* Key pressed. */
898 fixKbdLockStatus (&server->m_InputSynch, pKeyboard);
899 }
900
901 pKeyboard->PutScancode((LONG)pInputScancode->uScancode);
902 }
903 } break;
904
905 case VRDP_INPUT_POINT:
906 {
907 if (cbInput == sizeof (VRDPINPUTPOINT))
908 {
909 const VRDPINPUTPOINT *pInputPoint = (VRDPINPUTPOINT *)pvInput;
910
911 int mouseButtons = 0;
912 int iWheel = 0;
913
914 if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON1)
915 {
916 mouseButtons |= MouseButtonState_LeftButton;
917 }
918 if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON2)
919 {
920 mouseButtons |= MouseButtonState_RightButton;
921 }
922 if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON3)
923 {
924 mouseButtons |= MouseButtonState_MiddleButton;
925 }
926 if (pInputPoint->uButtons & VRDP_INPUT_POINT_WHEEL_UP)
927 {
928 mouseButtons |= MouseButtonState_WheelUp;
929 iWheel = -1;
930 }
931 if (pInputPoint->uButtons & VRDP_INPUT_POINT_WHEEL_DOWN)
932 {
933 mouseButtons |= MouseButtonState_WheelDown;
934 iWheel = 1;
935 }
936
937 if (server->m_fGuestWantsAbsolute)
938 {
939 pConsole->getMouse()->PutMouseEventAbsolute (pInputPoint->x + 1, pInputPoint->y + 1, iWheel, mouseButtons);
940 } else
941 {
942 pConsole->getMouse()->PutMouseEvent (pInputPoint->x - server->m_mousex,
943 pInputPoint->y - server->m_mousey,
944 iWheel, mouseButtons);
945 server->m_mousex = pInputPoint->x;
946 server->m_mousey = pInputPoint->y;
947 }
948 }
949 } break;
950
951 case VRDP_INPUT_CAD:
952 {
953 pConsole->getKeyboard ()->PutCAD();
954 } break;
955
956 case VRDP_INPUT_RESET:
957 {
958 pConsole->Reset();
959 } break;
960
961 case VRDP_INPUT_SYNCH:
962 {
963 if (cbInput == sizeof (VRDPINPUTSYNCH))
964 {
965 IKeyboard *pKeyboard = pConsole->getKeyboard ();
966
967 const VRDPINPUTSYNCH *pInputSynch = (VRDPINPUTSYNCH *)pvInput;
968
969 server->m_InputSynch.fClientNumLock = (pInputSynch->uLockStatus & VRDP_INPUT_SYNCH_NUMLOCK) != 0;
970 server->m_InputSynch.fClientCapsLock = (pInputSynch->uLockStatus & VRDP_INPUT_SYNCH_CAPITAL) != 0;
971 server->m_InputSynch.fClientScrollLock = (pInputSynch->uLockStatus & VRDP_INPUT_SYNCH_SCROLL) != 0;
972
973 /* The client initiated synchronization. Always make the guest to reflect the client state.
974 * Than means, when the guest changes the state itself, it is forced to return to the client
975 * state.
976 */
977 if (server->m_InputSynch.fClientNumLock != server->m_InputSynch.fGuestNumLock)
978 {
979 server->m_InputSynch.cGuestNumLockAdaptions = 2;
980 }
981
982 if (server->m_InputSynch.fClientCapsLock != server->m_InputSynch.fGuestCapsLock)
983 {
984 server->m_InputSynch.cGuestCapsLockAdaptions = 2;
985 }
986
987 fixKbdLockStatus (&server->m_InputSynch, pKeyboard);
988 }
989 } break;
990
991 default:
992 break;
993 }
994}
995
996DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackVideoModeHint (void *pvCallback, unsigned cWidth, unsigned cHeight, unsigned cBitsPerPixel, unsigned uScreenId)
997{
998 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
999
1000 server->mConsole->getDisplay ()->SetVideoModeHint(cWidth, cHeight, cBitsPerPixel, uScreenId);
1001}
1002
1003ConsoleVRDPServer::ConsoleVRDPServer (Console *console)
1004{
1005 mConsole = console;
1006
1007 int rc = RTCritSectInit (&mCritSect);
1008 AssertRC (rc);
1009
1010 mcClipboardRefs = 0;
1011 mpfnClipboardCallback = NULL;
1012
1013#ifdef VBOX_WITH_USB
1014 mUSBBackends.pHead = NULL;
1015 mUSBBackends.pTail = NULL;
1016
1017 mUSBBackends.thread = NIL_RTTHREAD;
1018 mUSBBackends.fThreadRunning = false;
1019 mUSBBackends.event = 0;
1020#endif
1021
1022#ifdef VBOX_VRDP
1023 mhServer = 0;
1024
1025 m_fGuestWantsAbsolute = false;
1026 m_mousex = 0;
1027 m_mousey = 0;
1028
1029 m_InputSynch.cGuestNumLockAdaptions = 2;
1030 m_InputSynch.cGuestCapsLockAdaptions = 2;
1031
1032 m_InputSynch.fGuestNumLock = false;
1033 m_InputSynch.fGuestCapsLock = false;
1034 m_InputSynch.fGuestScrollLock = false;
1035
1036 m_InputSynch.fClientNumLock = false;
1037 m_InputSynch.fClientCapsLock = false;
1038 m_InputSynch.fClientScrollLock = false;
1039
1040 memset (maFramebuffers, 0, sizeof (maFramebuffers));
1041
1042 mConsoleCallback = new VRDPConsoleCallback(this);
1043 mConsoleCallback->AddRef();
1044 console->RegisterCallback(mConsoleCallback);
1045#endif /* VBOX_VRDP */
1046
1047 mAuthLibrary = 0;
1048}
1049
1050ConsoleVRDPServer::~ConsoleVRDPServer ()
1051{
1052 Stop ();
1053
1054 if (mConsoleCallback)
1055 {
1056 mConsole->UnregisterCallback(mConsoleCallback);
1057 mConsoleCallback->Release();
1058 mConsoleCallback = NULL;
1059 }
1060
1061 unsigned i;
1062 for (i = 0; i < ELEMENTS(maFramebuffers); i++)
1063 {
1064 if (maFramebuffers[i])
1065 {
1066 maFramebuffers[i]->Release ();
1067 maFramebuffers[i] = NULL;
1068 }
1069 }
1070
1071 if (RTCritSectIsInitialized (&mCritSect))
1072 {
1073 RTCritSectDelete (&mCritSect);
1074 memset (&mCritSect, 0, sizeof (mCritSect));
1075 }
1076}
1077
1078int ConsoleVRDPServer::Launch (void)
1079{
1080 LogFlowMember(("ConsoleVRDPServer::Launch\n"));
1081#ifdef VBOX_VRDP
1082 int rc = VINF_SUCCESS;
1083 IVRDPServer *vrdpserver = mConsole->getVRDPServer ();
1084 Assert(vrdpserver);
1085 BOOL vrdpEnabled = FALSE;
1086
1087 HRESULT rc2 = vrdpserver->COMGETTER(Enabled) (&vrdpEnabled);
1088 AssertComRC(rc2);
1089
1090 if (SUCCEEDED (rc2)
1091 && vrdpEnabled
1092 && loadVRDPLibrary ())
1093 {
1094 rc = mpfnVRDPCreateServer (&mCallbacks.header, this, (VRDPINTERFACEHDR **)&mpEntryPoints, &mhServer);
1095
1096 if (VBOX_SUCCESS(rc))
1097 {
1098#ifdef VBOX_WITH_USB
1099 remoteUSBThreadStart ();
1100#endif /* VBOX_WITH_USB */
1101 }
1102 else
1103 AssertMsgFailed(("Could not start VRDP server: rc = %Vrc\n", rc));
1104 }
1105#else
1106 int rc = VERR_NOT_SUPPORTED;
1107 LogRel(("VRDP: this version does not include the VRDP server.\n"));
1108#endif /* VBOX_VRDP */
1109 return rc;
1110}
1111
1112void ConsoleVRDPServer::EnableConnections (void)
1113{
1114#ifdef VBOX_VRDP
1115 if (mpEntryPoints && mhServer)
1116 {
1117 mpEntryPoints->VRDPEnableConnections (mhServer, true);
1118 }
1119#endif /* VBOX_VRDP */
1120}
1121
1122void ConsoleVRDPServer::MousePointerUpdate (const VRDPCOLORPOINTER *pPointer)
1123{
1124#ifdef VBOX_VRDP
1125 if (mpEntryPoints && mhServer)
1126 {
1127 mpEntryPoints->VRDPColorPointer (mhServer, pPointer);
1128 }
1129#endif /* VBOX_VRDP */
1130}
1131
1132void ConsoleVRDPServer::MousePointerHide (void)
1133{
1134#ifdef VBOX_VRDP
1135 if (mpEntryPoints && mhServer)
1136 {
1137 mpEntryPoints->VRDPHidePointer (mhServer);
1138 }
1139#endif /* VBOX_VRDP */
1140}
1141
1142void ConsoleVRDPServer::Stop (void)
1143{
1144 Assert(VALID_PTR(this)); /** @todo r=bird: there are(/was) some odd cases where this buster was invalid on
1145 * linux. Just remove this when it's 100% sure that problem has been fixed. */
1146#ifdef VBOX_VRDP
1147 if (mhServer)
1148 {
1149 HVRDPSERVER hServer = mhServer;
1150
1151 /* Reset the handle to avoid further calls to the server. */
1152 mhServer = 0;
1153
1154 if (mpEntryPoints && hServer)
1155 {
1156 mpEntryPoints->VRDPDestroy (hServer);
1157 }
1158 }
1159#endif /* VBOX_VRDP */
1160
1161#ifdef VBOX_WITH_USB
1162 remoteUSBThreadStop ();
1163#endif /* VBOX_WITH_USB */
1164
1165 mpfnAuthEntry = NULL;
1166 mpfnAuthEntry2 = NULL;
1167
1168 if (mAuthLibrary)
1169 {
1170 RTLdrClose(mAuthLibrary);
1171 mAuthLibrary = 0;
1172 }
1173}
1174
1175/* Worker thread for Remote USB. The thread polls the clients for
1176 * the list of attached USB devices.
1177 * The thread is also responsible for attaching/detaching devices
1178 * to/from the VM.
1179 *
1180 * It is expected that attaching/detaching is not a frequent operation.
1181 *
1182 * The thread is always running when the VRDP server is active.
1183 *
1184 * The thread scans backends and requests the device list every 2 seconds.
1185 *
1186 * When device list is available, the thread calls the Console to process it.
1187 *
1188 */
1189#define VRDP_DEVICE_LIST_PERIOD_MS (2000)
1190
1191#ifdef VBOX_WITH_USB
1192static DECLCALLBACK(int) threadRemoteUSB (RTTHREAD self, void *pvUser)
1193{
1194 ConsoleVRDPServer *pOwner = (ConsoleVRDPServer *)pvUser;
1195
1196 LogFlow(("Console::threadRemoteUSB: start. owner = %p.\n", pOwner));
1197
1198 pOwner->notifyRemoteUSBThreadRunning (self);
1199
1200 while (pOwner->isRemoteUSBThreadRunning ())
1201 {
1202 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1203
1204 while ((pRemoteUSBBackend = pOwner->usbBackendGetNext (pRemoteUSBBackend)) != NULL)
1205 {
1206 pRemoteUSBBackend->PollRemoteDevices ();
1207 }
1208
1209 pOwner->waitRemoteUSBThreadEvent (VRDP_DEVICE_LIST_PERIOD_MS);
1210
1211 LogFlow(("Console::threadRemoteUSB: iteration. owner = %p.\n", pOwner));
1212 }
1213
1214 return VINF_SUCCESS;
1215}
1216
1217void ConsoleVRDPServer::notifyRemoteUSBThreadRunning (RTTHREAD thread)
1218{
1219 mUSBBackends.thread = thread;
1220 mUSBBackends.fThreadRunning = true;
1221 int rc = RTThreadUserSignal (thread);
1222 AssertRC (rc);
1223}
1224
1225bool ConsoleVRDPServer::isRemoteUSBThreadRunning (void)
1226{
1227 return mUSBBackends.fThreadRunning;
1228}
1229
1230void ConsoleVRDPServer::waitRemoteUSBThreadEvent (unsigned cMillies)
1231{
1232 int rc = RTSemEventWait (mUSBBackends.event, cMillies);
1233 Assert (VBOX_SUCCESS(rc) || rc == VERR_TIMEOUT);
1234 NOREF(rc);
1235}
1236
1237void ConsoleVRDPServer::remoteUSBThreadStart (void)
1238{
1239 int rc = RTSemEventCreate (&mUSBBackends.event);
1240
1241 if (VBOX_FAILURE (rc))
1242 {
1243 AssertFailed ();
1244 mUSBBackends.event = 0;
1245 }
1246
1247 if (VBOX_SUCCESS (rc))
1248 {
1249 rc = RTThreadCreate (&mUSBBackends.thread, threadRemoteUSB, this, 65536,
1250 RTTHREADTYPE_VRDP_IO, RTTHREADFLAGS_WAITABLE, "remote usb");
1251 }
1252
1253 if (VBOX_FAILURE (rc))
1254 {
1255 LogRel(("Warning: could not start the remote USB thread, rc = %Vrc!!!\n", rc));
1256 mUSBBackends.thread = NIL_RTTHREAD;
1257 }
1258 else
1259 {
1260 /* Wait until the thread is ready. */
1261 rc = RTThreadUserWait (mUSBBackends.thread, 60000);
1262 AssertRC (rc);
1263 Assert (mUSBBackends.fThreadRunning || VBOX_FAILURE (rc));
1264 }
1265}
1266
1267void ConsoleVRDPServer::remoteUSBThreadStop (void)
1268{
1269 mUSBBackends.fThreadRunning = false;
1270
1271 if (mUSBBackends.thread != NIL_RTTHREAD)
1272 {
1273 Assert (mUSBBackends.event != 0);
1274
1275 RTSemEventSignal (mUSBBackends.event);
1276
1277 int rc = RTThreadWait (mUSBBackends.thread, 60000, NULL);
1278 AssertRC (rc);
1279
1280 mUSBBackends.thread = NIL_RTTHREAD;
1281 }
1282
1283 if (mUSBBackends.event)
1284 {
1285 RTSemEventDestroy (mUSBBackends.event);
1286 mUSBBackends.event = 0;
1287 }
1288}
1289#endif /* VBOX_WITH_USB */
1290
1291VRDPAuthResult ConsoleVRDPServer::Authenticate (const Guid &uuid, VRDPAuthGuestJudgement guestJudgement,
1292 const char *pszUser, const char *pszPassword, const char *pszDomain,
1293 uint32_t u32ClientId)
1294{
1295 VRDPAUTHUUID rawuuid;
1296
1297 memcpy (rawuuid, ((Guid &)uuid).ptr (), sizeof (rawuuid));
1298
1299 LogFlow(("ConsoleVRDPServer::Authenticate: uuid = %Vuuid, guestJudgement = %d, pszUser = %s, pszPassword = %s, pszDomain = %s, u32ClientId = %d\n",
1300 rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, u32ClientId));
1301
1302 /*
1303 * Called only from VRDP input thread. So thread safety is not required.
1304 */
1305
1306 if (!mAuthLibrary)
1307 {
1308 /* Load the external authentication library. */
1309
1310 ComPtr<IMachine> machine;
1311 mConsole->COMGETTER(Machine)(machine.asOutParam());
1312
1313 ComPtr<IVirtualBox> virtualBox;
1314 machine->COMGETTER(Parent)(virtualBox.asOutParam());
1315
1316 ComPtr<ISystemProperties> systemProperties;
1317 virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
1318
1319 Bstr authLibrary;
1320 systemProperties->COMGETTER(RemoteDisplayAuthLibrary)(authLibrary.asOutParam());
1321
1322 Utf8Str filename = authLibrary;
1323
1324 LogRel(("VRDPAUTH: ConsoleVRDPServer::Authenticate: loading external authentication library '%ls'\n", authLibrary.raw()));
1325
1326 int rc = RTLdrLoad (filename.raw(), &mAuthLibrary);
1327 if (VBOX_FAILURE (rc))
1328 LogRel(("VRDPAUTH: Failed to load external authentication library. Error code: %Vrc\n", rc));
1329
1330 if (VBOX_SUCCESS (rc))
1331 {
1332 /* Get the entry point. */
1333 mpfnAuthEntry2 = NULL;
1334 int rc2 = RTLdrGetSymbol(mAuthLibrary, "VRDPAuth2", (void**)&mpfnAuthEntry2);
1335 if (VBOX_FAILURE (rc2))
1336 {
1337 LogRel(("VRDPAUTH: Could not resolve import '%s'. Error code: %Vrc\n", "VRDPAuth2", rc2));
1338 rc = rc2;
1339 }
1340
1341 /* Get the entry point. */
1342 mpfnAuthEntry = NULL;
1343 rc2 = RTLdrGetSymbol(mAuthLibrary, "VRDPAuth", (void**)&mpfnAuthEntry);
1344 if (VBOX_FAILURE (rc2))
1345 {
1346 LogRel(("VRDPAUTH: Could not resolve import '%s'. Error code: %Vrc\n", "VRDPAuth", rc2));
1347 rc = rc2;
1348 }
1349
1350 if (mpfnAuthEntry2 || mpfnAuthEntry)
1351 {
1352 LogRel(("VRDPAUTH: Using entry point '%s'.\n", mpfnAuthEntry2? "VRDPAuth2": "VRDPAuth"));
1353 rc = VINF_SUCCESS;
1354 }
1355 }
1356
1357 if (VBOX_FAILURE (rc))
1358 {
1359 mConsole->reportAuthLibraryError (filename.raw(), rc);
1360
1361 mpfnAuthEntry = NULL;
1362 mpfnAuthEntry2 = NULL;
1363
1364 if (mAuthLibrary)
1365 {
1366 RTLdrClose(mAuthLibrary);
1367 mAuthLibrary = 0;
1368 }
1369
1370 return VRDPAuthAccessDenied;
1371 }
1372 }
1373
1374 Assert (mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2));
1375
1376 VRDPAuthResult result = mpfnAuthEntry2?
1377 mpfnAuthEntry2 (&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, true, u32ClientId):
1378 mpfnAuthEntry (&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain);
1379
1380 switch (result)
1381 {
1382 case VRDPAuthAccessDenied:
1383 LogRel(("VRDPAUTH: external authentication module returned 'access denied'\n"));
1384 break;
1385 case VRDPAuthAccessGranted:
1386 LogRel(("VRDPAUTH: external authentication module returned 'access granted'\n"));
1387 break;
1388 case VRDPAuthDelegateToGuest:
1389 LogRel(("VRDPAUTH: external authentication module returned 'delegate request to guest'\n"));
1390 break;
1391 default:
1392 LogRel(("VRDPAUTH: external authentication module returned incorrect return code %d\n", result));
1393 result = VRDPAuthAccessDenied;
1394 }
1395
1396 LogFlow(("ConsoleVRDPServer::Authenticate: result = %d\n", result));
1397
1398 return result;
1399}
1400
1401void ConsoleVRDPServer::AuthDisconnect (const Guid &uuid, uint32_t u32ClientId)
1402{
1403 VRDPAUTHUUID rawuuid;
1404
1405 memcpy (rawuuid, ((Guid &)uuid).ptr (), sizeof (rawuuid));
1406
1407 LogFlow(("ConsoleVRDPServer::AuthDisconnect: uuid = %Vuuid, u32ClientId = %d\n",
1408 rawuuid, u32ClientId));
1409
1410 Assert (mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2));
1411
1412 if (mpfnAuthEntry2)
1413 mpfnAuthEntry2 (&rawuuid, VRDPAuthGuestNotAsked, NULL, NULL, NULL, false, u32ClientId);
1414}
1415
1416int ConsoleVRDPServer::lockConsoleVRDPServer (void)
1417{
1418 int rc = RTCritSectEnter (&mCritSect);
1419 AssertRC (rc);
1420 return rc;
1421}
1422
1423void ConsoleVRDPServer::unlockConsoleVRDPServer (void)
1424{
1425 RTCritSectLeave (&mCritSect);
1426}
1427
1428DECLCALLBACK(int) ConsoleVRDPServer::ClipboardCallback (void *pvCallback,
1429 uint32_t u32ClientId,
1430 uint32_t u32Function,
1431 uint32_t u32Format,
1432 const void *pvData,
1433 uint32_t cbData)
1434{
1435 LogFlowFunc(("pvCallback = %p, u32ClientId = %d, u32Function = %d, u32Format = 0x%08X, pvData = %p, cbData = %d\n",
1436 pvCallback, u32ClientId, u32Function, u32Format, pvData, cbData));
1437
1438 int rc = VINF_SUCCESS;
1439
1440 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvCallback);
1441
1442 NOREF(u32ClientId);
1443
1444 switch (u32Function)
1445 {
1446 case VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE:
1447 {
1448 if (pServer->mpfnClipboardCallback)
1449 {
1450 pServer->mpfnClipboardCallback (VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE,
1451 u32Format,
1452 (void *)pvData,
1453 cbData);
1454 }
1455 } break;
1456
1457 case VRDP_CLIPBOARD_FUNCTION_DATA_READ:
1458 {
1459 if (pServer->mpfnClipboardCallback)
1460 {
1461 pServer->mpfnClipboardCallback (VBOX_CLIPBOARD_EXT_FN_DATA_READ,
1462 u32Format,
1463 (void *)pvData,
1464 cbData);
1465 }
1466 } break;
1467
1468 default:
1469 rc = VERR_NOT_SUPPORTED;
1470 }
1471
1472 return rc;
1473}
1474
1475DECLCALLBACK(int) ConsoleVRDPServer::ClipboardServiceExtension (void *pvExtension,
1476 uint32_t u32Function,
1477 void *pvParms,
1478 uint32_t cbParms)
1479{
1480 LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
1481 pvExtension, u32Function, pvParms, cbParms));
1482
1483 int rc = VINF_SUCCESS;
1484
1485#ifdef VBOX_VRDP
1486 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvExtension);
1487
1488 VBOXCLIPBOARDEXTPARMS *pParms = (VBOXCLIPBOARDEXTPARMS *)pvParms;
1489
1490 switch (u32Function)
1491 {
1492 case VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK:
1493 {
1494 pServer->mpfnClipboardCallback = (PFNVRDPCLIPBOARDEXTCALLBACK)pParms->pvData;
1495 } break;
1496
1497 case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
1498 {
1499 /* The guest announces clipboard formats. This must be delivered to all clients. */
1500 if (mpEntryPoints && pServer->mhServer)
1501 {
1502 mpEntryPoints->VRDPClipboard (pServer->mhServer,
1503 VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE,
1504 pParms->u32Format,
1505 NULL,
1506 0,
1507 NULL);
1508 }
1509 } break;
1510
1511 case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
1512 {
1513 /* The clipboard service expects that the pvData buffer will be filled
1514 * with clipboard data. The server returns the data from the client that
1515 * announced the requested format most recently.
1516 */
1517 if (mpEntryPoints && pServer->mhServer)
1518 {
1519 mpEntryPoints->VRDPClipboard (pServer->mhServer,
1520 VRDP_CLIPBOARD_FUNCTION_DATA_READ,
1521 pParms->u32Format,
1522 pParms->pvData,
1523 pParms->cbData,
1524 &pParms->cbData);
1525 }
1526 } break;
1527
1528 case VBOX_CLIPBOARD_EXT_FN_DATA_WRITE:
1529 {
1530 if (mpEntryPoints && pServer->mhServer)
1531 {
1532 mpEntryPoints->VRDPClipboard (pServer->mhServer,
1533 VRDP_CLIPBOARD_FUNCTION_DATA_WRITE,
1534 pParms->u32Format,
1535 pParms->pvData,
1536 pParms->cbData,
1537 NULL);
1538 }
1539 } break;
1540
1541 default:
1542 rc = VERR_NOT_SUPPORTED;
1543 }
1544#endif /* VBOX_VRDP */
1545
1546 return rc;
1547}
1548
1549void ConsoleVRDPServer::ClipboardCreate (uint32_t u32ClientId)
1550{
1551 int rc = lockConsoleVRDPServer ();
1552
1553 if (VBOX_SUCCESS (rc))
1554 {
1555 if (mcClipboardRefs == 0)
1556 {
1557 rc = HGCMHostRegisterServiceExtension (&mhClipboard, "VBoxSharedClipboard", ClipboardServiceExtension, this);
1558
1559 if (VBOX_SUCCESS (rc))
1560 {
1561 mcClipboardRefs++;
1562 }
1563 }
1564
1565 unlockConsoleVRDPServer ();
1566 }
1567}
1568
1569void ConsoleVRDPServer::ClipboardDelete (uint32_t u32ClientId)
1570{
1571 int rc = lockConsoleVRDPServer ();
1572
1573 if (VBOX_SUCCESS (rc))
1574 {
1575 mcClipboardRefs--;
1576
1577 if (mcClipboardRefs == 0)
1578 {
1579 HGCMHostUnregisterServiceExtension (mhClipboard);
1580 }
1581
1582 unlockConsoleVRDPServer ();
1583 }
1584}
1585
1586/* That is called on INPUT thread of the VRDP server.
1587 * The ConsoleVRDPServer keeps a list of created backend instances.
1588 */
1589void ConsoleVRDPServer::USBBackendCreate (uint32_t u32ClientId, void **ppvIntercept)
1590{
1591#ifdef VBOX_WITH_USB
1592 LogFlow(("ConsoleVRDPServer::USBBackendCreate: u32ClientId = %d\n", u32ClientId));
1593
1594 /* Create a new instance of the USB backend for the new client. */
1595 RemoteUSBBackend *pRemoteUSBBackend = new RemoteUSBBackend (mConsole, this, u32ClientId);
1596
1597 if (pRemoteUSBBackend)
1598 {
1599 pRemoteUSBBackend->AddRef (); /* 'Release' called in USBBackendDelete. */
1600
1601 /* Append the new instance in the list. */
1602 int rc = lockConsoleVRDPServer ();
1603
1604 if (VBOX_SUCCESS (rc))
1605 {
1606 pRemoteUSBBackend->pNext = mUSBBackends.pHead;
1607 if (mUSBBackends.pHead)
1608 {
1609 mUSBBackends.pHead->pPrev = pRemoteUSBBackend;
1610 }
1611 else
1612 {
1613 mUSBBackends.pTail = pRemoteUSBBackend;
1614 }
1615
1616 mUSBBackends.pHead = pRemoteUSBBackend;
1617
1618 unlockConsoleVRDPServer ();
1619
1620 if (ppvIntercept)
1621 {
1622 *ppvIntercept = pRemoteUSBBackend;
1623 }
1624 }
1625
1626 if (VBOX_FAILURE (rc))
1627 {
1628 pRemoteUSBBackend->Release ();
1629 }
1630 }
1631#endif /* VBOX_WITH_USB */
1632}
1633
1634void ConsoleVRDPServer::USBBackendDelete (uint32_t u32ClientId)
1635{
1636#ifdef VBOX_WITH_USB
1637 LogFlow(("ConsoleVRDPServer::USBBackendDelete: u32ClientId = %d\n", u32ClientId));
1638
1639 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1640
1641 /* Find the instance. */
1642 int rc = lockConsoleVRDPServer ();
1643
1644 if (VBOX_SUCCESS (rc))
1645 {
1646 pRemoteUSBBackend = usbBackendFind (u32ClientId);
1647
1648 if (pRemoteUSBBackend)
1649 {
1650 /* Notify that it will be deleted. */
1651 pRemoteUSBBackend->NotifyDelete ();
1652 }
1653
1654 unlockConsoleVRDPServer ();
1655 }
1656
1657 if (pRemoteUSBBackend)
1658 {
1659 /* Here the instance has been excluded from the list and can be dereferenced. */
1660 pRemoteUSBBackend->Release ();
1661 }
1662#endif
1663}
1664
1665void *ConsoleVRDPServer::USBBackendRequestPointer (uint32_t u32ClientId, const Guid *pGuid)
1666{
1667#ifdef VBOX_WITH_USB
1668 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1669
1670 /* Find the instance. */
1671 int rc = lockConsoleVRDPServer ();
1672
1673 if (VBOX_SUCCESS (rc))
1674 {
1675 pRemoteUSBBackend = usbBackendFind (u32ClientId);
1676
1677 if (pRemoteUSBBackend)
1678 {
1679 /* Inform the backend instance that it is referenced by the Guid. */
1680 bool fAdded = pRemoteUSBBackend->addUUID (pGuid);
1681
1682 if (fAdded)
1683 {
1684 /* Reference the instance because its pointer is being taken. */
1685 pRemoteUSBBackend->AddRef (); /* 'Release' is called in USBBackendReleasePointer. */
1686 }
1687 else
1688 {
1689 pRemoteUSBBackend = NULL;
1690 }
1691 }
1692
1693 unlockConsoleVRDPServer ();
1694 }
1695
1696 if (pRemoteUSBBackend)
1697 {
1698 return pRemoteUSBBackend->GetBackendCallbackPointer ();
1699 }
1700
1701#endif
1702 return NULL;
1703}
1704
1705void ConsoleVRDPServer::USBBackendReleasePointer (const Guid *pGuid)
1706{
1707#ifdef VBOX_WITH_USB
1708 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1709
1710 /* Find the instance. */
1711 int rc = lockConsoleVRDPServer ();
1712
1713 if (VBOX_SUCCESS (rc))
1714 {
1715 pRemoteUSBBackend = usbBackendFindByUUID (pGuid);
1716
1717 if (pRemoteUSBBackend)
1718 {
1719 pRemoteUSBBackend->removeUUID (pGuid);
1720 }
1721
1722 unlockConsoleVRDPServer ();
1723
1724 if (pRemoteUSBBackend)
1725 {
1726 pRemoteUSBBackend->Release ();
1727 }
1728 }
1729#endif
1730}
1731
1732RemoteUSBBackend *ConsoleVRDPServer::usbBackendGetNext (RemoteUSBBackend *pRemoteUSBBackend)
1733{
1734 LogFlow(("ConsoleVRDPServer::usbBackendGetNext: pBackend = %p\n", pRemoteUSBBackend));
1735
1736 RemoteUSBBackend *pNextRemoteUSBBackend = NULL;
1737#ifdef VBOX_WITH_USB
1738
1739 int rc = lockConsoleVRDPServer ();
1740
1741 if (VBOX_SUCCESS (rc))
1742 {
1743 if (pRemoteUSBBackend == NULL)
1744 {
1745 /* The first backend in the list is requested. */
1746 pNextRemoteUSBBackend = mUSBBackends.pHead;
1747 }
1748 else
1749 {
1750 /* Get pointer to the next backend. */
1751 pNextRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1752 }
1753
1754 if (pNextRemoteUSBBackend)
1755 {
1756 pNextRemoteUSBBackend->AddRef ();
1757 }
1758
1759 unlockConsoleVRDPServer ();
1760
1761 if (pRemoteUSBBackend)
1762 {
1763 pRemoteUSBBackend->Release ();
1764 }
1765 }
1766#endif
1767
1768 return pNextRemoteUSBBackend;
1769}
1770
1771#ifdef VBOX_WITH_USB
1772/* Internal method. Called under the ConsoleVRDPServerLock. */
1773RemoteUSBBackend *ConsoleVRDPServer::usbBackendFind (uint32_t u32ClientId)
1774{
1775 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
1776
1777 while (pRemoteUSBBackend)
1778 {
1779 if (pRemoteUSBBackend->ClientId () == u32ClientId)
1780 {
1781 break;
1782 }
1783
1784 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1785 }
1786
1787 return pRemoteUSBBackend;
1788}
1789
1790/* Internal method. Called under the ConsoleVRDPServerLock. */
1791RemoteUSBBackend *ConsoleVRDPServer::usbBackendFindByUUID (const Guid *pGuid)
1792{
1793 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
1794
1795 while (pRemoteUSBBackend)
1796 {
1797 if (pRemoteUSBBackend->findUUID (pGuid))
1798 {
1799 break;
1800 }
1801
1802 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1803 }
1804
1805 return pRemoteUSBBackend;
1806}
1807#endif
1808
1809/* Internal method. Called by the backend destructor. */
1810void ConsoleVRDPServer::usbBackendRemoveFromList (RemoteUSBBackend *pRemoteUSBBackend)
1811{
1812#ifdef VBOX_WITH_USB
1813 int rc = lockConsoleVRDPServer ();
1814 AssertRC (rc);
1815
1816 /* Exclude the found instance from the list. */
1817 if (pRemoteUSBBackend->pNext)
1818 {
1819 pRemoteUSBBackend->pNext->pPrev = pRemoteUSBBackend->pPrev;
1820 }
1821 else
1822 {
1823 mUSBBackends.pTail = (RemoteUSBBackend *)pRemoteUSBBackend->pPrev;
1824 }
1825
1826 if (pRemoteUSBBackend->pPrev)
1827 {
1828 pRemoteUSBBackend->pPrev->pNext = pRemoteUSBBackend->pNext;
1829 }
1830 else
1831 {
1832 mUSBBackends.pHead = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1833 }
1834
1835 pRemoteUSBBackend->pNext = pRemoteUSBBackend->pPrev = NULL;
1836
1837 unlockConsoleVRDPServer ();
1838#endif
1839}
1840
1841
1842void ConsoleVRDPServer::SendUpdate (unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate) const
1843{
1844#ifdef VBOX_VRDP
1845 if (mpEntryPoints && mhServer)
1846 {
1847 mpEntryPoints->VRDPUpdate (mhServer, uScreenId, pvUpdate, cbUpdate);
1848 }
1849#endif
1850}
1851
1852void ConsoleVRDPServer::SendResize (void) const
1853{
1854#ifdef VBOX_VRDP
1855 if (mpEntryPoints && mhServer)
1856 {
1857 mpEntryPoints->VRDPResize (mhServer);
1858 }
1859#endif
1860}
1861
1862void ConsoleVRDPServer::SendUpdateBitmap (unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h) const
1863{
1864#ifdef VBOX_VRDP
1865 VRDPORDERHDR update;
1866 update.x = x;
1867 update.y = y;
1868 update.w = w;
1869 update.h = h;
1870 if (mpEntryPoints && mhServer)
1871 {
1872 mpEntryPoints->VRDPUpdate (mhServer, uScreenId, &update, sizeof (update));
1873 }
1874#endif
1875}
1876
1877void ConsoleVRDPServer::SendAudioSamples (void *pvSamples, uint32_t cSamples, VRDPAUDIOFORMAT format) const
1878{
1879#ifdef VBOX_VRDP
1880 if (mpEntryPoints && mhServer)
1881 {
1882 mpEntryPoints->VRDPAudioSamples (mhServer, pvSamples, cSamples, format);
1883 }
1884#endif
1885}
1886
1887void ConsoleVRDPServer::SendAudioVolume (uint16_t left, uint16_t right) const
1888{
1889#ifdef VBOX_VRDP
1890 if (mpEntryPoints && mhServer)
1891 {
1892 mpEntryPoints->VRDPAudioVolume (mhServer, left, right);
1893 }
1894#endif
1895}
1896
1897void ConsoleVRDPServer::SendUSBRequest (uint32_t u32ClientId, void *pvParms, uint32_t cbParms) const
1898{
1899#ifdef VBOX_VRDP
1900 if (mpEntryPoints && mhServer)
1901 {
1902 mpEntryPoints->VRDPUSBRequest (mhServer, u32ClientId, pvParms, cbParms);
1903 }
1904#endif
1905}
1906
1907void ConsoleVRDPServer::QueryInfo (uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const
1908{
1909#ifdef VBOX_VRDP
1910 if (mpEntryPoints && mhServer)
1911 {
1912 mpEntryPoints->VRDPQueryInfo (mhServer, index, pvBuffer, cbBuffer, pcbOut);
1913 }
1914#endif
1915}
1916
1917#ifdef VBOX_VRDP
1918/* note: static function now! */
1919bool ConsoleVRDPServer::loadVRDPLibrary (void)
1920{
1921 int rc = VINF_SUCCESS;
1922
1923 if (!mVRDPLibrary)
1924 {
1925 rc = RTLdrLoad("VBoxVRDP", &mVRDPLibrary);
1926
1927 if (VBOX_SUCCESS(rc))
1928 {
1929 LogFlow(("VRDPServer::loadLibrary(): successfully loaded VRDP library.\n"));
1930
1931 struct SymbolEntry
1932 {
1933 const char *name;
1934 void **ppfn;
1935 };
1936
1937 #define DEFSYMENTRY(a) { #a, (void**)&mpfn##a }
1938
1939 static const struct SymbolEntry symbols[] =
1940 {
1941 DEFSYMENTRY(VRDPCreateServer)
1942 };
1943
1944 #undef DEFSYMENTRY
1945
1946 for (unsigned i = 0; i < ELEMENTS(symbols); i++)
1947 {
1948 rc = RTLdrGetSymbol(mVRDPLibrary, symbols[i].name, symbols[i].ppfn);
1949
1950 AssertMsgRC(rc, ("Error resolving VRDP symbol %s\n", symbols[i].name));
1951
1952 if (VBOX_FAILURE(rc))
1953 {
1954 break;
1955 }
1956 }
1957 }
1958 else
1959 {
1960 LogFlow(("VRDPServer::loadLibrary(): failed to load VRDP library! VRDP not available.\n"));
1961 mVRDPLibrary = NULL;
1962 }
1963 }
1964
1965 // just to be safe
1966 if (VBOX_FAILURE(rc))
1967 {
1968 if (mVRDPLibrary)
1969 {
1970 RTLdrClose (mVRDPLibrary);
1971 mVRDPLibrary = NULL;
1972 }
1973 }
1974
1975 return (mVRDPLibrary != NULL);
1976}
1977#endif /* VBOX_VRDP */
1978
1979/*
1980 * IRemoteDisplayInfo implementation.
1981 */
1982// constructor / destructor
1983/////////////////////////////////////////////////////////////////////////////
1984
1985HRESULT RemoteDisplayInfo::FinalConstruct()
1986{
1987 return S_OK;
1988}
1989
1990void RemoteDisplayInfo::FinalRelease()
1991{
1992 if (isReady())
1993 uninit ();
1994}
1995
1996// public methods only for internal purposes
1997/////////////////////////////////////////////////////////////////////////////
1998
1999/**
2000 * Initializes the guest object.
2001 */
2002HRESULT RemoteDisplayInfo::init (Console *aParent)
2003{
2004 LogFlowMember (("RemoteDisplayInfo::init (%p)\n", aParent));
2005
2006 ComAssertRet (aParent, E_INVALIDARG);
2007
2008 AutoLock alock (this);
2009 ComAssertRet (!isReady(), E_UNEXPECTED);
2010
2011 mParent = aParent;
2012
2013 setReady (true);
2014 return S_OK;
2015}
2016
2017/**
2018 * Uninitializes the instance and sets the ready flag to FALSE.
2019 * Called either from FinalRelease() or by the parent when it gets destroyed.
2020 */
2021void RemoteDisplayInfo::uninit()
2022{
2023 LogFlowMember (("RemoteDisplayInfo::uninit()\n"));
2024
2025 AutoLock alock (this);
2026 AssertReturn (isReady(), (void) 0);
2027
2028 mParent.setNull();
2029
2030 setReady (false);
2031}
2032
2033// IRemoteDisplayInfo properties
2034/////////////////////////////////////////////////////////////////////////////
2035
2036#define IMPL_GETTER_BOOL(_aType, _aName, _aIndex) \
2037 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
2038 { \
2039 if (!a##_aName) \
2040 return E_POINTER; \
2041 \
2042 AutoLock alock (this); \
2043 CHECK_READY(); \
2044 \
2045 uint32_t value; \
2046 uint32_t cbOut = 0; \
2047 \
2048 mParent->consoleVRDPServer ()->QueryInfo \
2049 (_aIndex, &value, sizeof (value), &cbOut); \
2050 \
2051 *a##_aName = cbOut? !!value: FALSE; \
2052 \
2053 return S_OK; \
2054 }
2055
2056#define IMPL_GETTER_SCALAR(_aType, _aName, _aIndex) \
2057 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
2058 { \
2059 if (!a##_aName) \
2060 return E_POINTER; \
2061 \
2062 AutoLock alock (this); \
2063 CHECK_READY(); \
2064 \
2065 _aType value; \
2066 uint32_t cbOut = 0; \
2067 \
2068 mParent->consoleVRDPServer ()->QueryInfo \
2069 (_aIndex, &value, sizeof (value), &cbOut); \
2070 \
2071 *a##_aName = cbOut? value: 0; \
2072 \
2073 return S_OK; \
2074 }
2075
2076#define IMPL_GETTER_BSTR(_aType, _aName, _aIndex) \
2077 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
2078 { \
2079 if (!a##_aName) \
2080 return E_POINTER; \
2081 \
2082 AutoLock alock (this); \
2083 CHECK_READY(); \
2084 \
2085 uint32_t cbOut = 0; \
2086 \
2087 mParent->consoleVRDPServer ()->QueryInfo \
2088 (_aIndex, NULL, 0, &cbOut); \
2089 \
2090 if (cbOut == 0) \
2091 { \
2092 Bstr str(""); \
2093 str.cloneTo (a##_aName); \
2094 return S_OK; \
2095 } \
2096 \
2097 char *pchBuffer = (char *)RTMemTmpAlloc (cbOut); \
2098 \
2099 if (!pchBuffer) \
2100 { \
2101 Log(("RemoteDisplayInfo::" \
2102 #_aName \
2103 ": Failed to allocate memory %d bytes\n", cbOut)); \
2104 return E_OUTOFMEMORY; \
2105 } \
2106 \
2107 mParent->consoleVRDPServer ()->QueryInfo \
2108 (_aIndex, pchBuffer, cbOut, &cbOut); \
2109 \
2110 Bstr str(pchBuffer); \
2111 \
2112 str.cloneTo (a##_aName); \
2113 \
2114 RTMemTmpFree (pchBuffer); \
2115 \
2116 return S_OK; \
2117 }
2118
2119IMPL_GETTER_BOOL (BOOL, Active, VRDP_QI_ACTIVE);
2120IMPL_GETTER_SCALAR (ULONG, NumberOfClients, VRDP_QI_NUMBER_OF_CLIENTS);
2121IMPL_GETTER_SCALAR (LONG64, BeginTime, VRDP_QI_BEGIN_TIME);
2122IMPL_GETTER_SCALAR (LONG64, EndTime, VRDP_QI_END_TIME);
2123IMPL_GETTER_SCALAR (ULONG64, BytesSent, VRDP_QI_BYTES_SENT);
2124IMPL_GETTER_SCALAR (ULONG64, BytesSentTotal, VRDP_QI_BYTES_SENT_TOTAL);
2125IMPL_GETTER_SCALAR (ULONG64, BytesReceived, VRDP_QI_BYTES_RECEIVED);
2126IMPL_GETTER_SCALAR (ULONG64, BytesReceivedTotal, VRDP_QI_BYTES_RECEIVED_TOTAL);
2127IMPL_GETTER_BSTR (BSTR, User, VRDP_QI_USER);
2128IMPL_GETTER_BSTR (BSTR, Domain, VRDP_QI_DOMAIN);
2129IMPL_GETTER_BSTR (BSTR, ClientName, VRDP_QI_CLIENT_NAME);
2130IMPL_GETTER_BSTR (BSTR, ClientIP, VRDP_QI_CLIENT_IP);
2131IMPL_GETTER_SCALAR (ULONG, ClientVersion, VRDP_QI_CLIENT_VERSION);
2132IMPL_GETTER_SCALAR (ULONG, EncryptionStyle, VRDP_QI_ENCRYPTION_STYLE);
2133
2134#undef IMPL_GETTER_BSTR
2135#undef IMPL_GETTER_SCALAR
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette