VirtualBox

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

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

must include iprt/alloca.h when using alloca.

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