VirtualBox

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

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

Correctly process a NULL netAddress value.

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