VirtualBox

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

Last change on this file since 34912 was 34906, checked in by vboxsync, 14 years ago

Initial audio filter implementation, which is used for audio input via remote desktop server.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 81.3 KB
Line 
1/* $Id: ConsoleVRDPServer.cpp 34906 2010-12-09 16:29:49Z vboxsync $ */
2/** @file
3 * VBox Console VRDP Helper class
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
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 (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "ConsoleVRDPServer.h"
19#include "ConsoleImpl.h"
20#include "DisplayImpl.h"
21#include "KeyboardImpl.h"
22#include "MouseImpl.h"
23#include "AudioSnifferInterface.h"
24#ifdef VBOX_WITH_EXTPACK
25# include "ExtPackManagerImpl.h"
26#endif
27
28#include "Global.h"
29#include "AutoCaller.h"
30#include "Logging.h"
31
32#include <iprt/asm.h>
33#include <iprt/alloca.h>
34#include <iprt/ldr.h>
35#include <iprt/param.h>
36#include <iprt/path.h>
37#include <iprt/cpp/utils.h>
38
39#include <VBox/err.h>
40#include <VBox/RemoteDesktop/VRDEOrders.h>
41#include <VBox/com/listeners.h>
42
43class VRDPConsoleListener
44{
45public:
46 VRDPConsoleListener(ConsoleVRDPServer *server)
47 : m_server(server)
48 {
49 }
50
51 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent * aEvent)
52 {
53 switch (aType)
54 {
55 case VBoxEventType_OnMousePointerShapeChanged:
56 {
57 ComPtr<IMousePointerShapeChangedEvent> mpscev = aEvent;
58 Assert(mpscev);
59 BOOL visible, alpha;
60 ULONG xHot, yHot, width, height;
61 com::SafeArray <BYTE> shape;
62
63 mpscev->COMGETTER(Visible)(&visible);
64 mpscev->COMGETTER(Alpha)(&alpha);
65 mpscev->COMGETTER(Xhot)(&xHot);
66 mpscev->COMGETTER(Yhot)(&yHot);
67 mpscev->COMGETTER(Width)(&width);
68 mpscev->COMGETTER(Height)(&height);
69 mpscev->COMGETTER(Shape)(ComSafeArrayAsOutParam(shape));
70
71 OnMousePointerShapeChange(visible, alpha, xHot, yHot, width, height, ComSafeArrayAsInParam(shape));
72 break;
73 }
74 case VBoxEventType_OnMouseCapabilityChanged:
75 {
76 ComPtr<IMouseCapabilityChangedEvent> mccev = aEvent;
77 Assert(mccev);
78 if (m_server)
79 {
80 BOOL fAbsoluteMouse;
81 mccev->COMGETTER(SupportsAbsolute)(&fAbsoluteMouse);
82 m_server->NotifyAbsoluteMouse(!!fAbsoluteMouse);
83 }
84 break;
85 }
86 case VBoxEventType_OnKeyboardLedsChanged:
87 {
88 ComPtr<IKeyboardLedsChangedEvent> klcev = aEvent;
89 Assert(klcev);
90
91 if (m_server)
92 {
93 BOOL fNumLock, fCapsLock, fScrollLock;
94 klcev->COMGETTER(NumLock)(&fNumLock);
95 klcev->COMGETTER(CapsLock)(&fCapsLock);
96 klcev->COMGETTER(ScrollLock)(&fScrollLock);
97 m_server->NotifyKeyboardLedsChange(fNumLock, fCapsLock, fScrollLock);
98 }
99 break;
100 }
101
102 default:
103 AssertFailed();
104 }
105
106 return S_OK;
107 }
108
109private:
110 STDMETHOD(OnMousePointerShapeChange)(BOOL visible, BOOL alpha, ULONG xHot, ULONG yHot,
111 ULONG width, ULONG height, ComSafeArrayIn(BYTE,shape));
112 ConsoleVRDPServer *m_server;
113};
114
115typedef ListenerImpl<VRDPConsoleListener, ConsoleVRDPServer*> VRDPConsoleListenerImpl;
116
117VBOX_LISTENER_DECLARE(VRDPConsoleListenerImpl)
118
119#ifdef DEBUG_sunlover
120#define LOGDUMPPTR Log
121void dumpPointer(const uint8_t *pu8Shape, uint32_t width, uint32_t height, bool fXorMaskRGB32)
122{
123 unsigned i;
124
125 const uint8_t *pu8And = pu8Shape;
126
127 for (i = 0; i < height; i++)
128 {
129 unsigned j;
130 LOGDUMPPTR(("%p: ", pu8And));
131 for (j = 0; j < (width + 7) / 8; j++)
132 {
133 unsigned k;
134 for (k = 0; k < 8; k++)
135 {
136 LOGDUMPPTR(("%d", ((*pu8And) & (1 << (7 - k)))? 1: 0));
137 }
138
139 pu8And++;
140 }
141 LOGDUMPPTR(("\n"));
142 }
143
144 if (fXorMaskRGB32)
145 {
146 uint32_t *pu32Xor = (uint32_t*)(pu8Shape + ((((width + 7) / 8) * height + 3) & ~3));
147
148 for (i = 0; i < height; i++)
149 {
150 unsigned j;
151 LOGDUMPPTR(("%p: ", pu32Xor));
152 for (j = 0; j < width; j++)
153 {
154 LOGDUMPPTR(("%08X", *pu32Xor++));
155 }
156 LOGDUMPPTR(("\n"));
157 }
158 }
159 else
160 {
161 /* RDP 24 bit RGB mask. */
162 uint8_t *pu8Xor = (uint8_t*)(pu8Shape + ((((width + 7) / 8) * height + 3) & ~3));
163 for (i = 0; i < height; i++)
164 {
165 unsigned j;
166 LOGDUMPPTR(("%p: ", pu8Xor));
167 for (j = 0; j < width; j++)
168 {
169 LOGDUMPPTR(("%02X%02X%02X", pu8Xor[2], pu8Xor[1], pu8Xor[0]));
170 pu8Xor += 3;
171 }
172 LOGDUMPPTR(("\n"));
173 }
174 }
175}
176#else
177#define dumpPointer(a, b, c, d) do {} while (0)
178#endif /* DEBUG_sunlover */
179
180static void findTopLeftBorder(const uint8_t *pu8AndMask, const uint8_t *pu8XorMask, uint32_t width, uint32_t height, uint32_t *pxSkip, uint32_t *pySkip)
181{
182 /*
183 * Find the top border of the AND mask. First assign to special value.
184 */
185 uint32_t ySkipAnd = ~0;
186
187 const uint8_t *pu8And = pu8AndMask;
188 const uint32_t cbAndRow = (width + 7) / 8;
189 const uint8_t maskLastByte = (uint8_t)( 0xFF << (cbAndRow * 8 - width) );
190
191 Assert(cbAndRow > 0);
192
193 unsigned y;
194 unsigned x;
195
196 for (y = 0; y < height && ySkipAnd == ~(uint32_t)0; y++, pu8And += cbAndRow)
197 {
198 /* For each complete byte in the row. */
199 for (x = 0; x < cbAndRow - 1; x++)
200 {
201 if (pu8And[x] != 0xFF)
202 {
203 ySkipAnd = y;
204 break;
205 }
206 }
207
208 if (ySkipAnd == ~(uint32_t)0)
209 {
210 /* Last byte. */
211 if ((pu8And[cbAndRow - 1] & maskLastByte) != maskLastByte)
212 {
213 ySkipAnd = y;
214 }
215 }
216 }
217
218 if (ySkipAnd == ~(uint32_t)0)
219 {
220 ySkipAnd = 0;
221 }
222
223 /*
224 * Find the left border of the AND mask.
225 */
226 uint32_t xSkipAnd = ~0;
227
228 /* For all bit columns. */
229 for (x = 0; x < width && xSkipAnd == ~(uint32_t)0; x++)
230 {
231 pu8And = pu8AndMask + x/8; /* Currently checking byte. */
232 uint8_t mask = 1 << (7 - x%8); /* Currently checking bit in the byte. */
233
234 for (y = ySkipAnd; y < height; y++, pu8And += cbAndRow)
235 {
236 if ((*pu8And & mask) == 0)
237 {
238 xSkipAnd = x;
239 break;
240 }
241 }
242 }
243
244 if (xSkipAnd == ~(uint32_t)0)
245 {
246 xSkipAnd = 0;
247 }
248
249 /*
250 * Find the XOR mask top border.
251 */
252 uint32_t ySkipXor = ~0;
253
254 uint32_t *pu32XorStart = (uint32_t *)pu8XorMask;
255
256 uint32_t *pu32Xor = pu32XorStart;
257
258 for (y = 0; y < height && ySkipXor == ~(uint32_t)0; y++, pu32Xor += width)
259 {
260 for (x = 0; x < width; x++)
261 {
262 if (pu32Xor[x] != 0)
263 {
264 ySkipXor = y;
265 break;
266 }
267 }
268 }
269
270 if (ySkipXor == ~(uint32_t)0)
271 {
272 ySkipXor = 0;
273 }
274
275 /*
276 * Find the left border of the XOR mask.
277 */
278 uint32_t xSkipXor = ~(uint32_t)0;
279
280 /* For all columns. */
281 for (x = 0; x < width && xSkipXor == ~(uint32_t)0; x++)
282 {
283 pu32Xor = pu32XorStart + x; /* Currently checking dword. */
284
285 for (y = ySkipXor; y < height; y++, pu32Xor += width)
286 {
287 if (*pu32Xor != 0)
288 {
289 xSkipXor = x;
290 break;
291 }
292 }
293 }
294
295 if (xSkipXor == ~(uint32_t)0)
296 {
297 xSkipXor = 0;
298 }
299
300 *pxSkip = RT_MIN(xSkipAnd, xSkipXor);
301 *pySkip = RT_MIN(ySkipAnd, ySkipXor);
302}
303
304/* Generate an AND mask for alpha pointers here, because
305 * guest driver does not do that correctly for Vista pointers.
306 * Similar fix, changing the alpha threshold, could be applied
307 * for the guest driver, but then additions reinstall would be
308 * necessary, which we try to avoid.
309 */
310static void mousePointerGenerateANDMask(uint8_t *pu8DstAndMask, int cbDstAndMask, const uint8_t *pu8SrcAlpha, int w, int h)
311{
312 memset(pu8DstAndMask, 0xFF, cbDstAndMask);
313
314 int y;
315 for (y = 0; y < h; y++)
316 {
317 uint8_t bitmask = 0x80;
318
319 int x;
320 for (x = 0; x < w; x++, bitmask >>= 1)
321 {
322 if (bitmask == 0)
323 {
324 bitmask = 0x80;
325 }
326
327 /* Whether alpha channel value is not transparent enough for the pixel to be seen. */
328 if (pu8SrcAlpha[x * 4 + 3] > 0x7f)
329 {
330 pu8DstAndMask[x / 8] &= ~bitmask;
331 }
332 }
333
334 /* Point to next source and dest scans. */
335 pu8SrcAlpha += w * 4;
336 pu8DstAndMask += (w + 7) / 8;
337 }
338}
339
340STDMETHODIMP VRDPConsoleListener::OnMousePointerShapeChange(BOOL visible,
341 BOOL alpha,
342 ULONG xHot,
343 ULONG yHot,
344 ULONG width,
345 ULONG height,
346 ComSafeArrayIn(BYTE,inShape))
347{
348 LogSunlover(("VRDPConsoleListener::OnMousePointerShapeChange: %d, %d, %lux%lu, @%lu,%lu\n", visible, alpha, width, height, xHot, yHot));
349
350 if (m_server)
351 {
352 com::SafeArray <BYTE> aShape(ComSafeArrayInArg(inShape));
353 if (aShape.size() == 0)
354 {
355 if (!visible)
356 {
357 m_server->MousePointerHide();
358 }
359 }
360 else if (width != 0 && height != 0)
361 {
362 /* Pointer consists of 1 bpp AND and 24 BPP XOR masks.
363 * 'shape' AND mask followed by XOR mask.
364 * XOR mask contains 32 bit (lsb)BGR0(msb) values.
365 *
366 * We convert this to RDP color format which consist of
367 * one bpp AND mask and 24 BPP (BGR) color XOR image.
368 *
369 * RDP clients expect 8 aligned width and height of
370 * pointer (preferably 32x32).
371 *
372 * They even contain bugs which do not appear for
373 * 32x32 pointers but would appear for a 41x32 one.
374 *
375 * So set pointer size to 32x32. This can be done safely
376 * because most pointers are 32x32.
377 */
378 uint8_t* shape = aShape.raw();
379
380 dumpPointer(shape, width, height, true);
381
382 int cbDstAndMask = (((width + 7) / 8) * height + 3) & ~3;
383
384 uint8_t *pu8AndMask = shape;
385 uint8_t *pu8XorMask = shape + cbDstAndMask;
386
387 if (alpha)
388 {
389 pu8AndMask = (uint8_t*)alloca(cbDstAndMask);
390
391 mousePointerGenerateANDMask(pu8AndMask, cbDstAndMask, pu8XorMask, width, height);
392 }
393
394 /* Windows guest alpha pointers are wider than 32 pixels.
395 * Try to find out the top-left border of the pointer and
396 * then copy only meaningful bits. All complete top rows
397 * and all complete left columns where (AND == 1 && XOR == 0)
398 * are skipped. Hot spot is adjusted.
399 */
400 uint32_t ySkip = 0; /* How many rows to skip at the top. */
401 uint32_t xSkip = 0; /* How many columns to skip at the left. */
402
403 findTopLeftBorder(pu8AndMask, pu8XorMask, width, height, &xSkip, &ySkip);
404
405 /* Must not skip the hot spot. */
406 xSkip = RT_MIN(xSkip, xHot);
407 ySkip = RT_MIN(ySkip, yHot);
408
409 /*
410 * Compute size and allocate memory for the pointer.
411 */
412 const uint32_t dstwidth = 32;
413 const uint32_t dstheight = 32;
414
415 VRDECOLORPOINTER *pointer = NULL;
416
417 uint32_t dstmaskwidth = (dstwidth + 7) / 8;
418
419 uint32_t rdpmaskwidth = dstmaskwidth;
420 uint32_t rdpmasklen = dstheight * rdpmaskwidth;
421
422 uint32_t rdpdatawidth = dstwidth * 3;
423 uint32_t rdpdatalen = dstheight * rdpdatawidth;
424
425 pointer = (VRDECOLORPOINTER *)RTMemTmpAlloc(sizeof(VRDECOLORPOINTER) + rdpmasklen + rdpdatalen);
426
427 if (pointer)
428 {
429 uint8_t *maskarray = (uint8_t*)pointer + sizeof(VRDECOLORPOINTER);
430 uint8_t *dataarray = maskarray + rdpmasklen;
431
432 memset(maskarray, 0xFF, rdpmasklen);
433 memset(dataarray, 0x00, rdpdatalen);
434
435 uint32_t srcmaskwidth = (width + 7) / 8;
436 uint32_t srcdatawidth = width * 4;
437
438 /* Copy AND mask. */
439 uint8_t *src = pu8AndMask + ySkip * srcmaskwidth;
440 uint8_t *dst = maskarray + (dstheight - 1) * rdpmaskwidth;
441
442 uint32_t minheight = RT_MIN(height - ySkip, dstheight);
443 uint32_t minwidth = RT_MIN(width - xSkip, dstwidth);
444
445 unsigned x, y;
446
447 for (y = 0; y < minheight; y++)
448 {
449 for (x = 0; x < minwidth; x++)
450 {
451 uint32_t byteIndex = (x + xSkip) / 8;
452 uint32_t bitIndex = (x + xSkip) % 8;
453
454 bool bit = (src[byteIndex] & (1 << (7 - bitIndex))) != 0;
455
456 if (!bit)
457 {
458 byteIndex = x / 8;
459 bitIndex = x % 8;
460
461 dst[byteIndex] &= ~(1 << (7 - bitIndex));
462 }
463 }
464
465 src += srcmaskwidth;
466 dst -= rdpmaskwidth;
467 }
468
469 /* Point src to XOR mask */
470 src = pu8XorMask + ySkip * srcdatawidth;
471 dst = dataarray + (dstheight - 1) * rdpdatawidth;
472
473 for (y = 0; y < minheight ; y++)
474 {
475 for (x = 0; x < minwidth; x++)
476 {
477 memcpy(dst + x * 3, &src[4 * (x + xSkip)], 3);
478 }
479
480 src += srcdatawidth;
481 dst -= rdpdatawidth;
482 }
483
484 pointer->u16HotX = (uint16_t)(xHot - xSkip);
485 pointer->u16HotY = (uint16_t)(yHot - ySkip);
486
487 pointer->u16Width = (uint16_t)dstwidth;
488 pointer->u16Height = (uint16_t)dstheight;
489
490 pointer->u16MaskLen = (uint16_t)rdpmasklen;
491 pointer->u16DataLen = (uint16_t)rdpdatalen;
492
493 dumpPointer((uint8_t*)pointer + sizeof(*pointer), dstwidth, dstheight, false);
494
495 m_server->MousePointerUpdate(pointer);
496
497 RTMemTmpFree(pointer);
498 }
499 }
500 }
501
502 return S_OK;
503}
504
505
506// ConsoleVRDPServer
507////////////////////////////////////////////////////////////////////////////////
508
509RTLDRMOD ConsoleVRDPServer::mVRDPLibrary = NIL_RTLDRMOD;
510
511PFNVRDECREATESERVER ConsoleVRDPServer::mpfnVRDECreateServer = NULL;
512
513VRDEENTRYPOINTS_3 ConsoleVRDPServer::mEntryPoints; /* A copy of the server entry points. */
514VRDEENTRYPOINTS_3 *ConsoleVRDPServer::mpEntryPoints = NULL;
515
516VRDECALLBACKS_3 ConsoleVRDPServer::mCallbacks =
517{
518 { VRDE_INTERFACE_VERSION_3, sizeof(VRDECALLBACKS_3) },
519 ConsoleVRDPServer::VRDPCallbackQueryProperty,
520 ConsoleVRDPServer::VRDPCallbackClientLogon,
521 ConsoleVRDPServer::VRDPCallbackClientConnect,
522 ConsoleVRDPServer::VRDPCallbackClientDisconnect,
523 ConsoleVRDPServer::VRDPCallbackIntercept,
524 ConsoleVRDPServer::VRDPCallbackUSB,
525 ConsoleVRDPServer::VRDPCallbackClipboard,
526 ConsoleVRDPServer::VRDPCallbackFramebufferQuery,
527 ConsoleVRDPServer::VRDPCallbackFramebufferLock,
528 ConsoleVRDPServer::VRDPCallbackFramebufferUnlock,
529 ConsoleVRDPServer::VRDPCallbackInput,
530 ConsoleVRDPServer::VRDPCallbackVideoModeHint,
531 ConsoleVRDPServer::VRDECallbackAudioIn
532};
533
534DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackQueryProperty(void *pvCallback, uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut)
535{
536 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
537
538 int rc = VERR_NOT_SUPPORTED;
539
540 switch (index)
541 {
542 case VRDE_QP_NETWORK_PORT:
543 {
544 /* This is obsolete, the VRDE server uses VRDE_QP_NETWORK_PORT_RANGE instead. */
545 ULONG port = 0;
546
547 if (cbBuffer >= sizeof(uint32_t))
548 {
549 *(uint32_t *)pvBuffer = (uint32_t)port;
550 rc = VINF_SUCCESS;
551 }
552 else
553 {
554 rc = VINF_BUFFER_OVERFLOW;
555 }
556
557 *pcbOut = sizeof(uint32_t);
558 } break;
559
560 case VRDE_QP_NETWORK_ADDRESS:
561 {
562 com::Bstr bstr;
563 server->mConsole->getVRDEServer()->GetVRDEProperty(Bstr("TCP/Address").raw(), bstr.asOutParam());
564
565 /* The server expects UTF8. */
566 com::Utf8Str address = bstr;
567
568 size_t cbAddress = address.length() + 1;
569
570 if (cbAddress >= 0x10000)
571 {
572 /* More than 64K seems to be an invalid address. */
573 rc = VERR_TOO_MUCH_DATA;
574 break;
575 }
576
577 if ((size_t)cbBuffer >= cbAddress)
578 {
579 memcpy(pvBuffer, address.c_str(), cbAddress);
580 rc = VINF_SUCCESS;
581 }
582 else
583 {
584 rc = VINF_BUFFER_OVERFLOW;
585 }
586
587 *pcbOut = (uint32_t)cbAddress;
588 } break;
589
590 case VRDE_QP_NUMBER_MONITORS:
591 {
592 ULONG cMonitors = 1;
593
594 server->mConsole->machine()->COMGETTER(MonitorCount)(&cMonitors);
595
596 if (cbBuffer >= sizeof(uint32_t))
597 {
598 *(uint32_t *)pvBuffer = (uint32_t)cMonitors;
599 rc = VINF_SUCCESS;
600 }
601 else
602 {
603 rc = VINF_BUFFER_OVERFLOW;
604 }
605
606 *pcbOut = sizeof(uint32_t);
607 } break;
608
609 case VRDE_QP_NETWORK_PORT_RANGE:
610 {
611 com::Bstr bstr;
612 HRESULT hrc = server->mConsole->getVRDEServer()->GetVRDEProperty(Bstr("TCP/Ports").raw(), bstr.asOutParam());
613
614 if (hrc != S_OK)
615 {
616 bstr = "";
617 }
618
619 if (bstr == "0")
620 {
621 bstr = "3389";
622 }
623
624 /* The server expects UTF8. */
625 com::Utf8Str portRange = bstr;
626
627 size_t cbPortRange = portRange.length() + 1;
628
629 if (cbPortRange >= 0x10000)
630 {
631 /* More than 64K seems to be an invalid port range string. */
632 rc = VERR_TOO_MUCH_DATA;
633 break;
634 }
635
636 if ((size_t)cbBuffer >= cbPortRange)
637 {
638 memcpy(pvBuffer, portRange.c_str(), cbPortRange);
639 rc = VINF_SUCCESS;
640 }
641 else
642 {
643 rc = VINF_BUFFER_OVERFLOW;
644 }
645
646 *pcbOut = (uint32_t)cbPortRange;
647 } break;
648
649#ifdef VBOX_WITH_VRDP_VIDEO_CHANNEL
650 case VRDE_QP_VIDEO_CHANNEL:
651 {
652 BOOL fVideoEnabled = FALSE;
653
654 server->mConsole->getVRDEServer()->COMGETTER(VideoChannel)(&fVideoEnabled);
655
656 if (cbBuffer >= sizeof(uint32_t))
657 {
658 *(uint32_t *)pvBuffer = (uint32_t)fVideoEnabled;
659 rc = VINF_SUCCESS;
660 }
661 else
662 {
663 rc = VINF_BUFFER_OVERFLOW;
664 }
665
666 *pcbOut = sizeof(uint32_t);
667 } break;
668
669 case VRDE_QP_VIDEO_CHANNEL_QUALITY:
670 {
671 ULONG ulQuality = 0;
672
673 server->mConsole->getVRDEServer()->COMGETTER(VideoChannelQuality)(&ulQuality);
674
675 if (cbBuffer >= sizeof(uint32_t))
676 {
677 *(uint32_t *)pvBuffer = (uint32_t)ulQuality;
678 rc = VINF_SUCCESS;
679 }
680 else
681 {
682 rc = VINF_BUFFER_OVERFLOW;
683 }
684
685 *pcbOut = sizeof(uint32_t);
686 } break;
687
688 case VRDE_QP_VIDEO_CHANNEL_SUNFLSH:
689 {
690 ULONG ulSunFlsh = 1;
691
692 com::Bstr bstr;
693 HRESULT hrc = server->mConsole->machine()->GetExtraData(Bstr("VRDP/SunFlsh").raw(),
694 bstr.asOutParam());
695 if (hrc == S_OK && !bstr.isEmpty())
696 {
697 com::Utf8Str sunFlsh = bstr;
698 if (!sunFlsh.isEmpty())
699 {
700 ulSunFlsh = sunFlsh.toUInt32();
701 }
702 }
703
704 if (cbBuffer >= sizeof(uint32_t))
705 {
706 *(uint32_t *)pvBuffer = (uint32_t)ulSunFlsh;
707 rc = VINF_SUCCESS;
708 }
709 else
710 {
711 rc = VINF_BUFFER_OVERFLOW;
712 }
713
714 *pcbOut = sizeof(uint32_t);
715 } break;
716#endif /* VBOX_WITH_VRDP_VIDEO_CHANNEL */
717
718 case VRDE_QP_FEATURE:
719 {
720 if (cbBuffer < sizeof(VRDEFEATURE))
721 {
722 rc = VERR_INVALID_PARAMETER;
723 break;
724 }
725
726 size_t cbInfo = cbBuffer - RT_OFFSETOF(VRDEFEATURE, achInfo);
727
728 VRDEFEATURE *pFeature = (VRDEFEATURE *)pvBuffer;
729
730 size_t cchInfo = 0;
731 rc = RTStrNLenEx(pFeature->achInfo, cbInfo, &cchInfo);
732
733 if (RT_FAILURE(rc))
734 {
735 rc = VERR_INVALID_PARAMETER;
736 break;
737 }
738
739 Log(("VRDE_QP_FEATURE [%s]\n", pFeature->achInfo));
740
741 com::Bstr bstrValue;
742
743 if ( RTStrICmp(pFeature->achInfo, "Client/DisableDisplay") == 0
744 || RTStrICmp(pFeature->achInfo, "Client/DisableInput") == 0
745 || RTStrICmp(pFeature->achInfo, "Client/DisableAudio") == 0
746 || RTStrICmp(pFeature->achInfo, "Client/DisableUSB") == 0
747 || RTStrICmp(pFeature->achInfo, "Client/DisableClipboard") == 0
748 )
749 {
750 /* @todo these features should be per client. */
751 NOREF(pFeature->u32ClientId);
752
753 /* These features are mapped to "VRDE/Feature/NAME" extra data. */
754 com::Utf8Str extraData("VRDE/Feature/");
755 extraData += pFeature->achInfo;
756
757 HRESULT hrc = server->mConsole->machine()->GetExtraData(com::Bstr(extraData).raw(),
758 bstrValue.asOutParam());
759 if (FAILED(hrc) || bstrValue.isEmpty())
760 {
761 /* Also try the old "VRDP/Feature/NAME" */
762 extraData = "VRDP/Feature/";
763 extraData += pFeature->achInfo;
764
765 hrc = server->mConsole->machine()->GetExtraData(com::Bstr(extraData).raw(),
766 bstrValue.asOutParam());
767 if (FAILED(hrc))
768 {
769 rc = VERR_NOT_SUPPORTED;
770 }
771 }
772 }
773 else if (RTStrNCmp(pFeature->achInfo, "Property/", 9) == 0)
774 {
775 /* Generic properties. */
776 const char *pszPropertyName = &pFeature->achInfo[9];
777 HRESULT hrc = server->mConsole->getVRDEServer()->GetVRDEProperty(Bstr(pszPropertyName).raw(), bstrValue.asOutParam());
778 if (FAILED(hrc))
779 {
780 rc = VERR_NOT_SUPPORTED;
781 }
782 }
783 else
784 {
785 rc = VERR_NOT_SUPPORTED;
786 }
787
788 /* Copy the value string to the callers buffer. */
789 if (rc == VINF_SUCCESS)
790 {
791 com::Utf8Str value = bstrValue;
792
793 size_t cb = value.length() + 1;
794
795 if ((size_t)cbInfo >= cb)
796 {
797 memcpy(pFeature->achInfo, value.c_str(), cb);
798 }
799 else
800 {
801 rc = VINF_BUFFER_OVERFLOW;
802 }
803
804 *pcbOut = (uint32_t)cb;
805 }
806 } break;
807
808 case VRDE_SP_NETWORK_BIND_PORT:
809 {
810 if (cbBuffer != sizeof(uint32_t))
811 {
812 rc = VERR_INVALID_PARAMETER;
813 break;
814 }
815
816 ULONG port = *(uint32_t *)pvBuffer;
817
818 server->mVRDPBindPort = port;
819
820 rc = VINF_SUCCESS;
821
822 if (pcbOut)
823 {
824 *pcbOut = sizeof(uint32_t);
825 }
826
827 server->mConsole->onVRDEServerInfoChange();
828 } break;
829
830 default:
831 break;
832 }
833
834 return rc;
835}
836
837DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClientLogon(void *pvCallback, uint32_t u32ClientId, const char *pszUser, const char *pszPassword, const char *pszDomain)
838{
839 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
840
841 return server->mConsole->VRDPClientLogon(u32ClientId, pszUser, pszPassword, pszDomain);
842}
843
844DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientConnect(void *pvCallback, uint32_t u32ClientId)
845{
846 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
847
848 server->mConsole->VRDPClientConnect(u32ClientId);
849}
850
851DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientDisconnect(void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercepted)
852{
853 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
854
855 server->mConsole->VRDPClientDisconnect(u32ClientId, fu32Intercepted);
856
857 if (ASMAtomicReadU32(&server->mu32AudioInputClientId) == u32ClientId)
858 {
859 Log(("AUDIOIN: disconnected client %u\n", u32ClientId));
860 ASMAtomicWriteU32(&server->mu32AudioInputClientId, 0);
861
862 PPDMIAUDIOSNIFFERPORT pPort = server->mConsole->getAudioSniffer()->getAudioSnifferPort();
863 if (pPort)
864 {
865 // @todo dynamic filter attach does not yet work pPort->pfnAudioInputIntercept(pPort, false);
866 }
867 else
868 {
869 AssertFailed();
870 }
871 }
872}
873
874DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackIntercept(void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercept, void **ppvIntercept)
875{
876 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
877
878 LogFlowFunc(("%x\n", fu32Intercept));
879
880 int rc = VERR_NOT_SUPPORTED;
881
882 switch (fu32Intercept)
883 {
884 case VRDE_CLIENT_INTERCEPT_AUDIO:
885 {
886 server->mConsole->VRDPInterceptAudio(u32ClientId);
887 if (ppvIntercept)
888 {
889 *ppvIntercept = server;
890 }
891 rc = VINF_SUCCESS;
892 } break;
893
894 case VRDE_CLIENT_INTERCEPT_USB:
895 {
896 server->mConsole->VRDPInterceptUSB(u32ClientId, ppvIntercept);
897 rc = VINF_SUCCESS;
898 } break;
899
900 case VRDE_CLIENT_INTERCEPT_CLIPBOARD:
901 {
902 server->mConsole->VRDPInterceptClipboard(u32ClientId);
903 if (ppvIntercept)
904 {
905 *ppvIntercept = server;
906 }
907 rc = VINF_SUCCESS;
908 } break;
909
910 case VRDE_CLIENT_INTERCEPT_AUDIO_INPUT:
911 {
912 /* This request is processed internally by the ConsoleVRDPServer.
913 * Only one client is allowed to intercept audio input.
914 */
915 if (ASMAtomicCmpXchgU32(&server->mu32AudioInputClientId, u32ClientId, 0) == true)
916 {
917 Log(("AUDIOIN: connected client %u\n", u32ClientId));
918
919 PPDMIAUDIOSNIFFERPORT pPort = server->mConsole->getAudioSniffer()->getAudioSnifferPort();
920 if (pPort)
921 {
922 // @todo dynamic filter attach does not yet work pPort->pfnAudioInputIntercept(pPort, true);
923 if (ppvIntercept)
924 {
925 *ppvIntercept = server;
926 }
927 }
928 else
929 {
930 AssertFailed();
931 ASMAtomicWriteU32(&server->mu32AudioInputClientId, 0);
932 rc = VERR_NOT_SUPPORTED;
933 }
934 }
935 else
936 {
937 Log(("AUDIOIN: ignored client %u, active client %u\n", u32ClientId, server->mu32AudioInputClientId));
938 rc = VERR_NOT_SUPPORTED;
939 }
940 } break;
941
942 default:
943 break;
944 }
945
946 return rc;
947}
948
949DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackUSB(void *pvCallback, void *pvIntercept, uint32_t u32ClientId, uint8_t u8Code, const void *pvRet, uint32_t cbRet)
950{
951#ifdef VBOX_WITH_USB
952 return USBClientResponseCallback(pvIntercept, u32ClientId, u8Code, pvRet, cbRet);
953#else
954 return VERR_NOT_SUPPORTED;
955#endif
956}
957
958DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClipboard(void *pvCallback, void *pvIntercept, uint32_t u32ClientId, uint32_t u32Function, uint32_t u32Format, const void *pvData, uint32_t cbData)
959{
960 return ClipboardCallback(pvIntercept, u32ClientId, u32Function, u32Format, pvData, cbData);
961}
962
963DECLCALLBACK(bool) ConsoleVRDPServer::VRDPCallbackFramebufferQuery(void *pvCallback, unsigned uScreenId, VRDEFRAMEBUFFERINFO *pInfo)
964{
965 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
966
967 bool fAvailable = false;
968
969 IFramebuffer *pfb = NULL;
970 LONG xOrigin = 0;
971 LONG yOrigin = 0;
972
973 server->mConsole->getDisplay()->GetFramebuffer(uScreenId, &pfb, &xOrigin, &yOrigin);
974
975 if (pfb)
976 {
977 pfb->Lock ();
978
979 /* Query framebuffer parameters. */
980 ULONG lineSize = 0;
981 pfb->COMGETTER(BytesPerLine)(&lineSize);
982
983 ULONG bitsPerPixel = 0;
984 pfb->COMGETTER(BitsPerPixel)(&bitsPerPixel);
985
986 BYTE *address = NULL;
987 pfb->COMGETTER(Address)(&address);
988
989 ULONG height = 0;
990 pfb->COMGETTER(Height)(&height);
991
992 ULONG width = 0;
993 pfb->COMGETTER(Width)(&width);
994
995 /* Now fill the information as requested by the caller. */
996 pInfo->pu8Bits = address;
997 pInfo->xOrigin = xOrigin;
998 pInfo->yOrigin = yOrigin;
999 pInfo->cWidth = width;
1000 pInfo->cHeight = height;
1001 pInfo->cBitsPerPixel = bitsPerPixel;
1002 pInfo->cbLine = lineSize;
1003
1004 pfb->Unlock();
1005
1006 fAvailable = true;
1007 }
1008
1009 if (server->maFramebuffers[uScreenId])
1010 {
1011 server->maFramebuffers[uScreenId]->Release();
1012 }
1013 server->maFramebuffers[uScreenId] = pfb;
1014
1015 return fAvailable;
1016}
1017
1018DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferLock(void *pvCallback, unsigned uScreenId)
1019{
1020 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1021
1022 if (server->maFramebuffers[uScreenId])
1023 {
1024 server->maFramebuffers[uScreenId]->Lock();
1025 }
1026}
1027
1028DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferUnlock(void *pvCallback, unsigned uScreenId)
1029{
1030 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1031
1032 if (server->maFramebuffers[uScreenId])
1033 {
1034 server->maFramebuffers[uScreenId]->Unlock();
1035 }
1036}
1037
1038static void fixKbdLockStatus(VRDPInputSynch *pInputSynch, IKeyboard *pKeyboard)
1039{
1040 if ( pInputSynch->cGuestNumLockAdaptions
1041 && (pInputSynch->fGuestNumLock != pInputSynch->fClientNumLock))
1042 {
1043 pInputSynch->cGuestNumLockAdaptions--;
1044 pKeyboard->PutScancode(0x45);
1045 pKeyboard->PutScancode(0x45 | 0x80);
1046 }
1047 if ( pInputSynch->cGuestCapsLockAdaptions
1048 && (pInputSynch->fGuestCapsLock != pInputSynch->fClientCapsLock))
1049 {
1050 pInputSynch->cGuestCapsLockAdaptions--;
1051 pKeyboard->PutScancode(0x3a);
1052 pKeyboard->PutScancode(0x3a | 0x80);
1053 }
1054}
1055
1056DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackInput(void *pvCallback, int type, const void *pvInput, unsigned cbInput)
1057{
1058 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1059 Console *pConsole = server->mConsole;
1060
1061 switch (type)
1062 {
1063 case VRDE_INPUT_SCANCODE:
1064 {
1065 if (cbInput == sizeof(VRDEINPUTSCANCODE))
1066 {
1067 IKeyboard *pKeyboard = pConsole->getKeyboard();
1068
1069 const VRDEINPUTSCANCODE *pInputScancode = (VRDEINPUTSCANCODE *)pvInput;
1070
1071 /* Track lock keys. */
1072 if (pInputScancode->uScancode == 0x45)
1073 {
1074 server->m_InputSynch.fClientNumLock = !server->m_InputSynch.fClientNumLock;
1075 }
1076 else if (pInputScancode->uScancode == 0x3a)
1077 {
1078 server->m_InputSynch.fClientCapsLock = !server->m_InputSynch.fClientCapsLock;
1079 }
1080 else if (pInputScancode->uScancode == 0x46)
1081 {
1082 server->m_InputSynch.fClientScrollLock = !server->m_InputSynch.fClientScrollLock;
1083 }
1084 else if ((pInputScancode->uScancode & 0x80) == 0)
1085 {
1086 /* Key pressed. */
1087 fixKbdLockStatus(&server->m_InputSynch, pKeyboard);
1088 }
1089
1090 pKeyboard->PutScancode((LONG)pInputScancode->uScancode);
1091 }
1092 } break;
1093
1094 case VRDE_INPUT_POINT:
1095 {
1096 if (cbInput == sizeof(VRDEINPUTPOINT))
1097 {
1098 const VRDEINPUTPOINT *pInputPoint = (VRDEINPUTPOINT *)pvInput;
1099
1100 int mouseButtons = 0;
1101 int iWheel = 0;
1102
1103 if (pInputPoint->uButtons & VRDE_INPUT_POINT_BUTTON1)
1104 {
1105 mouseButtons |= MouseButtonState_LeftButton;
1106 }
1107 if (pInputPoint->uButtons & VRDE_INPUT_POINT_BUTTON2)
1108 {
1109 mouseButtons |= MouseButtonState_RightButton;
1110 }
1111 if (pInputPoint->uButtons & VRDE_INPUT_POINT_BUTTON3)
1112 {
1113 mouseButtons |= MouseButtonState_MiddleButton;
1114 }
1115 if (pInputPoint->uButtons & VRDE_INPUT_POINT_WHEEL_UP)
1116 {
1117 mouseButtons |= MouseButtonState_WheelUp;
1118 iWheel = -1;
1119 }
1120 if (pInputPoint->uButtons & VRDE_INPUT_POINT_WHEEL_DOWN)
1121 {
1122 mouseButtons |= MouseButtonState_WheelDown;
1123 iWheel = 1;
1124 }
1125
1126 if (server->m_fGuestWantsAbsolute)
1127 {
1128 pConsole->getMouse()->PutMouseEventAbsolute(pInputPoint->x + 1, pInputPoint->y + 1, iWheel, 0 /* Horizontal wheel */, mouseButtons);
1129 } else
1130 {
1131 pConsole->getMouse()->PutMouseEvent(pInputPoint->x - server->m_mousex,
1132 pInputPoint->y - server->m_mousey,
1133 iWheel, 0 /* Horizontal wheel */, mouseButtons);
1134 server->m_mousex = pInputPoint->x;
1135 server->m_mousey = pInputPoint->y;
1136 }
1137 }
1138 } break;
1139
1140 case VRDE_INPUT_CAD:
1141 {
1142 pConsole->getKeyboard()->PutCAD();
1143 } break;
1144
1145 case VRDE_INPUT_RESET:
1146 {
1147 pConsole->Reset();
1148 } break;
1149
1150 case VRDE_INPUT_SYNCH:
1151 {
1152 if (cbInput == sizeof(VRDEINPUTSYNCH))
1153 {
1154 IKeyboard *pKeyboard = pConsole->getKeyboard();
1155
1156 const VRDEINPUTSYNCH *pInputSynch = (VRDEINPUTSYNCH *)pvInput;
1157
1158 server->m_InputSynch.fClientNumLock = (pInputSynch->uLockStatus & VRDE_INPUT_SYNCH_NUMLOCK) != 0;
1159 server->m_InputSynch.fClientCapsLock = (pInputSynch->uLockStatus & VRDE_INPUT_SYNCH_CAPITAL) != 0;
1160 server->m_InputSynch.fClientScrollLock = (pInputSynch->uLockStatus & VRDE_INPUT_SYNCH_SCROLL) != 0;
1161
1162 /* The client initiated synchronization. Always make the guest to reflect the client state.
1163 * Than means, when the guest changes the state itself, it is forced to return to the client
1164 * state.
1165 */
1166 if (server->m_InputSynch.fClientNumLock != server->m_InputSynch.fGuestNumLock)
1167 {
1168 server->m_InputSynch.cGuestNumLockAdaptions = 2;
1169 }
1170
1171 if (server->m_InputSynch.fClientCapsLock != server->m_InputSynch.fGuestCapsLock)
1172 {
1173 server->m_InputSynch.cGuestCapsLockAdaptions = 2;
1174 }
1175
1176 fixKbdLockStatus(&server->m_InputSynch, pKeyboard);
1177 }
1178 } break;
1179
1180 default:
1181 break;
1182 }
1183}
1184
1185DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackVideoModeHint(void *pvCallback, unsigned cWidth, unsigned cHeight, unsigned cBitsPerPixel, unsigned uScreenId)
1186{
1187 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1188
1189 server->mConsole->getDisplay()->SetVideoModeHint(cWidth, cHeight, cBitsPerPixel, uScreenId);
1190}
1191
1192DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackAudioIn(void *pvCallback,
1193 void *pvCtx,
1194 uint32_t u32ClientId,
1195 uint32_t u32Event,
1196 const void *pvData,
1197 uint32_t cbData)
1198{
1199 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1200
1201 PPDMIAUDIOSNIFFERPORT pPort = server->mConsole->getAudioSniffer()->getAudioSnifferPort();
1202
1203 switch (u32Event)
1204 {
1205 case VRDE_AUDIOIN_BEGIN:
1206 {
1207 const VRDEAUDIOINBEGIN *pParms = (const VRDEAUDIOINBEGIN *)pvData;
1208
1209 pPort->pfnAudioInputEventBegin (pPort, pvCtx,
1210 VRDE_AUDIO_FMT_SAMPLE_FREQ(pParms->fmt),
1211 VRDE_AUDIO_FMT_CHANNELS(pParms->fmt),
1212 VRDE_AUDIO_FMT_BITS_PER_SAMPLE(pParms->fmt),
1213 VRDE_AUDIO_FMT_SIGNED(pParms->fmt)
1214 );
1215 } break;
1216
1217 case VRDE_AUDIOIN_DATA:
1218 {
1219 pPort->pfnAudioInputEventData (pPort, pvCtx, pvData, cbData);
1220 } break;
1221
1222 case VRDE_AUDIOIN_END:
1223 {
1224 pPort->pfnAudioInputEventEnd (pPort, pvCtx);
1225 } break;
1226
1227 default:
1228 return;
1229 }
1230}
1231
1232
1233ConsoleVRDPServer::ConsoleVRDPServer(Console *console)
1234{
1235 mConsole = console;
1236
1237 int rc = RTCritSectInit(&mCritSect);
1238 AssertRC(rc);
1239
1240 mcClipboardRefs = 0;
1241 mpfnClipboardCallback = NULL;
1242
1243#ifdef VBOX_WITH_USB
1244 mUSBBackends.pHead = NULL;
1245 mUSBBackends.pTail = NULL;
1246
1247 mUSBBackends.thread = NIL_RTTHREAD;
1248 mUSBBackends.fThreadRunning = false;
1249 mUSBBackends.event = 0;
1250#endif
1251
1252 mhServer = 0;
1253 mServerInterfaceVersion = 0;
1254
1255 m_fGuestWantsAbsolute = false;
1256 m_mousex = 0;
1257 m_mousey = 0;
1258
1259 m_InputSynch.cGuestNumLockAdaptions = 2;
1260 m_InputSynch.cGuestCapsLockAdaptions = 2;
1261
1262 m_InputSynch.fGuestNumLock = false;
1263 m_InputSynch.fGuestCapsLock = false;
1264 m_InputSynch.fGuestScrollLock = false;
1265
1266 m_InputSynch.fClientNumLock = false;
1267 m_InputSynch.fClientCapsLock = false;
1268 m_InputSynch.fClientScrollLock = false;
1269
1270 memset(maFramebuffers, 0, sizeof(maFramebuffers));
1271
1272 {
1273 ComPtr<IEventSource> es;
1274 console->COMGETTER(EventSource)(es.asOutParam());
1275 mConsoleListener = new VRDPConsoleListenerImpl(this);
1276 com::SafeArray <VBoxEventType_T> eventTypes;
1277 eventTypes.push_back(VBoxEventType_OnMousePointerShapeChanged);
1278 eventTypes.push_back(VBoxEventType_OnMouseCapabilityChanged);
1279 eventTypes.push_back(VBoxEventType_OnKeyboardLedsChanged);
1280 es->RegisterListener(mConsoleListener, ComSafeArrayAsInParam(eventTypes), true);
1281 }
1282
1283 mVRDPBindPort = -1;
1284
1285 mAuthLibrary = 0;
1286
1287 mu32AudioInputClientId = 0;
1288}
1289
1290ConsoleVRDPServer::~ConsoleVRDPServer()
1291{
1292 Stop();
1293
1294 if (mConsoleListener)
1295 {
1296 ComPtr<IEventSource> es;
1297 mConsole->COMGETTER(EventSource)(es.asOutParam());
1298 es->UnregisterListener(mConsoleListener);
1299 mConsoleListener->Release();
1300 mConsoleListener = NULL;
1301 }
1302
1303 unsigned i;
1304 for (i = 0; i < RT_ELEMENTS(maFramebuffers); i++)
1305 {
1306 if (maFramebuffers[i])
1307 {
1308 maFramebuffers[i]->Release();
1309 maFramebuffers[i] = NULL;
1310 }
1311 }
1312
1313 if (RTCritSectIsInitialized(&mCritSect))
1314 {
1315 RTCritSectDelete(&mCritSect);
1316 memset(&mCritSect, 0, sizeof(mCritSect));
1317 }
1318}
1319
1320int ConsoleVRDPServer::Launch(void)
1321{
1322 LogFlowThisFunc(("\n"));
1323
1324 IVRDEServer *server = mConsole->getVRDEServer();
1325 AssertReturn(server, VERR_INTERNAL_ERROR_2);
1326
1327 /*
1328 * Check if VRDE is enabled.
1329 */
1330 BOOL fEnabled;
1331 HRESULT hrc = server->COMGETTER(Enabled)(&fEnabled);
1332 AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));
1333 if (!fEnabled)
1334 return VINF_SUCCESS;
1335
1336 /*
1337 * Check that a VRDE extension pack name is set and resolve it into a
1338 * library path.
1339 */
1340 Bstr bstrExtPack;
1341 hrc = server->COMGETTER(VRDEExtPack)(bstrExtPack.asOutParam());
1342 if (FAILED(hrc))
1343 return Global::vboxStatusCodeFromCOM(hrc);
1344 if (bstrExtPack.isEmpty())
1345 return VINF_NOT_SUPPORTED;
1346
1347 Utf8Str strExtPack(bstrExtPack);
1348 Utf8Str strVrdeLibrary;
1349 int vrc = VINF_SUCCESS;
1350 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
1351 strVrdeLibrary = "VBoxVRDP";
1352 else
1353 {
1354#ifdef VBOX_WITH_EXTPACK
1355 ExtPackManager *pExtPackMgr = mConsole->getExtPackManager();
1356 vrc = pExtPackMgr->getVrdeLibraryPathForExtPack(&strExtPack, &strVrdeLibrary);
1357#else
1358 vrc = VERR_FILE_NOT_FOUND;
1359#endif
1360 }
1361 if (RT_SUCCESS(vrc))
1362 {
1363 /*
1364 * Load the VRDE library and start the server, if it is enabled.
1365 */
1366 vrc = loadVRDPLibrary(strVrdeLibrary.c_str());
1367 if (RT_SUCCESS(vrc))
1368 {
1369 VRDEENTRYPOINTS_3 *pEntryPoints3;
1370 vrc = mpfnVRDECreateServer(&mCallbacks.header, this, (VRDEINTERFACEHDR **)&pEntryPoints3, &mhServer);
1371
1372 if (RT_SUCCESS(vrc))
1373 {
1374 mServerInterfaceVersion = 3;
1375 mEntryPoints = *pEntryPoints3;
1376 mpEntryPoints = &mEntryPoints;
1377 }
1378 else if (vrc == VERR_VERSION_MISMATCH)
1379 {
1380 /* An older version of VRDE is installed, try version 1. */
1381 VRDEENTRYPOINTS_1 *pEntryPoints1;
1382
1383 VRDECALLBACKS_1 callbacks =
1384 {
1385 { VRDE_INTERFACE_VERSION_1, sizeof(VRDECALLBACKS_1) },
1386 ConsoleVRDPServer::VRDPCallbackQueryProperty,
1387 ConsoleVRDPServer::VRDPCallbackClientLogon,
1388 ConsoleVRDPServer::VRDPCallbackClientConnect,
1389 ConsoleVRDPServer::VRDPCallbackClientDisconnect,
1390 ConsoleVRDPServer::VRDPCallbackIntercept,
1391 ConsoleVRDPServer::VRDPCallbackUSB,
1392 ConsoleVRDPServer::VRDPCallbackClipboard,
1393 ConsoleVRDPServer::VRDPCallbackFramebufferQuery,
1394 ConsoleVRDPServer::VRDPCallbackFramebufferLock,
1395 ConsoleVRDPServer::VRDPCallbackFramebufferUnlock,
1396 ConsoleVRDPServer::VRDPCallbackInput,
1397 ConsoleVRDPServer::VRDPCallbackVideoModeHint
1398 };
1399
1400 vrc = mpfnVRDECreateServer(&callbacks.header, this, (VRDEINTERFACEHDR **)&pEntryPoints1, &mhServer);
1401 if (RT_SUCCESS(vrc))
1402 {
1403 LogRel(("VRDE: loaded an older version of the server.\n"));
1404
1405 mServerInterfaceVersion = 3;
1406 mEntryPoints.header = pEntryPoints1->header;
1407 mEntryPoints.VRDEDestroy = pEntryPoints1->VRDEDestroy;
1408 mEntryPoints.VRDEEnableConnections = pEntryPoints1->VRDEEnableConnections;
1409 mEntryPoints.VRDEDisconnect = pEntryPoints1->VRDEDisconnect;
1410 mEntryPoints.VRDEResize = pEntryPoints1->VRDEResize;
1411 mEntryPoints.VRDEUpdate = pEntryPoints1->VRDEUpdate;
1412 mEntryPoints.VRDEColorPointer = pEntryPoints1->VRDEColorPointer;
1413 mEntryPoints.VRDEHidePointer = pEntryPoints1->VRDEHidePointer;
1414 mEntryPoints.VRDEAudioSamples = pEntryPoints1->VRDEAudioSamples;
1415 mEntryPoints.VRDEAudioVolume = pEntryPoints1->VRDEAudioVolume;
1416 mEntryPoints.VRDEUSBRequest = pEntryPoints1->VRDEUSBRequest;
1417 mEntryPoints.VRDEClipboard = pEntryPoints1->VRDEClipboard;
1418 mEntryPoints.VRDEQueryInfo = pEntryPoints1->VRDEQueryInfo;
1419 mEntryPoints.VRDERedirect = NULL;
1420 mEntryPoints.VRDEAudioInOpen = NULL;
1421 mEntryPoints.VRDEAudioInClose = NULL;
1422 mpEntryPoints = &mEntryPoints;
1423 }
1424 }
1425
1426 if (RT_SUCCESS(vrc))
1427 {
1428#ifdef VBOX_WITH_USB
1429 remoteUSBThreadStart();
1430#endif
1431 }
1432 else
1433 {
1434 if (vrc != VERR_NET_ADDRESS_IN_USE)
1435 LogRel(("VRDE: Could not start the server rc = %Rrc\n", vrc));
1436 /* Don't unload the lib, because it prevents us trying again or
1437 because there may be other users? */
1438 }
1439 }
1440 }
1441
1442 return vrc;
1443}
1444
1445void ConsoleVRDPServer::EnableConnections(void)
1446{
1447 if (mpEntryPoints && mhServer)
1448 {
1449 mpEntryPoints->VRDEEnableConnections(mhServer, true);
1450 }
1451}
1452
1453void ConsoleVRDPServer::DisconnectClient(uint32_t u32ClientId, bool fReconnect)
1454{
1455 if (mpEntryPoints && mhServer)
1456 {
1457 mpEntryPoints->VRDEDisconnect(mhServer, u32ClientId, fReconnect);
1458 }
1459}
1460
1461void ConsoleVRDPServer::MousePointerUpdate(const VRDECOLORPOINTER *pPointer)
1462{
1463 if (mpEntryPoints && mhServer)
1464 {
1465 mpEntryPoints->VRDEColorPointer(mhServer, pPointer);
1466 }
1467}
1468
1469void ConsoleVRDPServer::MousePointerHide(void)
1470{
1471 if (mpEntryPoints && mhServer)
1472 {
1473 mpEntryPoints->VRDEHidePointer(mhServer);
1474 }
1475}
1476
1477void ConsoleVRDPServer::Stop(void)
1478{
1479 Assert(VALID_PTR(this)); /** @todo r=bird: there are(/was) some odd cases where this buster was invalid on
1480 * linux. Just remove this when it's 100% sure that problem has been fixed. */
1481 if (mhServer)
1482 {
1483 HVRDESERVER hServer = mhServer;
1484
1485 /* Reset the handle to avoid further calls to the server. */
1486 mhServer = 0;
1487
1488 if (mpEntryPoints && hServer)
1489 {
1490 mpEntryPoints->VRDEDestroy(hServer);
1491 }
1492 }
1493
1494#ifdef VBOX_WITH_USB
1495 remoteUSBThreadStop();
1496#endif /* VBOX_WITH_USB */
1497
1498 mpfnAuthEntry = NULL;
1499 mpfnAuthEntry2 = NULL;
1500 mpfnAuthEntry3 = NULL;
1501
1502 if (mAuthLibrary)
1503 {
1504 RTLdrClose(mAuthLibrary);
1505 mAuthLibrary = 0;
1506 }
1507}
1508
1509/* Worker thread for Remote USB. The thread polls the clients for
1510 * the list of attached USB devices.
1511 * The thread is also responsible for attaching/detaching devices
1512 * to/from the VM.
1513 *
1514 * It is expected that attaching/detaching is not a frequent operation.
1515 *
1516 * The thread is always running when the VRDP server is active.
1517 *
1518 * The thread scans backends and requests the device list every 2 seconds.
1519 *
1520 * When device list is available, the thread calls the Console to process it.
1521 *
1522 */
1523#define VRDP_DEVICE_LIST_PERIOD_MS (2000)
1524
1525#ifdef VBOX_WITH_USB
1526static DECLCALLBACK(int) threadRemoteUSB(RTTHREAD self, void *pvUser)
1527{
1528 ConsoleVRDPServer *pOwner = (ConsoleVRDPServer *)pvUser;
1529
1530 LogFlow(("Console::threadRemoteUSB: start. owner = %p.\n", pOwner));
1531
1532 pOwner->notifyRemoteUSBThreadRunning(self);
1533
1534 while (pOwner->isRemoteUSBThreadRunning())
1535 {
1536 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1537
1538 while ((pRemoteUSBBackend = pOwner->usbBackendGetNext(pRemoteUSBBackend)) != NULL)
1539 {
1540 pRemoteUSBBackend->PollRemoteDevices();
1541 }
1542
1543 pOwner->waitRemoteUSBThreadEvent(VRDP_DEVICE_LIST_PERIOD_MS);
1544
1545 LogFlow(("Console::threadRemoteUSB: iteration. owner = %p.\n", pOwner));
1546 }
1547
1548 return VINF_SUCCESS;
1549}
1550
1551void ConsoleVRDPServer::notifyRemoteUSBThreadRunning(RTTHREAD thread)
1552{
1553 mUSBBackends.thread = thread;
1554 mUSBBackends.fThreadRunning = true;
1555 int rc = RTThreadUserSignal(thread);
1556 AssertRC(rc);
1557}
1558
1559bool ConsoleVRDPServer::isRemoteUSBThreadRunning(void)
1560{
1561 return mUSBBackends.fThreadRunning;
1562}
1563
1564void ConsoleVRDPServer::waitRemoteUSBThreadEvent(RTMSINTERVAL cMillies)
1565{
1566 int rc = RTSemEventWait(mUSBBackends.event, cMillies);
1567 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1568 NOREF(rc);
1569}
1570
1571void ConsoleVRDPServer::remoteUSBThreadStart(void)
1572{
1573 int rc = RTSemEventCreate(&mUSBBackends.event);
1574
1575 if (RT_FAILURE(rc))
1576 {
1577 AssertFailed();
1578 mUSBBackends.event = 0;
1579 }
1580
1581 if (RT_SUCCESS(rc))
1582 {
1583 rc = RTThreadCreate(&mUSBBackends.thread, threadRemoteUSB, this, 65536,
1584 RTTHREADTYPE_VRDP_IO, RTTHREADFLAGS_WAITABLE, "remote usb");
1585 }
1586
1587 if (RT_FAILURE(rc))
1588 {
1589 LogRel(("Warning: could not start the remote USB thread, rc = %Rrc!!!\n", rc));
1590 mUSBBackends.thread = NIL_RTTHREAD;
1591 }
1592 else
1593 {
1594 /* Wait until the thread is ready. */
1595 rc = RTThreadUserWait(mUSBBackends.thread, 60000);
1596 AssertRC(rc);
1597 Assert (mUSBBackends.fThreadRunning || RT_FAILURE(rc));
1598 }
1599}
1600
1601void ConsoleVRDPServer::remoteUSBThreadStop(void)
1602{
1603 mUSBBackends.fThreadRunning = false;
1604
1605 if (mUSBBackends.thread != NIL_RTTHREAD)
1606 {
1607 Assert (mUSBBackends.event != 0);
1608
1609 RTSemEventSignal(mUSBBackends.event);
1610
1611 int rc = RTThreadWait(mUSBBackends.thread, 60000, NULL);
1612 AssertRC(rc);
1613
1614 mUSBBackends.thread = NIL_RTTHREAD;
1615 }
1616
1617 if (mUSBBackends.event)
1618 {
1619 RTSemEventDestroy(mUSBBackends.event);
1620 mUSBBackends.event = 0;
1621 }
1622}
1623#endif /* VBOX_WITH_USB */
1624
1625AuthResult ConsoleVRDPServer::Authenticate(const Guid &uuid, AuthGuestJudgement guestJudgement,
1626 const char *pszUser, const char *pszPassword, const char *pszDomain,
1627 uint32_t u32ClientId)
1628{
1629 AUTHUUID rawuuid;
1630
1631 memcpy(rawuuid, uuid.raw(), sizeof(rawuuid));
1632
1633 LogFlow(("ConsoleVRDPServer::Authenticate: uuid = %RTuuid, guestJudgement = %d, pszUser = %s, pszPassword = %s, pszDomain = %s, u32ClientId = %d\n",
1634 rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, u32ClientId));
1635
1636 /*
1637 * Called only from VRDP input thread. So thread safety is not required.
1638 */
1639
1640 if (!mAuthLibrary)
1641 {
1642 /* Load the external authentication library. */
1643 Bstr authLibrary;
1644 mConsole->getVRDEServer()->COMGETTER(AuthLibrary)(authLibrary.asOutParam());
1645
1646 Utf8Str filename = authLibrary;
1647
1648 LogRel(("AUTH: ConsoleVRDPServer::Authenticate: loading external authentication library '%ls'\n", authLibrary.raw()));
1649
1650 int rc;
1651 if (RTPathHavePath(filename.c_str()))
1652 rc = RTLdrLoad(filename.c_str(), &mAuthLibrary);
1653 else
1654 rc = RTLdrLoadAppPriv(filename.c_str(), &mAuthLibrary);
1655
1656 if (RT_FAILURE(rc))
1657 LogRel(("AUTH: Failed to load external authentication library. Error code: %Rrc\n", rc));
1658
1659 if (RT_SUCCESS(rc))
1660 {
1661 typedef struct AuthEntryInfo
1662 {
1663 const char *pszName;
1664 void **ppvAddress;
1665
1666 } AuthEntryInfo;
1667 AuthEntryInfo entries[] =
1668 {
1669 { AUTHENTRY3_NAME, (void **)&mpfnAuthEntry3 },
1670 { AUTHENTRY2_NAME, (void **)&mpfnAuthEntry2 },
1671 { AUTHENTRY_NAME, (void **)&mpfnAuthEntry },
1672 { NULL, NULL }
1673 };
1674
1675 /* Get the entry point. */
1676 AuthEntryInfo *pEntryInfo = &entries[0];
1677 while (pEntryInfo->pszName)
1678 {
1679 *pEntryInfo->ppvAddress = NULL;
1680
1681 int rc2 = RTLdrGetSymbol(mAuthLibrary, pEntryInfo->pszName, pEntryInfo->ppvAddress);
1682 if (RT_SUCCESS(rc2))
1683 {
1684 /* Found an entry point. */
1685 LogRel(("AUTH: Using entry point '%s'.\n", pEntryInfo->pszName));
1686 rc = VINF_SUCCESS;
1687 break;
1688 }
1689
1690 if (rc2 != VERR_SYMBOL_NOT_FOUND)
1691 {
1692 LogRel(("AUTH: Could not resolve import '%s'. Error code: %Rrc\n", pEntryInfo->pszName, rc2));
1693 }
1694 rc = rc2;
1695
1696 pEntryInfo++;
1697 }
1698 }
1699
1700 if (RT_FAILURE(rc))
1701 {
1702 mConsole->setError(E_FAIL,
1703 mConsole->tr("Could not load the external authentication library '%s' (%Rrc)"),
1704 filename.c_str(),
1705 rc);
1706
1707 mpfnAuthEntry = NULL;
1708 mpfnAuthEntry2 = NULL;
1709 mpfnAuthEntry3 = NULL;
1710
1711 if (mAuthLibrary)
1712 {
1713 RTLdrClose(mAuthLibrary);
1714 mAuthLibrary = 0;
1715 }
1716
1717 return AuthResultAccessDenied;
1718 }
1719 }
1720
1721 Assert(mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2 || mpfnAuthEntry3));
1722
1723 AuthResult result = AuthResultAccessDenied;
1724 if (mpfnAuthEntry3)
1725 {
1726 result = mpfnAuthEntry3("vrde", &rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, true, u32ClientId);
1727 }
1728 else if (mpfnAuthEntry2)
1729 {
1730 result = mpfnAuthEntry2(&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, true, u32ClientId);
1731 }
1732 else if (mpfnAuthEntry)
1733 {
1734 result = mpfnAuthEntry(&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain);
1735 }
1736
1737 switch (result)
1738 {
1739 case AuthResultAccessDenied:
1740 LogRel(("AUTH: external authentication module returned 'access denied'\n"));
1741 break;
1742 case AuthResultAccessGranted:
1743 LogRel(("AUTH: external authentication module returned 'access granted'\n"));
1744 break;
1745 case AuthResultDelegateToGuest:
1746 LogRel(("AUTH: external authentication module returned 'delegate request to guest'\n"));
1747 break;
1748 default:
1749 LogRel(("AUTH: external authentication module returned incorrect return code %d\n", result));
1750 result = AuthResultAccessDenied;
1751 }
1752
1753 LogFlow(("ConsoleVRDPServer::Authenticate: result = %d\n", result));
1754
1755 return result;
1756}
1757
1758void ConsoleVRDPServer::AuthDisconnect(const Guid &uuid, uint32_t u32ClientId)
1759{
1760 AUTHUUID rawuuid;
1761
1762 memcpy(rawuuid, uuid.raw(), sizeof(rawuuid));
1763
1764 LogFlow(("ConsoleVRDPServer::AuthDisconnect: uuid = %RTuuid, u32ClientId = %d\n",
1765 rawuuid, u32ClientId));
1766
1767 Assert(mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2 || mpfnAuthEntry3));
1768
1769 if (mpfnAuthEntry3)
1770 mpfnAuthEntry3("vrde", &rawuuid, AuthGuestNotAsked, NULL, NULL, NULL, false, u32ClientId);
1771 else if (mpfnAuthEntry2)
1772 mpfnAuthEntry2(&rawuuid, AuthGuestNotAsked, NULL, NULL, NULL, false, u32ClientId);
1773}
1774
1775int ConsoleVRDPServer::lockConsoleVRDPServer(void)
1776{
1777 int rc = RTCritSectEnter(&mCritSect);
1778 AssertRC(rc);
1779 return rc;
1780}
1781
1782void ConsoleVRDPServer::unlockConsoleVRDPServer(void)
1783{
1784 RTCritSectLeave(&mCritSect);
1785}
1786
1787DECLCALLBACK(int) ConsoleVRDPServer::ClipboardCallback(void *pvCallback,
1788 uint32_t u32ClientId,
1789 uint32_t u32Function,
1790 uint32_t u32Format,
1791 const void *pvData,
1792 uint32_t cbData)
1793{
1794 LogFlowFunc(("pvCallback = %p, u32ClientId = %d, u32Function = %d, u32Format = 0x%08X, pvData = %p, cbData = %d\n",
1795 pvCallback, u32ClientId, u32Function, u32Format, pvData, cbData));
1796
1797 int rc = VINF_SUCCESS;
1798
1799 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvCallback);
1800
1801 NOREF(u32ClientId);
1802
1803 switch (u32Function)
1804 {
1805 case VRDE_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE:
1806 {
1807 if (pServer->mpfnClipboardCallback)
1808 {
1809 pServer->mpfnClipboardCallback(VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE,
1810 u32Format,
1811 (void *)pvData,
1812 cbData);
1813 }
1814 } break;
1815
1816 case VRDE_CLIPBOARD_FUNCTION_DATA_READ:
1817 {
1818 if (pServer->mpfnClipboardCallback)
1819 {
1820 pServer->mpfnClipboardCallback(VBOX_CLIPBOARD_EXT_FN_DATA_READ,
1821 u32Format,
1822 (void *)pvData,
1823 cbData);
1824 }
1825 } break;
1826
1827 default:
1828 rc = VERR_NOT_SUPPORTED;
1829 }
1830
1831 return rc;
1832}
1833
1834DECLCALLBACK(int) ConsoleVRDPServer::ClipboardServiceExtension(void *pvExtension,
1835 uint32_t u32Function,
1836 void *pvParms,
1837 uint32_t cbParms)
1838{
1839 LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
1840 pvExtension, u32Function, pvParms, cbParms));
1841
1842 int rc = VINF_SUCCESS;
1843
1844 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvExtension);
1845
1846 VBOXCLIPBOARDEXTPARMS *pParms = (VBOXCLIPBOARDEXTPARMS *)pvParms;
1847
1848 switch (u32Function)
1849 {
1850 case VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK:
1851 {
1852 pServer->mpfnClipboardCallback = pParms->u.pfnCallback;
1853 } break;
1854
1855 case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
1856 {
1857 /* The guest announces clipboard formats. This must be delivered to all clients. */
1858 if (mpEntryPoints && pServer->mhServer)
1859 {
1860 mpEntryPoints->VRDEClipboard(pServer->mhServer,
1861 VRDE_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE,
1862 pParms->u32Format,
1863 NULL,
1864 0,
1865 NULL);
1866 }
1867 } break;
1868
1869 case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
1870 {
1871 /* The clipboard service expects that the pvData buffer will be filled
1872 * with clipboard data. The server returns the data from the client that
1873 * announced the requested format most recently.
1874 */
1875 if (mpEntryPoints && pServer->mhServer)
1876 {
1877 mpEntryPoints->VRDEClipboard(pServer->mhServer,
1878 VRDE_CLIPBOARD_FUNCTION_DATA_READ,
1879 pParms->u32Format,
1880 pParms->u.pvData,
1881 pParms->cbData,
1882 &pParms->cbData);
1883 }
1884 } break;
1885
1886 case VBOX_CLIPBOARD_EXT_FN_DATA_WRITE:
1887 {
1888 if (mpEntryPoints && pServer->mhServer)
1889 {
1890 mpEntryPoints->VRDEClipboard(pServer->mhServer,
1891 VRDE_CLIPBOARD_FUNCTION_DATA_WRITE,
1892 pParms->u32Format,
1893 pParms->u.pvData,
1894 pParms->cbData,
1895 NULL);
1896 }
1897 } break;
1898
1899 default:
1900 rc = VERR_NOT_SUPPORTED;
1901 }
1902
1903 return rc;
1904}
1905
1906void ConsoleVRDPServer::ClipboardCreate(uint32_t u32ClientId)
1907{
1908 int rc = lockConsoleVRDPServer();
1909
1910 if (RT_SUCCESS(rc))
1911 {
1912 if (mcClipboardRefs == 0)
1913 {
1914 rc = HGCMHostRegisterServiceExtension(&mhClipboard, "VBoxSharedClipboard", ClipboardServiceExtension, this);
1915
1916 if (RT_SUCCESS(rc))
1917 {
1918 mcClipboardRefs++;
1919 }
1920 }
1921
1922 unlockConsoleVRDPServer();
1923 }
1924}
1925
1926void ConsoleVRDPServer::ClipboardDelete(uint32_t u32ClientId)
1927{
1928 int rc = lockConsoleVRDPServer();
1929
1930 if (RT_SUCCESS(rc))
1931 {
1932 mcClipboardRefs--;
1933
1934 if (mcClipboardRefs == 0)
1935 {
1936 HGCMHostUnregisterServiceExtension(mhClipboard);
1937 }
1938
1939 unlockConsoleVRDPServer();
1940 }
1941}
1942
1943/* That is called on INPUT thread of the VRDP server.
1944 * The ConsoleVRDPServer keeps a list of created backend instances.
1945 */
1946void ConsoleVRDPServer::USBBackendCreate(uint32_t u32ClientId, void **ppvIntercept)
1947{
1948#ifdef VBOX_WITH_USB
1949 LogFlow(("ConsoleVRDPServer::USBBackendCreate: u32ClientId = %d\n", u32ClientId));
1950
1951 /* Create a new instance of the USB backend for the new client. */
1952 RemoteUSBBackend *pRemoteUSBBackend = new RemoteUSBBackend(mConsole, this, u32ClientId);
1953
1954 if (pRemoteUSBBackend)
1955 {
1956 pRemoteUSBBackend->AddRef(); /* 'Release' called in USBBackendDelete. */
1957
1958 /* Append the new instance in the list. */
1959 int rc = lockConsoleVRDPServer();
1960
1961 if (RT_SUCCESS(rc))
1962 {
1963 pRemoteUSBBackend->pNext = mUSBBackends.pHead;
1964 if (mUSBBackends.pHead)
1965 {
1966 mUSBBackends.pHead->pPrev = pRemoteUSBBackend;
1967 }
1968 else
1969 {
1970 mUSBBackends.pTail = pRemoteUSBBackend;
1971 }
1972
1973 mUSBBackends.pHead = pRemoteUSBBackend;
1974
1975 unlockConsoleVRDPServer();
1976
1977 if (ppvIntercept)
1978 {
1979 *ppvIntercept = pRemoteUSBBackend;
1980 }
1981 }
1982
1983 if (RT_FAILURE(rc))
1984 {
1985 pRemoteUSBBackend->Release();
1986 }
1987 }
1988#endif /* VBOX_WITH_USB */
1989}
1990
1991void ConsoleVRDPServer::USBBackendDelete(uint32_t u32ClientId)
1992{
1993#ifdef VBOX_WITH_USB
1994 LogFlow(("ConsoleVRDPServer::USBBackendDelete: u32ClientId = %d\n", u32ClientId));
1995
1996 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1997
1998 /* Find the instance. */
1999 int rc = lockConsoleVRDPServer();
2000
2001 if (RT_SUCCESS(rc))
2002 {
2003 pRemoteUSBBackend = usbBackendFind(u32ClientId);
2004
2005 if (pRemoteUSBBackend)
2006 {
2007 /* Notify that it will be deleted. */
2008 pRemoteUSBBackend->NotifyDelete();
2009 }
2010
2011 unlockConsoleVRDPServer();
2012 }
2013
2014 if (pRemoteUSBBackend)
2015 {
2016 /* Here the instance has been excluded from the list and can be dereferenced. */
2017 pRemoteUSBBackend->Release();
2018 }
2019#endif
2020}
2021
2022void *ConsoleVRDPServer::USBBackendRequestPointer(uint32_t u32ClientId, const Guid *pGuid)
2023{
2024#ifdef VBOX_WITH_USB
2025 RemoteUSBBackend *pRemoteUSBBackend = NULL;
2026
2027 /* Find the instance. */
2028 int rc = lockConsoleVRDPServer();
2029
2030 if (RT_SUCCESS(rc))
2031 {
2032 pRemoteUSBBackend = usbBackendFind(u32ClientId);
2033
2034 if (pRemoteUSBBackend)
2035 {
2036 /* Inform the backend instance that it is referenced by the Guid. */
2037 bool fAdded = pRemoteUSBBackend->addUUID(pGuid);
2038
2039 if (fAdded)
2040 {
2041 /* Reference the instance because its pointer is being taken. */
2042 pRemoteUSBBackend->AddRef(); /* 'Release' is called in USBBackendReleasePointer. */
2043 }
2044 else
2045 {
2046 pRemoteUSBBackend = NULL;
2047 }
2048 }
2049
2050 unlockConsoleVRDPServer();
2051 }
2052
2053 if (pRemoteUSBBackend)
2054 {
2055 return pRemoteUSBBackend->GetBackendCallbackPointer();
2056 }
2057
2058#endif
2059 return NULL;
2060}
2061
2062void ConsoleVRDPServer::USBBackendReleasePointer(const Guid *pGuid)
2063{
2064#ifdef VBOX_WITH_USB
2065 RemoteUSBBackend *pRemoteUSBBackend = NULL;
2066
2067 /* Find the instance. */
2068 int rc = lockConsoleVRDPServer();
2069
2070 if (RT_SUCCESS(rc))
2071 {
2072 pRemoteUSBBackend = usbBackendFindByUUID(pGuid);
2073
2074 if (pRemoteUSBBackend)
2075 {
2076 pRemoteUSBBackend->removeUUID(pGuid);
2077 }
2078
2079 unlockConsoleVRDPServer();
2080
2081 if (pRemoteUSBBackend)
2082 {
2083 pRemoteUSBBackend->Release();
2084 }
2085 }
2086#endif
2087}
2088
2089RemoteUSBBackend *ConsoleVRDPServer::usbBackendGetNext(RemoteUSBBackend *pRemoteUSBBackend)
2090{
2091 LogFlow(("ConsoleVRDPServer::usbBackendGetNext: pBackend = %p\n", pRemoteUSBBackend));
2092
2093 RemoteUSBBackend *pNextRemoteUSBBackend = NULL;
2094#ifdef VBOX_WITH_USB
2095
2096 int rc = lockConsoleVRDPServer();
2097
2098 if (RT_SUCCESS(rc))
2099 {
2100 if (pRemoteUSBBackend == NULL)
2101 {
2102 /* The first backend in the list is requested. */
2103 pNextRemoteUSBBackend = mUSBBackends.pHead;
2104 }
2105 else
2106 {
2107 /* Get pointer to the next backend. */
2108 pNextRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
2109 }
2110
2111 if (pNextRemoteUSBBackend)
2112 {
2113 pNextRemoteUSBBackend->AddRef();
2114 }
2115
2116 unlockConsoleVRDPServer();
2117
2118 if (pRemoteUSBBackend)
2119 {
2120 pRemoteUSBBackend->Release();
2121 }
2122 }
2123#endif
2124
2125 return pNextRemoteUSBBackend;
2126}
2127
2128#ifdef VBOX_WITH_USB
2129/* Internal method. Called under the ConsoleVRDPServerLock. */
2130RemoteUSBBackend *ConsoleVRDPServer::usbBackendFind(uint32_t u32ClientId)
2131{
2132 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
2133
2134 while (pRemoteUSBBackend)
2135 {
2136 if (pRemoteUSBBackend->ClientId() == u32ClientId)
2137 {
2138 break;
2139 }
2140
2141 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
2142 }
2143
2144 return pRemoteUSBBackend;
2145}
2146
2147/* Internal method. Called under the ConsoleVRDPServerLock. */
2148RemoteUSBBackend *ConsoleVRDPServer::usbBackendFindByUUID(const Guid *pGuid)
2149{
2150 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
2151
2152 while (pRemoteUSBBackend)
2153 {
2154 if (pRemoteUSBBackend->findUUID(pGuid))
2155 {
2156 break;
2157 }
2158
2159 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
2160 }
2161
2162 return pRemoteUSBBackend;
2163}
2164#endif
2165
2166/* Internal method. Called by the backend destructor. */
2167void ConsoleVRDPServer::usbBackendRemoveFromList(RemoteUSBBackend *pRemoteUSBBackend)
2168{
2169#ifdef VBOX_WITH_USB
2170 int rc = lockConsoleVRDPServer();
2171 AssertRC(rc);
2172
2173 /* Exclude the found instance from the list. */
2174 if (pRemoteUSBBackend->pNext)
2175 {
2176 pRemoteUSBBackend->pNext->pPrev = pRemoteUSBBackend->pPrev;
2177 }
2178 else
2179 {
2180 mUSBBackends.pTail = (RemoteUSBBackend *)pRemoteUSBBackend->pPrev;
2181 }
2182
2183 if (pRemoteUSBBackend->pPrev)
2184 {
2185 pRemoteUSBBackend->pPrev->pNext = pRemoteUSBBackend->pNext;
2186 }
2187 else
2188 {
2189 mUSBBackends.pHead = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
2190 }
2191
2192 pRemoteUSBBackend->pNext = pRemoteUSBBackend->pPrev = NULL;
2193
2194 unlockConsoleVRDPServer();
2195#endif
2196}
2197
2198
2199void ConsoleVRDPServer::SendUpdate(unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate) const
2200{
2201 if (mpEntryPoints && mhServer)
2202 {
2203 mpEntryPoints->VRDEUpdate(mhServer, uScreenId, pvUpdate, cbUpdate);
2204 }
2205}
2206
2207void ConsoleVRDPServer::SendResize(void) const
2208{
2209 if (mpEntryPoints && mhServer)
2210 {
2211 mpEntryPoints->VRDEResize(mhServer);
2212 }
2213}
2214
2215void ConsoleVRDPServer::SendUpdateBitmap(unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h) const
2216{
2217 VRDEORDERHDR update;
2218 update.x = x;
2219 update.y = y;
2220 update.w = w;
2221 update.h = h;
2222 if (mpEntryPoints && mhServer)
2223 {
2224 mpEntryPoints->VRDEUpdate(mhServer, uScreenId, &update, sizeof(update));
2225 }
2226}
2227
2228void ConsoleVRDPServer::SendAudioSamples(void *pvSamples, uint32_t cSamples, VRDEAUDIOFORMAT format) const
2229{
2230 if (mpEntryPoints && mhServer)
2231 {
2232 mpEntryPoints->VRDEAudioSamples(mhServer, pvSamples, cSamples, format);
2233 }
2234}
2235
2236void ConsoleVRDPServer::SendAudioVolume(uint16_t left, uint16_t right) const
2237{
2238 if (mpEntryPoints && mhServer)
2239 {
2240 mpEntryPoints->VRDEAudioVolume(mhServer, left, right);
2241 }
2242}
2243
2244void ConsoleVRDPServer::SendUSBRequest(uint32_t u32ClientId, void *pvParms, uint32_t cbParms) const
2245{
2246 if (mpEntryPoints && mhServer)
2247 {
2248 mpEntryPoints->VRDEUSBRequest(mhServer, u32ClientId, pvParms, cbParms);
2249 }
2250}
2251
2252/* @todo rc not needed? */
2253int ConsoleVRDPServer::SendAudioInputBegin(void **ppvUserCtx,
2254 void *pvContext,
2255 uint32_t cSamples,
2256 uint32_t iSampleHz,
2257 uint32_t cChannels,
2258 uint32_t cBits)
2259{
2260 if (mpEntryPoints && mhServer && mpEntryPoints->VRDEAudioInOpen)
2261 {
2262 uint32_t u32ClientId = ASMAtomicReadU32(&mu32AudioInputClientId);
2263 if (u32ClientId != 0) /* 0 would mean broadcast to all clients. */
2264 {
2265 VRDEAUDIOFORMAT audioFormat = VRDE_AUDIO_FMT_MAKE(iSampleHz, cChannels, cBits, 0);
2266 mpEntryPoints->VRDEAudioInOpen (mhServer,
2267 pvContext,
2268 u32ClientId,
2269 audioFormat,
2270 cSamples);
2271 *ppvUserCtx = NULL; /* This is the ConsoleVRDP server context.
2272 * Currently not used because only one client is allowed to
2273 * do audio input and the client id is saved by the ConsoleVRDPServer.
2274 */
2275
2276 return VINF_SUCCESS;
2277 }
2278 }
2279 return VERR_NOT_SUPPORTED;
2280}
2281
2282void ConsoleVRDPServer::SendAudioInputEnd(void *pvUserCtx)
2283{
2284 if (mpEntryPoints && mhServer && mpEntryPoints->VRDEAudioInClose)
2285 {
2286 uint32_t u32ClientId = ASMAtomicReadU32(&mu32AudioInputClientId);
2287 if (u32ClientId != 0) /* 0 would mean broadcast to all clients. */
2288 {
2289 mpEntryPoints->VRDEAudioInClose(mhServer, u32ClientId);
2290 }
2291 }
2292}
2293
2294
2295
2296void ConsoleVRDPServer::QueryInfo(uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const
2297{
2298 if (index == VRDE_QI_PORT)
2299 {
2300 uint32_t cbOut = sizeof(int32_t);
2301
2302 if (cbBuffer >= cbOut)
2303 {
2304 *pcbOut = cbOut;
2305 *(int32_t *)pvBuffer = (int32_t)mVRDPBindPort;
2306 }
2307 }
2308 else if (mpEntryPoints && mhServer)
2309 {
2310 mpEntryPoints->VRDEQueryInfo(mhServer, index, pvBuffer, cbBuffer, pcbOut);
2311 }
2312}
2313
2314/* static */ int ConsoleVRDPServer::loadVRDPLibrary(const char *pszLibraryName)
2315{
2316 int rc = VINF_SUCCESS;
2317
2318 if (mVRDPLibrary == NIL_RTLDRMOD)
2319 {
2320 char szErr[4096 + 512];
2321 szErr[0] = '\0';
2322 if (RTPathHavePath(pszLibraryName))
2323 rc = SUPR3HardenedLdrLoadPlugIn(pszLibraryName, &mVRDPLibrary, szErr, sizeof(szErr));
2324 else
2325 rc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &mVRDPLibrary);
2326 if (RT_SUCCESS(rc))
2327 {
2328 struct SymbolEntry
2329 {
2330 const char *name;
2331 void **ppfn;
2332 };
2333
2334 #define DEFSYMENTRY(a) { #a, (void**)&mpfn##a }
2335
2336 static const struct SymbolEntry s_aSymbols[] =
2337 {
2338 DEFSYMENTRY(VRDECreateServer)
2339 };
2340
2341 #undef DEFSYMENTRY
2342
2343 for (unsigned i = 0; i < RT_ELEMENTS(s_aSymbols); i++)
2344 {
2345 rc = RTLdrGetSymbol(mVRDPLibrary, s_aSymbols[i].name, s_aSymbols[i].ppfn);
2346
2347 if (RT_FAILURE(rc))
2348 {
2349 LogRel(("VRDE: Error resolving symbol '%s', rc %Rrc.\n", s_aSymbols[i].name, rc));
2350 break;
2351 }
2352 }
2353 }
2354 else
2355 {
2356 if (szErr[0])
2357 LogRel(("VRDE: Error loading the library '%s': %s (%Rrc)\n", pszLibraryName, szErr, rc));
2358 else
2359 LogRel(("VRDE: Error loading the library '%s' rc = %Rrc.\n", pszLibraryName, rc));
2360
2361 mVRDPLibrary = NIL_RTLDRMOD;
2362 }
2363 }
2364
2365 if (RT_FAILURE(rc))
2366 {
2367 if (mVRDPLibrary != NIL_RTLDRMOD)
2368 {
2369 RTLdrClose(mVRDPLibrary);
2370 mVRDPLibrary = NIL_RTLDRMOD;
2371 }
2372 }
2373
2374 return rc;
2375}
2376
2377/*
2378 * IVRDEServerInfo implementation.
2379 */
2380// constructor / destructor
2381/////////////////////////////////////////////////////////////////////////////
2382
2383VRDEServerInfo::VRDEServerInfo()
2384 : mParent(NULL)
2385{
2386}
2387
2388VRDEServerInfo::~VRDEServerInfo()
2389{
2390}
2391
2392
2393HRESULT VRDEServerInfo::FinalConstruct()
2394{
2395 return S_OK;
2396}
2397
2398void VRDEServerInfo::FinalRelease()
2399{
2400 uninit();
2401}
2402
2403// public methods only for internal purposes
2404/////////////////////////////////////////////////////////////////////////////
2405
2406/**
2407 * Initializes the guest object.
2408 */
2409HRESULT VRDEServerInfo::init(Console *aParent)
2410{
2411 LogFlowThisFunc(("aParent=%p\n", aParent));
2412
2413 ComAssertRet(aParent, E_INVALIDARG);
2414
2415 /* Enclose the state transition NotReady->InInit->Ready */
2416 AutoInitSpan autoInitSpan(this);
2417 AssertReturn(autoInitSpan.isOk(), E_FAIL);
2418
2419 unconst(mParent) = aParent;
2420
2421 /* Confirm a successful initialization */
2422 autoInitSpan.setSucceeded();
2423
2424 return S_OK;
2425}
2426
2427/**
2428 * Uninitializes the instance and sets the ready flag to FALSE.
2429 * Called either from FinalRelease() or by the parent when it gets destroyed.
2430 */
2431void VRDEServerInfo::uninit()
2432{
2433 LogFlowThisFunc(("\n"));
2434
2435 /* Enclose the state transition Ready->InUninit->NotReady */
2436 AutoUninitSpan autoUninitSpan(this);
2437 if (autoUninitSpan.uninitDone())
2438 return;
2439
2440 unconst(mParent) = NULL;
2441}
2442
2443// IVRDEServerInfo properties
2444/////////////////////////////////////////////////////////////////////////////
2445
2446#define IMPL_GETTER_BOOL(_aType, _aName, _aIndex) \
2447 STDMETHODIMP VRDEServerInfo::COMGETTER(_aName)(_aType *a##_aName) \
2448 { \
2449 if (!a##_aName) \
2450 return E_POINTER; \
2451 \
2452 AutoCaller autoCaller(this); \
2453 if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2454 \
2455 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
2456 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2457 \
2458 uint32_t value; \
2459 uint32_t cbOut = 0; \
2460 \
2461 mParent->consoleVRDPServer()->QueryInfo \
2462 (_aIndex, &value, sizeof(value), &cbOut); \
2463 \
2464 *a##_aName = cbOut? !!value: FALSE; \
2465 \
2466 return S_OK; \
2467 } \
2468 extern void IMPL_GETTER_BOOL_DUMMY(void)
2469
2470#define IMPL_GETTER_SCALAR(_aType, _aName, _aIndex, _aValueMask) \
2471 STDMETHODIMP VRDEServerInfo::COMGETTER(_aName)(_aType *a##_aName) \
2472 { \
2473 if (!a##_aName) \
2474 return E_POINTER; \
2475 \
2476 AutoCaller autoCaller(this); \
2477 if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2478 \
2479 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
2480 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2481 \
2482 _aType value; \
2483 uint32_t cbOut = 0; \
2484 \
2485 mParent->consoleVRDPServer()->QueryInfo \
2486 (_aIndex, &value, sizeof(value), &cbOut); \
2487 \
2488 if (_aValueMask) value &= (_aValueMask); \
2489 *a##_aName = cbOut? value: 0; \
2490 \
2491 return S_OK; \
2492 } \
2493 extern void IMPL_GETTER_SCALAR_DUMMY(void)
2494
2495#define IMPL_GETTER_BSTR(_aType, _aName, _aIndex) \
2496 STDMETHODIMP VRDEServerInfo::COMGETTER(_aName)(_aType *a##_aName) \
2497 { \
2498 if (!a##_aName) \
2499 return E_POINTER; \
2500 \
2501 AutoCaller autoCaller(this); \
2502 if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2503 \
2504 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
2505 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2506 \
2507 uint32_t cbOut = 0; \
2508 \
2509 mParent->consoleVRDPServer()->QueryInfo \
2510 (_aIndex, NULL, 0, &cbOut); \
2511 \
2512 if (cbOut == 0) \
2513 { \
2514 Bstr str(""); \
2515 str.cloneTo(a##_aName); \
2516 return S_OK; \
2517 } \
2518 \
2519 char *pchBuffer = (char *)RTMemTmpAlloc(cbOut); \
2520 \
2521 if (!pchBuffer) \
2522 { \
2523 Log(("VRDEServerInfo::" \
2524 #_aName \
2525 ": Failed to allocate memory %d bytes\n", cbOut)); \
2526 return E_OUTOFMEMORY; \
2527 } \
2528 \
2529 mParent->consoleVRDPServer()->QueryInfo \
2530 (_aIndex, pchBuffer, cbOut, &cbOut); \
2531 \
2532 Bstr str(pchBuffer); \
2533 \
2534 str.cloneTo(a##_aName); \
2535 \
2536 RTMemTmpFree(pchBuffer); \
2537 \
2538 return S_OK; \
2539 } \
2540 extern void IMPL_GETTER_BSTR_DUMMY(void)
2541
2542IMPL_GETTER_BOOL (BOOL, Active, VRDE_QI_ACTIVE);
2543IMPL_GETTER_SCALAR (LONG, Port, VRDE_QI_PORT, 0);
2544IMPL_GETTER_SCALAR (ULONG, NumberOfClients, VRDE_QI_NUMBER_OF_CLIENTS, 0);
2545IMPL_GETTER_SCALAR (LONG64, BeginTime, VRDE_QI_BEGIN_TIME, 0);
2546IMPL_GETTER_SCALAR (LONG64, EndTime, VRDE_QI_END_TIME, 0);
2547IMPL_GETTER_SCALAR (LONG64, BytesSent, VRDE_QI_BYTES_SENT, INT64_MAX);
2548IMPL_GETTER_SCALAR (LONG64, BytesSentTotal, VRDE_QI_BYTES_SENT_TOTAL, INT64_MAX);
2549IMPL_GETTER_SCALAR (LONG64, BytesReceived, VRDE_QI_BYTES_RECEIVED, INT64_MAX);
2550IMPL_GETTER_SCALAR (LONG64, BytesReceivedTotal, VRDE_QI_BYTES_RECEIVED_TOTAL, INT64_MAX);
2551IMPL_GETTER_BSTR (BSTR, User, VRDE_QI_USER);
2552IMPL_GETTER_BSTR (BSTR, Domain, VRDE_QI_DOMAIN);
2553IMPL_GETTER_BSTR (BSTR, ClientName, VRDE_QI_CLIENT_NAME);
2554IMPL_GETTER_BSTR (BSTR, ClientIP, VRDE_QI_CLIENT_IP);
2555IMPL_GETTER_SCALAR (ULONG, ClientVersion, VRDE_QI_CLIENT_VERSION, 0);
2556IMPL_GETTER_SCALAR (ULONG, EncryptionStyle, VRDE_QI_ENCRYPTION_STYLE, 0);
2557
2558#undef IMPL_GETTER_BSTR
2559#undef IMPL_GETTER_SCALAR
2560#undef IMPL_GETTER_BOOL
2561/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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