VirtualBox

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

Last change on this file since 5611 was 5611, checked in by vboxsync, 18 years ago

Fixed querying netAddress property in VRDP server.

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

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