VirtualBox

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

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

Implemented NumLock state synch over VRDP.

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