VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/ConsoleVRDPServer.cpp@ 52978

Last change on this file since 52978 was 52978, checked in by vboxsync, 10 years ago

IDisplay::GetScreenResolution returns status of the guest monitor.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 138.6 KB
Line 
1/* $Id: ConsoleVRDPServer.cpp 52978 2014-10-08 07:09:11Z vboxsync $ */
2/** @file
3 * VBox Console VRDP Helper class
4 */
5
6/*
7 * Copyright (C) 2006-2014 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#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
24#include "DrvAudioVRDE.h"
25#else
26#include "AudioSnifferInterface.h"
27#endif
28#ifdef VBOX_WITH_EXTPACK
29# include "ExtPackManagerImpl.h"
30#endif
31#include "VMMDev.h"
32#ifdef VBOX_WITH_USB_CARDREADER
33# include "UsbCardReader.h"
34#endif
35#include "UsbWebcamInterface.h"
36
37#include "Global.h"
38#include "AutoCaller.h"
39#include "Logging.h"
40
41#include <iprt/asm.h>
42#include <iprt/alloca.h>
43#include <iprt/ldr.h>
44#include <iprt/param.h>
45#include <iprt/path.h>
46#include <iprt/cpp/utils.h>
47
48#include <VBox/err.h>
49#include <VBox/RemoteDesktop/VRDEOrders.h>
50#include <VBox/com/listeners.h>
51#include <VBox/HostServices/VBoxCrOpenGLSvc.h>
52
53class VRDPConsoleListener
54{
55public:
56 VRDPConsoleListener()
57 {
58 }
59
60 HRESULT init(ConsoleVRDPServer *server)
61 {
62 m_server = server;
63 return S_OK;
64 }
65
66 void uninit()
67 {
68 }
69
70 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent * aEvent)
71 {
72 switch (aType)
73 {
74 case VBoxEventType_OnMousePointerShapeChanged:
75 {
76 ComPtr<IMousePointerShapeChangedEvent> mpscev = aEvent;
77 Assert(mpscev);
78 BOOL visible, alpha;
79 ULONG xHot, yHot, width, height;
80 com::SafeArray <BYTE> shape;
81
82 mpscev->COMGETTER(Visible)(&visible);
83 mpscev->COMGETTER(Alpha)(&alpha);
84 mpscev->COMGETTER(Xhot)(&xHot);
85 mpscev->COMGETTER(Yhot)(&yHot);
86 mpscev->COMGETTER(Width)(&width);
87 mpscev->COMGETTER(Height)(&height);
88 mpscev->COMGETTER(Shape)(ComSafeArrayAsOutParam(shape));
89
90 m_server->onMousePointerShapeChange(visible, alpha, xHot, yHot, width, height, ComSafeArrayAsInParam(shape));
91 break;
92 }
93 case VBoxEventType_OnMouseCapabilityChanged:
94 {
95 ComPtr<IMouseCapabilityChangedEvent> mccev = aEvent;
96 Assert(mccev);
97 if (m_server)
98 {
99 BOOL fAbsoluteMouse;
100 mccev->COMGETTER(SupportsAbsolute)(&fAbsoluteMouse);
101 m_server->NotifyAbsoluteMouse(!!fAbsoluteMouse);
102 }
103 break;
104 }
105 case VBoxEventType_OnKeyboardLedsChanged:
106 {
107 ComPtr<IKeyboardLedsChangedEvent> klcev = aEvent;
108 Assert(klcev);
109
110 if (m_server)
111 {
112 BOOL fNumLock, fCapsLock, fScrollLock;
113 klcev->COMGETTER(NumLock)(&fNumLock);
114 klcev->COMGETTER(CapsLock)(&fCapsLock);
115 klcev->COMGETTER(ScrollLock)(&fScrollLock);
116 m_server->NotifyKeyboardLedsChange(fNumLock, fCapsLock, fScrollLock);
117 }
118 break;
119 }
120
121 default:
122 AssertFailed();
123 }
124
125 return S_OK;
126 }
127
128private:
129 ConsoleVRDPServer *m_server;
130};
131
132typedef ListenerImpl<VRDPConsoleListener, ConsoleVRDPServer*> VRDPConsoleListenerImpl;
133
134VBOX_LISTENER_DECLARE(VRDPConsoleListenerImpl)
135
136#ifdef DEBUG_sunlover
137#define LOGDUMPPTR Log
138void dumpPointer(const uint8_t *pu8Shape, uint32_t width, uint32_t height, bool fXorMaskRGB32)
139{
140 unsigned i;
141
142 const uint8_t *pu8And = pu8Shape;
143
144 for (i = 0; i < height; i++)
145 {
146 unsigned j;
147 LOGDUMPPTR(("%p: ", pu8And));
148 for (j = 0; j < (width + 7) / 8; j++)
149 {
150 unsigned k;
151 for (k = 0; k < 8; k++)
152 {
153 LOGDUMPPTR(("%d", ((*pu8And) & (1 << (7 - k)))? 1: 0));
154 }
155
156 pu8And++;
157 }
158 LOGDUMPPTR(("\n"));
159 }
160
161 if (fXorMaskRGB32)
162 {
163 uint32_t *pu32Xor = (uint32_t*)(pu8Shape + ((((width + 7) / 8) * height + 3) & ~3));
164
165 for (i = 0; i < height; i++)
166 {
167 unsigned j;
168 LOGDUMPPTR(("%p: ", pu32Xor));
169 for (j = 0; j < width; j++)
170 {
171 LOGDUMPPTR(("%08X", *pu32Xor++));
172 }
173 LOGDUMPPTR(("\n"));
174 }
175 }
176 else
177 {
178 /* RDP 24 bit RGB mask. */
179 uint8_t *pu8Xor = (uint8_t*)(pu8Shape + ((((width + 7) / 8) * height + 3) & ~3));
180 for (i = 0; i < height; i++)
181 {
182 unsigned j;
183 LOGDUMPPTR(("%p: ", pu8Xor));
184 for (j = 0; j < width; j++)
185 {
186 LOGDUMPPTR(("%02X%02X%02X", pu8Xor[2], pu8Xor[1], pu8Xor[0]));
187 pu8Xor += 3;
188 }
189 LOGDUMPPTR(("\n"));
190 }
191 }
192}
193#else
194#define dumpPointer(a, b, c, d) do {} while (0)
195#endif /* DEBUG_sunlover */
196
197static void findTopLeftBorder(const uint8_t *pu8AndMask, const uint8_t *pu8XorMask, uint32_t width,
198 uint32_t height, uint32_t *pxSkip, uint32_t *pySkip)
199{
200 /*
201 * Find the top border of the AND mask. First assign to special value.
202 */
203 uint32_t ySkipAnd = ~0;
204
205 const uint8_t *pu8And = pu8AndMask;
206 const uint32_t cbAndRow = (width + 7) / 8;
207 const uint8_t maskLastByte = (uint8_t)( 0xFF << (cbAndRow * 8 - width) );
208
209 Assert(cbAndRow > 0);
210
211 unsigned y;
212 unsigned x;
213
214 for (y = 0; y < height && ySkipAnd == ~(uint32_t)0; y++, pu8And += cbAndRow)
215 {
216 /* For each complete byte in the row. */
217 for (x = 0; x < cbAndRow - 1; x++)
218 {
219 if (pu8And[x] != 0xFF)
220 {
221 ySkipAnd = y;
222 break;
223 }
224 }
225
226 if (ySkipAnd == ~(uint32_t)0)
227 {
228 /* Last byte. */
229 if ((pu8And[cbAndRow - 1] & maskLastByte) != maskLastByte)
230 {
231 ySkipAnd = y;
232 }
233 }
234 }
235
236 if (ySkipAnd == ~(uint32_t)0)
237 {
238 ySkipAnd = 0;
239 }
240
241 /*
242 * Find the left border of the AND mask.
243 */
244 uint32_t xSkipAnd = ~0;
245
246 /* For all bit columns. */
247 for (x = 0; x < width && xSkipAnd == ~(uint32_t)0; x++)
248 {
249 pu8And = pu8AndMask + x/8; /* Currently checking byte. */
250 uint8_t mask = 1 << (7 - x%8); /* Currently checking bit in the byte. */
251
252 for (y = ySkipAnd; y < height; y++, pu8And += cbAndRow)
253 {
254 if ((*pu8And & mask) == 0)
255 {
256 xSkipAnd = x;
257 break;
258 }
259 }
260 }
261
262 if (xSkipAnd == ~(uint32_t)0)
263 {
264 xSkipAnd = 0;
265 }
266
267 /*
268 * Find the XOR mask top border.
269 */
270 uint32_t ySkipXor = ~0;
271
272 uint32_t *pu32XorStart = (uint32_t *)pu8XorMask;
273
274 uint32_t *pu32Xor = pu32XorStart;
275
276 for (y = 0; y < height && ySkipXor == ~(uint32_t)0; y++, pu32Xor += width)
277 {
278 for (x = 0; x < width; x++)
279 {
280 if (pu32Xor[x] != 0)
281 {
282 ySkipXor = y;
283 break;
284 }
285 }
286 }
287
288 if (ySkipXor == ~(uint32_t)0)
289 {
290 ySkipXor = 0;
291 }
292
293 /*
294 * Find the left border of the XOR mask.
295 */
296 uint32_t xSkipXor = ~(uint32_t)0;
297
298 /* For all columns. */
299 for (x = 0; x < width && xSkipXor == ~(uint32_t)0; x++)
300 {
301 pu32Xor = pu32XorStart + x; /* Currently checking dword. */
302
303 for (y = ySkipXor; y < height; y++, pu32Xor += width)
304 {
305 if (*pu32Xor != 0)
306 {
307 xSkipXor = x;
308 break;
309 }
310 }
311 }
312
313 if (xSkipXor == ~(uint32_t)0)
314 {
315 xSkipXor = 0;
316 }
317
318 *pxSkip = RT_MIN(xSkipAnd, xSkipXor);
319 *pySkip = RT_MIN(ySkipAnd, ySkipXor);
320}
321
322/* Generate an AND mask for alpha pointers here, because
323 * guest driver does not do that correctly for Vista pointers.
324 * Similar fix, changing the alpha threshold, could be applied
325 * for the guest driver, but then additions reinstall would be
326 * necessary, which we try to avoid.
327 */
328static void mousePointerGenerateANDMask(uint8_t *pu8DstAndMask, int cbDstAndMask, const uint8_t *pu8SrcAlpha, int w, int h)
329{
330 memset(pu8DstAndMask, 0xFF, cbDstAndMask);
331
332 int y;
333 for (y = 0; y < h; y++)
334 {
335 uint8_t bitmask = 0x80;
336
337 int x;
338 for (x = 0; x < w; x++, bitmask >>= 1)
339 {
340 if (bitmask == 0)
341 {
342 bitmask = 0x80;
343 }
344
345 /* Whether alpha channel value is not transparent enough for the pixel to be seen. */
346 if (pu8SrcAlpha[x * 4 + 3] > 0x7f)
347 {
348 pu8DstAndMask[x / 8] &= ~bitmask;
349 }
350 }
351
352 /* Point to next source and dest scans. */
353 pu8SrcAlpha += w * 4;
354 pu8DstAndMask += (w + 7) / 8;
355 }
356}
357
358void ConsoleVRDPServer::onMousePointerShapeChange(BOOL visible,
359 BOOL alpha,
360 ULONG xHot,
361 ULONG yHot,
362 ULONG width,
363 ULONG height,
364 ComSafeArrayIn(BYTE,inShape))
365{
366 LogSunlover(("VRDPConsoleListener::OnMousePointerShapeChange: %d, %d, %lux%lu, @%lu,%lu\n",
367 visible, alpha, width, height, xHot, yHot));
368
369 com::SafeArray <BYTE> aShape(ComSafeArrayInArg(inShape));
370 if (aShape.size() == 0)
371 {
372 if (!visible)
373 {
374 MousePointerHide();
375 }
376 }
377 else if (width != 0 && height != 0)
378 {
379 uint8_t* shape = aShape.raw();
380
381 dumpPointer(shape, width, height, true);
382
383 /* Try the new interface. */
384 if (MousePointer(alpha, xHot, yHot, width, height, shape) == VINF_SUCCESS)
385 {
386 return;
387 }
388
389 /* Continue with the old interface. */
390
391 /* Pointer consists of 1 bpp AND and 24 BPP XOR masks.
392 * 'shape' AND mask followed by XOR mask.
393 * XOR mask contains 32 bit (lsb)BGR0(msb) values.
394 *
395 * We convert this to RDP color format which consist of
396 * one bpp AND mask and 24 BPP (BGR) color XOR image.
397 *
398 * RDP clients expect 8 aligned width and height of
399 * pointer (preferably 32x32).
400 *
401 * They even contain bugs which do not appear for
402 * 32x32 pointers but would appear for a 41x32 one.
403 *
404 * So set pointer size to 32x32. This can be done safely
405 * because most pointers are 32x32.
406 */
407
408 int cbDstAndMask = (((width + 7) / 8) * height + 3) & ~3;
409
410 uint8_t *pu8AndMask = shape;
411 uint8_t *pu8XorMask = shape + cbDstAndMask;
412
413 if (alpha)
414 {
415 pu8AndMask = (uint8_t*)alloca(cbDstAndMask);
416
417 mousePointerGenerateANDMask(pu8AndMask, cbDstAndMask, pu8XorMask, width, height);
418 }
419
420 /* Windows guest alpha pointers are wider than 32 pixels.
421 * Try to find out the top-left border of the pointer and
422 * then copy only meaningful bits. All complete top rows
423 * and all complete left columns where (AND == 1 && XOR == 0)
424 * are skipped. Hot spot is adjusted.
425 */
426 uint32_t ySkip = 0; /* How many rows to skip at the top. */
427 uint32_t xSkip = 0; /* How many columns to skip at the left. */
428
429 findTopLeftBorder(pu8AndMask, pu8XorMask, width, height, &xSkip, &ySkip);
430
431 /* Must not skip the hot spot. */
432 xSkip = RT_MIN(xSkip, xHot);
433 ySkip = RT_MIN(ySkip, yHot);
434
435 /*
436 * Compute size and allocate memory for the pointer.
437 */
438 const uint32_t dstwidth = 32;
439 const uint32_t dstheight = 32;
440
441 VRDECOLORPOINTER *pointer = NULL;
442
443 uint32_t dstmaskwidth = (dstwidth + 7) / 8;
444
445 uint32_t rdpmaskwidth = dstmaskwidth;
446 uint32_t rdpmasklen = dstheight * rdpmaskwidth;
447
448 uint32_t rdpdatawidth = dstwidth * 3;
449 uint32_t rdpdatalen = dstheight * rdpdatawidth;
450
451 pointer = (VRDECOLORPOINTER *)RTMemTmpAlloc(sizeof(VRDECOLORPOINTER) + rdpmasklen + rdpdatalen);
452
453 if (pointer)
454 {
455 uint8_t *maskarray = (uint8_t*)pointer + sizeof(VRDECOLORPOINTER);
456 uint8_t *dataarray = maskarray + rdpmasklen;
457
458 memset(maskarray, 0xFF, rdpmasklen);
459 memset(dataarray, 0x00, rdpdatalen);
460
461 uint32_t srcmaskwidth = (width + 7) / 8;
462 uint32_t srcdatawidth = width * 4;
463
464 /* Copy AND mask. */
465 uint8_t *src = pu8AndMask + ySkip * srcmaskwidth;
466 uint8_t *dst = maskarray + (dstheight - 1) * rdpmaskwidth;
467
468 uint32_t minheight = RT_MIN(height - ySkip, dstheight);
469 uint32_t minwidth = RT_MIN(width - xSkip, dstwidth);
470
471 unsigned x, y;
472
473 for (y = 0; y < minheight; y++)
474 {
475 for (x = 0; x < minwidth; x++)
476 {
477 uint32_t byteIndex = (x + xSkip) / 8;
478 uint32_t bitIndex = (x + xSkip) % 8;
479
480 bool bit = (src[byteIndex] & (1 << (7 - bitIndex))) != 0;
481
482 if (!bit)
483 {
484 byteIndex = x / 8;
485 bitIndex = x % 8;
486
487 dst[byteIndex] &= ~(1 << (7 - bitIndex));
488 }
489 }
490
491 src += srcmaskwidth;
492 dst -= rdpmaskwidth;
493 }
494
495 /* Point src to XOR mask */
496 src = pu8XorMask + ySkip * srcdatawidth;
497 dst = dataarray + (dstheight - 1) * rdpdatawidth;
498
499 for (y = 0; y < minheight ; y++)
500 {
501 for (x = 0; x < minwidth; x++)
502 {
503 memcpy(dst + x * 3, &src[4 * (x + xSkip)], 3);
504 }
505
506 src += srcdatawidth;
507 dst -= rdpdatawidth;
508 }
509
510 pointer->u16HotX = (uint16_t)(xHot - xSkip);
511 pointer->u16HotY = (uint16_t)(yHot - ySkip);
512
513 pointer->u16Width = (uint16_t)dstwidth;
514 pointer->u16Height = (uint16_t)dstheight;
515
516 pointer->u16MaskLen = (uint16_t)rdpmasklen;
517 pointer->u16DataLen = (uint16_t)rdpdatalen;
518
519 dumpPointer((uint8_t*)pointer + sizeof(*pointer), dstwidth, dstheight, false);
520
521 MousePointerUpdate(pointer);
522
523 RTMemTmpFree(pointer);
524 }
525 }
526}
527
528
529// ConsoleVRDPServer
530////////////////////////////////////////////////////////////////////////////////
531
532RTLDRMOD ConsoleVRDPServer::mVRDPLibrary = NIL_RTLDRMOD;
533
534PFNVRDECREATESERVER ConsoleVRDPServer::mpfnVRDECreateServer = NULL;
535
536VRDEENTRYPOINTS_4 ConsoleVRDPServer::mEntryPoints; /* A copy of the server entry points. */
537VRDEENTRYPOINTS_4 *ConsoleVRDPServer::mpEntryPoints = NULL;
538
539VRDECALLBACKS_4 ConsoleVRDPServer::mCallbacks =
540{
541 { VRDE_INTERFACE_VERSION_4, sizeof(VRDECALLBACKS_4) },
542 ConsoleVRDPServer::VRDPCallbackQueryProperty,
543 ConsoleVRDPServer::VRDPCallbackClientLogon,
544 ConsoleVRDPServer::VRDPCallbackClientConnect,
545 ConsoleVRDPServer::VRDPCallbackClientDisconnect,
546 ConsoleVRDPServer::VRDPCallbackIntercept,
547 ConsoleVRDPServer::VRDPCallbackUSB,
548 ConsoleVRDPServer::VRDPCallbackClipboard,
549 ConsoleVRDPServer::VRDPCallbackFramebufferQuery,
550 ConsoleVRDPServer::VRDPCallbackFramebufferLock,
551 ConsoleVRDPServer::VRDPCallbackFramebufferUnlock,
552 ConsoleVRDPServer::VRDPCallbackInput,
553 ConsoleVRDPServer::VRDPCallbackVideoModeHint,
554 ConsoleVRDPServer::VRDECallbackAudioIn
555};
556
557DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackQueryProperty(void *pvCallback, uint32_t index, void *pvBuffer,
558 uint32_t cbBuffer, uint32_t *pcbOut)
559{
560 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
561
562 int rc = VERR_NOT_SUPPORTED;
563
564 switch (index)
565 {
566 case VRDE_QP_NETWORK_PORT:
567 {
568 /* This is obsolete, the VRDE server uses VRDE_QP_NETWORK_PORT_RANGE instead. */
569 ULONG port = 0;
570
571 if (cbBuffer >= sizeof(uint32_t))
572 {
573 *(uint32_t *)pvBuffer = (uint32_t)port;
574 rc = VINF_SUCCESS;
575 }
576 else
577 {
578 rc = VINF_BUFFER_OVERFLOW;
579 }
580
581 *pcbOut = sizeof(uint32_t);
582 } break;
583
584 case VRDE_QP_NETWORK_ADDRESS:
585 {
586 com::Bstr bstr;
587 server->mConsole->i_getVRDEServer()->GetVRDEProperty(Bstr("TCP/Address").raw(), bstr.asOutParam());
588
589 /* The server expects UTF8. */
590 com::Utf8Str address = bstr;
591
592 size_t cbAddress = address.length() + 1;
593
594 if (cbAddress >= 0x10000)
595 {
596 /* More than 64K seems to be an invalid address. */
597 rc = VERR_TOO_MUCH_DATA;
598 break;
599 }
600
601 if ((size_t)cbBuffer >= cbAddress)
602 {
603 memcpy(pvBuffer, address.c_str(), cbAddress);
604 rc = VINF_SUCCESS;
605 }
606 else
607 {
608 rc = VINF_BUFFER_OVERFLOW;
609 }
610
611 *pcbOut = (uint32_t)cbAddress;
612 } break;
613
614 case VRDE_QP_NUMBER_MONITORS:
615 {
616 ULONG cMonitors = 1;
617
618 server->mConsole->i_machine()->COMGETTER(MonitorCount)(&cMonitors);
619
620 if (cbBuffer >= sizeof(uint32_t))
621 {
622 *(uint32_t *)pvBuffer = (uint32_t)cMonitors;
623 rc = VINF_SUCCESS;
624 }
625 else
626 {
627 rc = VINF_BUFFER_OVERFLOW;
628 }
629
630 *pcbOut = sizeof(uint32_t);
631 } break;
632
633 case VRDE_QP_NETWORK_PORT_RANGE:
634 {
635 com::Bstr bstr;
636 HRESULT hrc = server->mConsole->i_getVRDEServer()->GetVRDEProperty(Bstr("TCP/Ports").raw(), bstr.asOutParam());
637
638 if (hrc != S_OK)
639 {
640 bstr = "";
641 }
642
643 if (bstr == "0")
644 {
645 bstr = "3389";
646 }
647
648 /* The server expects UTF8. */
649 com::Utf8Str portRange = bstr;
650
651 size_t cbPortRange = portRange.length() + 1;
652
653 if (cbPortRange >= 0x10000)
654 {
655 /* More than 64K seems to be an invalid port range string. */
656 rc = VERR_TOO_MUCH_DATA;
657 break;
658 }
659
660 if ((size_t)cbBuffer >= cbPortRange)
661 {
662 memcpy(pvBuffer, portRange.c_str(), cbPortRange);
663 rc = VINF_SUCCESS;
664 }
665 else
666 {
667 rc = VINF_BUFFER_OVERFLOW;
668 }
669
670 *pcbOut = (uint32_t)cbPortRange;
671 } break;
672
673 case VRDE_QP_VIDEO_CHANNEL:
674 {
675 com::Bstr bstr;
676 HRESULT hrc = server->mConsole->i_getVRDEServer()->GetVRDEProperty(Bstr("VideoChannel/Enabled").raw(),
677 bstr.asOutParam());
678
679 if (hrc != S_OK)
680 {
681 bstr = "";
682 }
683
684 com::Utf8Str value = bstr;
685
686 BOOL fVideoEnabled = RTStrICmp(value.c_str(), "true") == 0
687 || RTStrICmp(value.c_str(), "1") == 0;
688
689 if (cbBuffer >= sizeof(uint32_t))
690 {
691 *(uint32_t *)pvBuffer = (uint32_t)fVideoEnabled;
692 rc = VINF_SUCCESS;
693 }
694 else
695 {
696 rc = VINF_BUFFER_OVERFLOW;
697 }
698
699 *pcbOut = sizeof(uint32_t);
700 } break;
701
702 case VRDE_QP_VIDEO_CHANNEL_QUALITY:
703 {
704 com::Bstr bstr;
705 HRESULT hrc = server->mConsole->i_getVRDEServer()->GetVRDEProperty(Bstr("VideoChannel/Quality").raw(),
706 bstr.asOutParam());
707
708 if (hrc != S_OK)
709 {
710 bstr = "";
711 }
712
713 com::Utf8Str value = bstr;
714
715 ULONG ulQuality = RTStrToUInt32(value.c_str()); /* This returns 0 on invalid string which is ok. */
716
717 if (cbBuffer >= sizeof(uint32_t))
718 {
719 *(uint32_t *)pvBuffer = (uint32_t)ulQuality;
720 rc = VINF_SUCCESS;
721 }
722 else
723 {
724 rc = VINF_BUFFER_OVERFLOW;
725 }
726
727 *pcbOut = sizeof(uint32_t);
728 } break;
729
730 case VRDE_QP_VIDEO_CHANNEL_SUNFLSH:
731 {
732 ULONG ulSunFlsh = 1;
733
734 com::Bstr bstr;
735 HRESULT hrc = server->mConsole->i_machine()->GetExtraData(Bstr("VRDP/SunFlsh").raw(),
736 bstr.asOutParam());
737 if (hrc == S_OK && !bstr.isEmpty())
738 {
739 com::Utf8Str sunFlsh = bstr;
740 if (!sunFlsh.isEmpty())
741 {
742 ulSunFlsh = sunFlsh.toUInt32();
743 }
744 }
745
746 if (cbBuffer >= sizeof(uint32_t))
747 {
748 *(uint32_t *)pvBuffer = (uint32_t)ulSunFlsh;
749 rc = VINF_SUCCESS;
750 }
751 else
752 {
753 rc = VINF_BUFFER_OVERFLOW;
754 }
755
756 *pcbOut = sizeof(uint32_t);
757 } break;
758
759 case VRDE_QP_FEATURE:
760 {
761 if (cbBuffer < sizeof(VRDEFEATURE))
762 {
763 rc = VERR_INVALID_PARAMETER;
764 break;
765 }
766
767 size_t cbInfo = cbBuffer - RT_OFFSETOF(VRDEFEATURE, achInfo);
768
769 VRDEFEATURE *pFeature = (VRDEFEATURE *)pvBuffer;
770
771 size_t cchInfo = 0;
772 rc = RTStrNLenEx(pFeature->achInfo, cbInfo, &cchInfo);
773
774 if (RT_FAILURE(rc))
775 {
776 rc = VERR_INVALID_PARAMETER;
777 break;
778 }
779
780 Log(("VRDE_QP_FEATURE [%s]\n", pFeature->achInfo));
781
782 com::Bstr bstrValue;
783
784 if ( RTStrICmp(pFeature->achInfo, "Client/DisableDisplay") == 0
785 || RTStrICmp(pFeature->achInfo, "Client/DisableInput") == 0
786 || RTStrICmp(pFeature->achInfo, "Client/DisableAudio") == 0
787 || RTStrICmp(pFeature->achInfo, "Client/DisableUSB") == 0
788 || RTStrICmp(pFeature->achInfo, "Client/DisableClipboard") == 0
789 )
790 {
791 /* @todo these features should be per client. */
792 NOREF(pFeature->u32ClientId);
793
794 /* These features are mapped to "VRDE/Feature/NAME" extra data. */
795 com::Utf8Str extraData("VRDE/Feature/");
796 extraData += pFeature->achInfo;
797
798 HRESULT hrc = server->mConsole->i_machine()->GetExtraData(com::Bstr(extraData).raw(),
799 bstrValue.asOutParam());
800 if (FAILED(hrc) || bstrValue.isEmpty())
801 {
802 /* Also try the old "VRDP/Feature/NAME" */
803 extraData = "VRDP/Feature/";
804 extraData += pFeature->achInfo;
805
806 hrc = server->mConsole->i_machine()->GetExtraData(com::Bstr(extraData).raw(),
807 bstrValue.asOutParam());
808 if (FAILED(hrc))
809 {
810 rc = VERR_NOT_SUPPORTED;
811 }
812 }
813 }
814 else if (RTStrNCmp(pFeature->achInfo, "Property/", 9) == 0)
815 {
816 /* Generic properties. */
817 const char *pszPropertyName = &pFeature->achInfo[9];
818 HRESULT hrc = server->mConsole->i_getVRDEServer()->GetVRDEProperty(Bstr(pszPropertyName).raw(),
819 bstrValue.asOutParam());
820 if (FAILED(hrc))
821 {
822 rc = VERR_NOT_SUPPORTED;
823 }
824 }
825 else
826 {
827 rc = VERR_NOT_SUPPORTED;
828 }
829
830 /* Copy the value string to the callers buffer. */
831 if (rc == VINF_SUCCESS)
832 {
833 com::Utf8Str value = bstrValue;
834
835 size_t cb = value.length() + 1;
836
837 if ((size_t)cbInfo >= cb)
838 {
839 memcpy(pFeature->achInfo, value.c_str(), cb);
840 }
841 else
842 {
843 rc = VINF_BUFFER_OVERFLOW;
844 }
845
846 *pcbOut = (uint32_t)cb;
847 }
848 } break;
849
850 case VRDE_SP_NETWORK_BIND_PORT:
851 {
852 if (cbBuffer != sizeof(uint32_t))
853 {
854 rc = VERR_INVALID_PARAMETER;
855 break;
856 }
857
858 ULONG port = *(uint32_t *)pvBuffer;
859
860 server->mVRDPBindPort = port;
861
862 rc = VINF_SUCCESS;
863
864 if (pcbOut)
865 {
866 *pcbOut = sizeof(uint32_t);
867 }
868
869 server->mConsole->i_onVRDEServerInfoChange();
870 } break;
871
872 case VRDE_SP_CLIENT_STATUS:
873 {
874 if (cbBuffer < sizeof(VRDECLIENTSTATUS))
875 {
876 rc = VERR_INVALID_PARAMETER;
877 break;
878 }
879
880 size_t cbStatus = cbBuffer - RT_UOFFSETOF(VRDECLIENTSTATUS, achStatus);
881
882 VRDECLIENTSTATUS *pStatus = (VRDECLIENTSTATUS *)pvBuffer;
883
884 if (cbBuffer < RT_UOFFSETOF(VRDECLIENTSTATUS, achStatus) + pStatus->cbStatus)
885 {
886 rc = VERR_INVALID_PARAMETER;
887 break;
888 }
889
890 size_t cchStatus = 0;
891 rc = RTStrNLenEx(pStatus->achStatus, cbStatus, &cchStatus);
892
893 if (RT_FAILURE(rc))
894 {
895 rc = VERR_INVALID_PARAMETER;
896 break;
897 }
898
899 Log(("VRDE_SP_CLIENT_STATUS [%s]\n", pStatus->achStatus));
900
901 server->mConsole->i_VRDPClientStatusChange(pStatus->u32ClientId, pStatus->achStatus);
902
903 rc = VINF_SUCCESS;
904
905 if (pcbOut)
906 {
907 *pcbOut = cbBuffer;
908 }
909
910 server->mConsole->i_onVRDEServerInfoChange();
911 } break;
912
913 default:
914 break;
915 }
916
917 return rc;
918}
919
920DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClientLogon(void *pvCallback, uint32_t u32ClientId, const char *pszUser,
921 const char *pszPassword, const char *pszDomain)
922{
923 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
924
925 return server->mConsole->i_VRDPClientLogon(u32ClientId, pszUser, pszPassword, pszDomain);
926}
927
928DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientConnect(void *pvCallback, uint32_t u32ClientId)
929{
930 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
931
932 server->mConsole->i_VRDPClientConnect(u32ClientId);
933
934 /* Should the server report usage of an interface for each client?
935 * Similar to Intercept.
936 */
937 int c = ASMAtomicIncS32(&server->mcClients);
938 if (c == 1)
939 {
940 /* Features which should be enabled only if there is a client. */
941 server->remote3DRedirect(true);
942 }
943}
944
945DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientDisconnect(void *pvCallback, uint32_t u32ClientId,
946 uint32_t fu32Intercepted)
947{
948 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
949
950 server->mConsole->i_VRDPClientDisconnect(u32ClientId, fu32Intercepted);
951
952 if (ASMAtomicReadU32(&server->mu32AudioInputClientId) == u32ClientId)
953 {
954 Log(("AUDIOIN: disconnected client %u\n", u32ClientId));
955 ASMAtomicWriteU32(&server->mu32AudioInputClientId, 0);
956
957#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
958 server->mConsole->getAudioVRDE()->handleVRDESvrCmdAudioInputIntercept(false);
959#else
960 PPDMIAUDIOSNIFFERPORT pPort = server->mConsole->i_getAudioSniffer()->getAudioSnifferPort();
961 if (pPort)
962 {
963 pPort->pfnAudioInputIntercept(pPort, false);
964 }
965 else
966 {
967 AssertFailed();
968 }
969#endif
970 }
971
972 int c = ASMAtomicDecS32(&server->mcClients);
973 if (c == 0)
974 {
975 /* Features which should be enabled only if there is a client. */
976 server->remote3DRedirect(false);
977 }
978}
979
980DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackIntercept(void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercept,
981 void **ppvIntercept)
982{
983 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
984
985 LogFlowFunc(("%x\n", fu32Intercept));
986
987 int rc = VERR_NOT_SUPPORTED;
988
989 switch (fu32Intercept)
990 {
991 case VRDE_CLIENT_INTERCEPT_AUDIO:
992 {
993 server->mConsole->i_VRDPInterceptAudio(u32ClientId);
994 if (ppvIntercept)
995 {
996 *ppvIntercept = server;
997 }
998 rc = VINF_SUCCESS;
999 } break;
1000
1001 case VRDE_CLIENT_INTERCEPT_USB:
1002 {
1003 server->mConsole->i_VRDPInterceptUSB(u32ClientId, ppvIntercept);
1004 rc = VINF_SUCCESS;
1005 } break;
1006
1007 case VRDE_CLIENT_INTERCEPT_CLIPBOARD:
1008 {
1009 server->mConsole->i_VRDPInterceptClipboard(u32ClientId);
1010 if (ppvIntercept)
1011 {
1012 *ppvIntercept = server;
1013 }
1014 rc = VINF_SUCCESS;
1015 } break;
1016
1017 case VRDE_CLIENT_INTERCEPT_AUDIO_INPUT:
1018 {
1019 /* This request is processed internally by the ConsoleVRDPServer.
1020 * Only one client is allowed to intercept audio input.
1021 */
1022 if (ASMAtomicCmpXchgU32(&server->mu32AudioInputClientId, u32ClientId, 0) == true)
1023 {
1024 Log(("AUDIOIN: connected client %u\n", u32ClientId));
1025#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1026 server->mConsole->getAudioVRDE()->handleVRDESvrCmdAudioInputIntercept(true);
1027#else
1028 PPDMIAUDIOSNIFFERPORT pPort = server->mConsole->i_getAudioSniffer()->getAudioSnifferPort();
1029 if (pPort)
1030 {
1031 pPort->pfnAudioInputIntercept(pPort, true);
1032 if (ppvIntercept)
1033 {
1034 *ppvIntercept = server;
1035 }
1036 }
1037 else
1038 {
1039 AssertFailed();
1040 ASMAtomicWriteU32(&server->mu32AudioInputClientId, 0);
1041 rc = VERR_NOT_SUPPORTED;
1042 }
1043#endif
1044 }
1045 else
1046 {
1047 Log(("AUDIOIN: ignored client %u, active client %u\n", u32ClientId, server->mu32AudioInputClientId));
1048 rc = VERR_NOT_SUPPORTED;
1049 }
1050 } break;
1051
1052 default:
1053 break;
1054 }
1055
1056 return rc;
1057}
1058
1059DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackUSB(void *pvCallback, void *pvIntercept, uint32_t u32ClientId,
1060 uint8_t u8Code, const void *pvRet, uint32_t cbRet)
1061{
1062#ifdef VBOX_WITH_USB
1063 return USBClientResponseCallback(pvIntercept, u32ClientId, u8Code, pvRet, cbRet);
1064#else
1065 return VERR_NOT_SUPPORTED;
1066#endif
1067}
1068
1069DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClipboard(void *pvCallback, void *pvIntercept, uint32_t u32ClientId,
1070 uint32_t u32Function, uint32_t u32Format,
1071 const void *pvData, uint32_t cbData)
1072{
1073 return ClipboardCallback(pvIntercept, u32ClientId, u32Function, u32Format, pvData, cbData);
1074}
1075
1076DECLCALLBACK(bool) ConsoleVRDPServer::VRDPCallbackFramebufferQuery(void *pvCallback, unsigned uScreenId,
1077 VRDEFRAMEBUFFERINFO *pInfo)
1078{
1079 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1080
1081 bool fAvailable = false;
1082
1083 /* Obtain the new screen bitmap. */
1084 HRESULT hr = server->mConsole->i_getDisplay()->QuerySourceBitmap(uScreenId, server->maSourceBitmaps[uScreenId].asOutParam());
1085 if (SUCCEEDED(hr))
1086 {
1087 LONG xOrigin = 0;
1088 LONG yOrigin = 0;
1089 BYTE *pAddress = NULL;
1090 ULONG ulWidth = 0;
1091 ULONG ulHeight = 0;
1092 ULONG ulBitsPerPixel = 0;
1093 ULONG ulBytesPerLine = 0;
1094 ULONG ulPixelFormat = 0;
1095
1096 hr = server->maSourceBitmaps[uScreenId]->QueryBitmapInfo(&pAddress,
1097 &ulWidth,
1098 &ulHeight,
1099 &ulBitsPerPixel,
1100 &ulBytesPerLine,
1101 &ulPixelFormat);
1102
1103 if (SUCCEEDED(hr))
1104 {
1105 ULONG dummy;
1106 GuestMonitorStatus_T monitorStatus;
1107 hr = server->mConsole->i_getDisplay()->GetScreenResolution(uScreenId, &dummy, &dummy, &dummy,
1108 &xOrigin, &yOrigin, &monitorStatus);
1109
1110 if (SUCCEEDED(hr))
1111 {
1112 /* Now fill the information as requested by the caller. */
1113 pInfo->pu8Bits = pAddress;
1114 pInfo->xOrigin = xOrigin;
1115 pInfo->yOrigin = yOrigin;
1116 pInfo->cWidth = ulWidth;
1117 pInfo->cHeight = ulHeight;
1118 pInfo->cBitsPerPixel = ulBitsPerPixel;
1119 pInfo->cbLine = ulBytesPerLine;
1120
1121 fAvailable = true;
1122 }
1123 }
1124 }
1125
1126 return fAvailable;
1127}
1128
1129DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferLock(void *pvCallback, unsigned uScreenId)
1130{
1131 NOREF(pvCallback);
1132 NOREF(uScreenId);
1133 /* Do nothing */
1134}
1135
1136DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferUnlock(void *pvCallback, unsigned uScreenId)
1137{
1138 NOREF(pvCallback);
1139 NOREF(uScreenId);
1140 /* Do nothing */
1141}
1142
1143static void fixKbdLockStatus(VRDPInputSynch *pInputSynch, IKeyboard *pKeyboard)
1144{
1145 if ( pInputSynch->cGuestNumLockAdaptions
1146 && (pInputSynch->fGuestNumLock != pInputSynch->fClientNumLock))
1147 {
1148 pInputSynch->cGuestNumLockAdaptions--;
1149 pKeyboard->PutScancode(0x45);
1150 pKeyboard->PutScancode(0x45 | 0x80);
1151 }
1152 if ( pInputSynch->cGuestCapsLockAdaptions
1153 && (pInputSynch->fGuestCapsLock != pInputSynch->fClientCapsLock))
1154 {
1155 pInputSynch->cGuestCapsLockAdaptions--;
1156 pKeyboard->PutScancode(0x3a);
1157 pKeyboard->PutScancode(0x3a | 0x80);
1158 }
1159}
1160
1161DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackInput(void *pvCallback, int type, const void *pvInput, unsigned cbInput)
1162{
1163 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1164 Console *pConsole = server->mConsole;
1165
1166 switch (type)
1167 {
1168 case VRDE_INPUT_SCANCODE:
1169 {
1170 if (cbInput == sizeof(VRDEINPUTSCANCODE))
1171 {
1172 IKeyboard *pKeyboard = pConsole->i_getKeyboard();
1173
1174 const VRDEINPUTSCANCODE *pInputScancode = (VRDEINPUTSCANCODE *)pvInput;
1175
1176 /* Track lock keys. */
1177 if (pInputScancode->uScancode == 0x45)
1178 {
1179 server->m_InputSynch.fClientNumLock = !server->m_InputSynch.fClientNumLock;
1180 }
1181 else if (pInputScancode->uScancode == 0x3a)
1182 {
1183 server->m_InputSynch.fClientCapsLock = !server->m_InputSynch.fClientCapsLock;
1184 }
1185 else if (pInputScancode->uScancode == 0x46)
1186 {
1187 server->m_InputSynch.fClientScrollLock = !server->m_InputSynch.fClientScrollLock;
1188 }
1189 else if ((pInputScancode->uScancode & 0x80) == 0)
1190 {
1191 /* Key pressed. */
1192 fixKbdLockStatus(&server->m_InputSynch, pKeyboard);
1193 }
1194
1195 pKeyboard->PutScancode((LONG)pInputScancode->uScancode);
1196 }
1197 } break;
1198
1199 case VRDE_INPUT_POINT:
1200 {
1201 if (cbInput == sizeof(VRDEINPUTPOINT))
1202 {
1203 const VRDEINPUTPOINT *pInputPoint = (VRDEINPUTPOINT *)pvInput;
1204
1205 int mouseButtons = 0;
1206 int iWheel = 0;
1207
1208 if (pInputPoint->uButtons & VRDE_INPUT_POINT_BUTTON1)
1209 {
1210 mouseButtons |= MouseButtonState_LeftButton;
1211 }
1212 if (pInputPoint->uButtons & VRDE_INPUT_POINT_BUTTON2)
1213 {
1214 mouseButtons |= MouseButtonState_RightButton;
1215 }
1216 if (pInputPoint->uButtons & VRDE_INPUT_POINT_BUTTON3)
1217 {
1218 mouseButtons |= MouseButtonState_MiddleButton;
1219 }
1220 if (pInputPoint->uButtons & VRDE_INPUT_POINT_WHEEL_UP)
1221 {
1222 mouseButtons |= MouseButtonState_WheelUp;
1223 iWheel = -1;
1224 }
1225 if (pInputPoint->uButtons & VRDE_INPUT_POINT_WHEEL_DOWN)
1226 {
1227 mouseButtons |= MouseButtonState_WheelDown;
1228 iWheel = 1;
1229 }
1230
1231 if (server->m_fGuestWantsAbsolute)
1232 {
1233 pConsole->i_getMouse()->PutMouseEventAbsolute(pInputPoint->x + 1, pInputPoint->y + 1, iWheel,
1234 0 /* Horizontal wheel */, mouseButtons);
1235 } else
1236 {
1237 pConsole->i_getMouse()->PutMouseEvent(pInputPoint->x - server->m_mousex,
1238 pInputPoint->y - server->m_mousey,
1239 iWheel, 0 /* Horizontal wheel */, mouseButtons);
1240 server->m_mousex = pInputPoint->x;
1241 server->m_mousey = pInputPoint->y;
1242 }
1243 }
1244 } break;
1245
1246 case VRDE_INPUT_CAD:
1247 {
1248 pConsole->i_getKeyboard()->PutCAD();
1249 } break;
1250
1251 case VRDE_INPUT_RESET:
1252 {
1253 pConsole->Reset();
1254 } break;
1255
1256 case VRDE_INPUT_SYNCH:
1257 {
1258 if (cbInput == sizeof(VRDEINPUTSYNCH))
1259 {
1260 IKeyboard *pKeyboard = pConsole->i_getKeyboard();
1261
1262 const VRDEINPUTSYNCH *pInputSynch = (VRDEINPUTSYNCH *)pvInput;
1263
1264 server->m_InputSynch.fClientNumLock = (pInputSynch->uLockStatus & VRDE_INPUT_SYNCH_NUMLOCK) != 0;
1265 server->m_InputSynch.fClientCapsLock = (pInputSynch->uLockStatus & VRDE_INPUT_SYNCH_CAPITAL) != 0;
1266 server->m_InputSynch.fClientScrollLock = (pInputSynch->uLockStatus & VRDE_INPUT_SYNCH_SCROLL) != 0;
1267
1268 /* The client initiated synchronization. Always make the guest to reflect the client state.
1269 * Than means, when the guest changes the state itself, it is forced to return to the client
1270 * state.
1271 */
1272 if (server->m_InputSynch.fClientNumLock != server->m_InputSynch.fGuestNumLock)
1273 {
1274 server->m_InputSynch.cGuestNumLockAdaptions = 2;
1275 }
1276
1277 if (server->m_InputSynch.fClientCapsLock != server->m_InputSynch.fGuestCapsLock)
1278 {
1279 server->m_InputSynch.cGuestCapsLockAdaptions = 2;
1280 }
1281
1282 fixKbdLockStatus(&server->m_InputSynch, pKeyboard);
1283 }
1284 } break;
1285
1286 default:
1287 break;
1288 }
1289}
1290
1291DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackVideoModeHint(void *pvCallback, unsigned cWidth, unsigned cHeight,
1292 unsigned cBitsPerPixel, unsigned uScreenId)
1293{
1294 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1295
1296 server->mConsole->i_getDisplay()->SetVideoModeHint(uScreenId, TRUE /*=enabled*/,
1297 FALSE /*=changeOrigin*/, 0/*=OriginX*/, 0/*=OriginY*/,
1298 cWidth, cHeight, cBitsPerPixel);
1299}
1300
1301DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackAudioIn(void *pvCallback,
1302 void *pvCtx,
1303 uint32_t u32ClientId,
1304 uint32_t u32Event,
1305 const void *pvData,
1306 uint32_t cbData)
1307{
1308 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1309#ifndef VBOX_WITH_PDM_AUDIO_DRIVER
1310 PPDMIAUDIOSNIFFERPORT pPort = server->mConsole->i_getAudioSniffer()->getAudioSnifferPort();
1311#endif
1312
1313 switch (u32Event)
1314 {
1315 case VRDE_AUDIOIN_BEGIN:
1316 {
1317 const VRDEAUDIOINBEGIN *pParms = (const VRDEAUDIOINBEGIN *)pvData;
1318#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1319 server->mConsole->getAudioVRDE()->handleVRDESvrCmdAudioInputEventBegin(pvCtx,
1320 VRDE_AUDIO_FMT_SAMPLE_FREQ(pParms->fmt),
1321 VRDE_AUDIO_FMT_CHANNELS(pParms->fmt),
1322 VRDE_AUDIO_FMT_BITS_PER_SAMPLE(pParms->fmt),
1323 VRDE_AUDIO_FMT_SIGNED(pParms->fmt)
1324 );
1325#else
1326 pPort->pfnAudioInputEventBegin (pPort, pvCtx,
1327 VRDE_AUDIO_FMT_SAMPLE_FREQ(pParms->fmt),
1328 VRDE_AUDIO_FMT_CHANNELS(pParms->fmt),
1329 VRDE_AUDIO_FMT_BITS_PER_SAMPLE(pParms->fmt),
1330 VRDE_AUDIO_FMT_SIGNED(pParms->fmt)
1331 );
1332#endif
1333 } break;
1334
1335 case VRDE_AUDIOIN_DATA:
1336 {
1337#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1338 server->mConsole->getAudioVRDE()->handleVRDESvrCmdAudioInputEventData(pvCtx, pvData, cbData);
1339#else
1340 pPort->pfnAudioInputEventData (pPort, pvCtx, pvData, cbData);
1341#endif
1342 } break;
1343
1344 case VRDE_AUDIOIN_END:
1345 {
1346#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1347 server->mConsole->getAudioVRDE()->handleVRDESvrCmdAudioInputEventEnd(pvCtx);
1348#else
1349 pPort->pfnAudioInputEventEnd (pPort, pvCtx);
1350#endif
1351 } break;
1352
1353 default:
1354 return;
1355 }
1356}
1357
1358
1359ConsoleVRDPServer::ConsoleVRDPServer(Console *console)
1360{
1361 mConsole = console;
1362
1363 int rc = RTCritSectInit(&mCritSect);
1364 AssertRC(rc);
1365
1366 mcClipboardRefs = 0;
1367 mpfnClipboardCallback = NULL;
1368#ifdef VBOX_WITH_USB
1369 mUSBBackends.pHead = NULL;
1370 mUSBBackends.pTail = NULL;
1371
1372 mUSBBackends.thread = NIL_RTTHREAD;
1373 mUSBBackends.fThreadRunning = false;
1374 mUSBBackends.event = 0;
1375#endif
1376
1377 mhServer = 0;
1378 mServerInterfaceVersion = 0;
1379
1380 mcInResize = 0;
1381
1382 m_fGuestWantsAbsolute = false;
1383 m_mousex = 0;
1384 m_mousey = 0;
1385
1386 m_InputSynch.cGuestNumLockAdaptions = 2;
1387 m_InputSynch.cGuestCapsLockAdaptions = 2;
1388
1389 m_InputSynch.fGuestNumLock = false;
1390 m_InputSynch.fGuestCapsLock = false;
1391 m_InputSynch.fGuestScrollLock = false;
1392
1393 m_InputSynch.fClientNumLock = false;
1394 m_InputSynch.fClientCapsLock = false;
1395 m_InputSynch.fClientScrollLock = false;
1396
1397 {
1398 ComPtr<IEventSource> es;
1399 console->COMGETTER(EventSource)(es.asOutParam());
1400 ComObjPtr<VRDPConsoleListenerImpl> aConsoleListener;
1401 aConsoleListener.createObject();
1402 aConsoleListener->init(new VRDPConsoleListener(), this);
1403 mConsoleListener = aConsoleListener;
1404 com::SafeArray <VBoxEventType_T> eventTypes;
1405 eventTypes.push_back(VBoxEventType_OnMousePointerShapeChanged);
1406 eventTypes.push_back(VBoxEventType_OnMouseCapabilityChanged);
1407 eventTypes.push_back(VBoxEventType_OnKeyboardLedsChanged);
1408 es->RegisterListener(mConsoleListener, ComSafeArrayAsInParam(eventTypes), true);
1409 }
1410
1411 mVRDPBindPort = -1;
1412
1413 mAuthLibrary = 0;
1414
1415 mu32AudioInputClientId = 0;
1416 mcClients = 0;
1417
1418 /*
1419 * Optional interfaces.
1420 */
1421 m_fInterfaceImage = false;
1422 RT_ZERO(m_interfaceImage);
1423 RT_ZERO(m_interfaceCallbacksImage);
1424 RT_ZERO(m_interfaceMousePtr);
1425 RT_ZERO(m_interfaceSCard);
1426 RT_ZERO(m_interfaceCallbacksSCard);
1427 RT_ZERO(m_interfaceTSMF);
1428 RT_ZERO(m_interfaceCallbacksTSMF);
1429 RT_ZERO(m_interfaceVideoIn);
1430 RT_ZERO(m_interfaceCallbacksVideoIn);
1431 RT_ZERO(m_interfaceInput);
1432 RT_ZERO(m_interfaceCallbacksInput);
1433
1434 rc = RTCritSectInit(&mTSMFLock);
1435 AssertRC(rc);
1436
1437 mEmWebcam = new EmWebcam(this);
1438 AssertPtr(mEmWebcam);
1439}
1440
1441ConsoleVRDPServer::~ConsoleVRDPServer()
1442{
1443 Stop();
1444
1445 if (mConsoleListener)
1446 {
1447 ComPtr<IEventSource> es;
1448 mConsole->COMGETTER(EventSource)(es.asOutParam());
1449 es->UnregisterListener(mConsoleListener);
1450 mConsoleListener.setNull();
1451 }
1452
1453 unsigned i;
1454 for (i = 0; i < RT_ELEMENTS(maSourceBitmaps); i++)
1455 {
1456 maSourceBitmaps[i].setNull();
1457 }
1458
1459 if (mEmWebcam)
1460 {
1461 delete mEmWebcam;
1462 mEmWebcam = NULL;
1463 }
1464
1465 if (RTCritSectIsInitialized(&mCritSect))
1466 {
1467 RTCritSectDelete(&mCritSect);
1468 RT_ZERO(mCritSect);
1469 }
1470
1471 if (RTCritSectIsInitialized(&mTSMFLock))
1472 {
1473 RTCritSectDelete(&mTSMFLock);
1474 RT_ZERO(mTSMFLock);
1475 }
1476}
1477
1478int ConsoleVRDPServer::Launch(void)
1479{
1480 LogFlowThisFunc(("\n"));
1481
1482 IVRDEServer *server = mConsole->i_getVRDEServer();
1483 AssertReturn(server, VERR_INTERNAL_ERROR_2);
1484
1485 /*
1486 * Check if VRDE is enabled.
1487 */
1488 BOOL fEnabled;
1489 HRESULT hrc = server->COMGETTER(Enabled)(&fEnabled);
1490 AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));
1491 if (!fEnabled)
1492 return VINF_SUCCESS;
1493
1494 /*
1495 * Check that a VRDE extension pack name is set and resolve it into a
1496 * library path.
1497 */
1498 Bstr bstrExtPack;
1499 hrc = server->COMGETTER(VRDEExtPack)(bstrExtPack.asOutParam());
1500 if (FAILED(hrc))
1501 return Global::vboxStatusCodeFromCOM(hrc);
1502 if (bstrExtPack.isEmpty())
1503 return VINF_NOT_SUPPORTED;
1504
1505 Utf8Str strExtPack(bstrExtPack);
1506 Utf8Str strVrdeLibrary;
1507 int vrc = VINF_SUCCESS;
1508 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
1509 strVrdeLibrary = "VBoxVRDP";
1510 else
1511 {
1512#ifdef VBOX_WITH_EXTPACK
1513 ExtPackManager *pExtPackMgr = mConsole->i_getExtPackManager();
1514 vrc = pExtPackMgr->i_getVrdeLibraryPathForExtPack(&strExtPack, &strVrdeLibrary);
1515#else
1516 vrc = VERR_FILE_NOT_FOUND;
1517#endif
1518 }
1519 if (RT_SUCCESS(vrc))
1520 {
1521 /*
1522 * Load the VRDE library and start the server, if it is enabled.
1523 */
1524 vrc = loadVRDPLibrary(strVrdeLibrary.c_str());
1525 if (RT_SUCCESS(vrc))
1526 {
1527 VRDEENTRYPOINTS_4 *pEntryPoints4;
1528 vrc = mpfnVRDECreateServer(&mCallbacks.header, this, (VRDEINTERFACEHDR **)&pEntryPoints4, &mhServer);
1529
1530 if (RT_SUCCESS(vrc))
1531 {
1532 mServerInterfaceVersion = 4;
1533 mEntryPoints = *pEntryPoints4;
1534 mpEntryPoints = &mEntryPoints;
1535 }
1536 else if (vrc == VERR_VERSION_MISMATCH)
1537 {
1538 /* An older version of VRDE is installed, try version 3. */
1539 VRDEENTRYPOINTS_3 *pEntryPoints3;
1540
1541 static VRDECALLBACKS_3 sCallbacks3 =
1542 {
1543 { VRDE_INTERFACE_VERSION_3, sizeof(VRDECALLBACKS_3) },
1544 ConsoleVRDPServer::VRDPCallbackQueryProperty,
1545 ConsoleVRDPServer::VRDPCallbackClientLogon,
1546 ConsoleVRDPServer::VRDPCallbackClientConnect,
1547 ConsoleVRDPServer::VRDPCallbackClientDisconnect,
1548 ConsoleVRDPServer::VRDPCallbackIntercept,
1549 ConsoleVRDPServer::VRDPCallbackUSB,
1550 ConsoleVRDPServer::VRDPCallbackClipboard,
1551 ConsoleVRDPServer::VRDPCallbackFramebufferQuery,
1552 ConsoleVRDPServer::VRDPCallbackFramebufferLock,
1553 ConsoleVRDPServer::VRDPCallbackFramebufferUnlock,
1554 ConsoleVRDPServer::VRDPCallbackInput,
1555 ConsoleVRDPServer::VRDPCallbackVideoModeHint,
1556 ConsoleVRDPServer::VRDECallbackAudioIn
1557 };
1558
1559 vrc = mpfnVRDECreateServer(&sCallbacks3.header, this, (VRDEINTERFACEHDR **)&pEntryPoints3, &mhServer);
1560 if (RT_SUCCESS(vrc))
1561 {
1562 mServerInterfaceVersion = 3;
1563 mEntryPoints.header = pEntryPoints3->header;
1564 mEntryPoints.VRDEDestroy = pEntryPoints3->VRDEDestroy;
1565 mEntryPoints.VRDEEnableConnections = pEntryPoints3->VRDEEnableConnections;
1566 mEntryPoints.VRDEDisconnect = pEntryPoints3->VRDEDisconnect;
1567 mEntryPoints.VRDEResize = pEntryPoints3->VRDEResize;
1568 mEntryPoints.VRDEUpdate = pEntryPoints3->VRDEUpdate;
1569 mEntryPoints.VRDEColorPointer = pEntryPoints3->VRDEColorPointer;
1570 mEntryPoints.VRDEHidePointer = pEntryPoints3->VRDEHidePointer;
1571 mEntryPoints.VRDEAudioSamples = pEntryPoints3->VRDEAudioSamples;
1572 mEntryPoints.VRDEAudioVolume = pEntryPoints3->VRDEAudioVolume;
1573 mEntryPoints.VRDEUSBRequest = pEntryPoints3->VRDEUSBRequest;
1574 mEntryPoints.VRDEClipboard = pEntryPoints3->VRDEClipboard;
1575 mEntryPoints.VRDEQueryInfo = pEntryPoints3->VRDEQueryInfo;
1576 mEntryPoints.VRDERedirect = pEntryPoints3->VRDERedirect;
1577 mEntryPoints.VRDEAudioInOpen = pEntryPoints3->VRDEAudioInOpen;
1578 mEntryPoints.VRDEAudioInClose = pEntryPoints3->VRDEAudioInClose;
1579 mEntryPoints.VRDEGetInterface = NULL;
1580 mpEntryPoints = &mEntryPoints;
1581 }
1582 else if (vrc == VERR_VERSION_MISMATCH)
1583 {
1584 /* An older version of VRDE is installed, try version 1. */
1585 VRDEENTRYPOINTS_1 *pEntryPoints1;
1586
1587 static VRDECALLBACKS_1 sCallbacks1 =
1588 {
1589 { VRDE_INTERFACE_VERSION_1, sizeof(VRDECALLBACKS_1) },
1590 ConsoleVRDPServer::VRDPCallbackQueryProperty,
1591 ConsoleVRDPServer::VRDPCallbackClientLogon,
1592 ConsoleVRDPServer::VRDPCallbackClientConnect,
1593 ConsoleVRDPServer::VRDPCallbackClientDisconnect,
1594 ConsoleVRDPServer::VRDPCallbackIntercept,
1595 ConsoleVRDPServer::VRDPCallbackUSB,
1596 ConsoleVRDPServer::VRDPCallbackClipboard,
1597 ConsoleVRDPServer::VRDPCallbackFramebufferQuery,
1598 ConsoleVRDPServer::VRDPCallbackFramebufferLock,
1599 ConsoleVRDPServer::VRDPCallbackFramebufferUnlock,
1600 ConsoleVRDPServer::VRDPCallbackInput,
1601 ConsoleVRDPServer::VRDPCallbackVideoModeHint
1602 };
1603
1604 vrc = mpfnVRDECreateServer(&sCallbacks1.header, this, (VRDEINTERFACEHDR **)&pEntryPoints1, &mhServer);
1605 if (RT_SUCCESS(vrc))
1606 {
1607 mServerInterfaceVersion = 1;
1608 mEntryPoints.header = pEntryPoints1->header;
1609 mEntryPoints.VRDEDestroy = pEntryPoints1->VRDEDestroy;
1610 mEntryPoints.VRDEEnableConnections = pEntryPoints1->VRDEEnableConnections;
1611 mEntryPoints.VRDEDisconnect = pEntryPoints1->VRDEDisconnect;
1612 mEntryPoints.VRDEResize = pEntryPoints1->VRDEResize;
1613 mEntryPoints.VRDEUpdate = pEntryPoints1->VRDEUpdate;
1614 mEntryPoints.VRDEColorPointer = pEntryPoints1->VRDEColorPointer;
1615 mEntryPoints.VRDEHidePointer = pEntryPoints1->VRDEHidePointer;
1616 mEntryPoints.VRDEAudioSamples = pEntryPoints1->VRDEAudioSamples;
1617 mEntryPoints.VRDEAudioVolume = pEntryPoints1->VRDEAudioVolume;
1618 mEntryPoints.VRDEUSBRequest = pEntryPoints1->VRDEUSBRequest;
1619 mEntryPoints.VRDEClipboard = pEntryPoints1->VRDEClipboard;
1620 mEntryPoints.VRDEQueryInfo = pEntryPoints1->VRDEQueryInfo;
1621 mEntryPoints.VRDERedirect = NULL;
1622 mEntryPoints.VRDEAudioInOpen = NULL;
1623 mEntryPoints.VRDEAudioInClose = NULL;
1624 mEntryPoints.VRDEGetInterface = NULL;
1625 mpEntryPoints = &mEntryPoints;
1626 }
1627 }
1628 }
1629
1630 if (RT_SUCCESS(vrc))
1631 {
1632 LogRel(("VRDE: loaded version %d of the server.\n", mServerInterfaceVersion));
1633
1634 if (mServerInterfaceVersion >= 4)
1635 {
1636 /* The server supports optional interfaces. */
1637 Assert(mpEntryPoints->VRDEGetInterface != NULL);
1638
1639 /* Image interface. */
1640 m_interfaceImage.header.u64Version = 1;
1641 m_interfaceImage.header.u64Size = sizeof(m_interfaceImage);
1642
1643 m_interfaceCallbacksImage.header.u64Version = 1;
1644 m_interfaceCallbacksImage.header.u64Size = sizeof(m_interfaceCallbacksImage);
1645 m_interfaceCallbacksImage.VRDEImageCbNotify = VRDEImageCbNotify;
1646
1647 vrc = mpEntryPoints->VRDEGetInterface(mhServer,
1648 VRDE_IMAGE_INTERFACE_NAME,
1649 &m_interfaceImage.header,
1650 &m_interfaceCallbacksImage.header,
1651 this);
1652 if (RT_SUCCESS(vrc))
1653 {
1654 LogRel(("VRDE: [%s]\n", VRDE_IMAGE_INTERFACE_NAME));
1655 m_fInterfaceImage = true;
1656 }
1657
1658 /* Mouse pointer interface. */
1659 m_interfaceMousePtr.header.u64Version = 1;
1660 m_interfaceMousePtr.header.u64Size = sizeof(m_interfaceMousePtr);
1661
1662 vrc = mpEntryPoints->VRDEGetInterface(mhServer,
1663 VRDE_MOUSEPTR_INTERFACE_NAME,
1664 &m_interfaceMousePtr.header,
1665 NULL,
1666 this);
1667 if (RT_SUCCESS(vrc))
1668 {
1669 LogRel(("VRDE: [%s]\n", VRDE_MOUSEPTR_INTERFACE_NAME));
1670 }
1671 else
1672 {
1673 RT_ZERO(m_interfaceMousePtr);
1674 }
1675
1676 /* Smartcard interface. */
1677 m_interfaceSCard.header.u64Version = 1;
1678 m_interfaceSCard.header.u64Size = sizeof(m_interfaceSCard);
1679
1680 m_interfaceCallbacksSCard.header.u64Version = 1;
1681 m_interfaceCallbacksSCard.header.u64Size = sizeof(m_interfaceCallbacksSCard);
1682 m_interfaceCallbacksSCard.VRDESCardCbNotify = VRDESCardCbNotify;
1683 m_interfaceCallbacksSCard.VRDESCardCbResponse = VRDESCardCbResponse;
1684
1685 vrc = mpEntryPoints->VRDEGetInterface(mhServer,
1686 VRDE_SCARD_INTERFACE_NAME,
1687 &m_interfaceSCard.header,
1688 &m_interfaceCallbacksSCard.header,
1689 this);
1690 if (RT_SUCCESS(vrc))
1691 {
1692 LogRel(("VRDE: [%s]\n", VRDE_SCARD_INTERFACE_NAME));
1693 }
1694 else
1695 {
1696 RT_ZERO(m_interfaceSCard);
1697 }
1698
1699 /* Raw TSMF interface. */
1700 m_interfaceTSMF.header.u64Version = 1;
1701 m_interfaceTSMF.header.u64Size = sizeof(m_interfaceTSMF);
1702
1703 m_interfaceCallbacksTSMF.header.u64Version = 1;
1704 m_interfaceCallbacksTSMF.header.u64Size = sizeof(m_interfaceCallbacksTSMF);
1705 m_interfaceCallbacksTSMF.VRDETSMFCbNotify = VRDETSMFCbNotify;
1706
1707 vrc = mpEntryPoints->VRDEGetInterface(mhServer,
1708 VRDE_TSMF_INTERFACE_NAME,
1709 &m_interfaceTSMF.header,
1710 &m_interfaceCallbacksTSMF.header,
1711 this);
1712 if (RT_SUCCESS(vrc))
1713 {
1714 LogRel(("VRDE: [%s]\n", VRDE_TSMF_INTERFACE_NAME));
1715 }
1716 else
1717 {
1718 RT_ZERO(m_interfaceTSMF);
1719 }
1720
1721 /* VideoIn interface. */
1722 m_interfaceVideoIn.header.u64Version = 1;
1723 m_interfaceVideoIn.header.u64Size = sizeof(m_interfaceVideoIn);
1724
1725 m_interfaceCallbacksVideoIn.header.u64Version = 1;
1726 m_interfaceCallbacksVideoIn.header.u64Size = sizeof(m_interfaceCallbacksVideoIn);
1727 m_interfaceCallbacksVideoIn.VRDECallbackVideoInNotify = VRDECallbackVideoInNotify;
1728 m_interfaceCallbacksVideoIn.VRDECallbackVideoInDeviceDesc = VRDECallbackVideoInDeviceDesc;
1729 m_interfaceCallbacksVideoIn.VRDECallbackVideoInControl = VRDECallbackVideoInControl;
1730 m_interfaceCallbacksVideoIn.VRDECallbackVideoInFrame = VRDECallbackVideoInFrame;
1731
1732 vrc = mpEntryPoints->VRDEGetInterface(mhServer,
1733 VRDE_VIDEOIN_INTERFACE_NAME,
1734 &m_interfaceVideoIn.header,
1735 &m_interfaceCallbacksVideoIn.header,
1736 this);
1737 if (RT_SUCCESS(vrc))
1738 {
1739 LogRel(("VRDE: [%s]\n", VRDE_VIDEOIN_INTERFACE_NAME));
1740 }
1741 else
1742 {
1743 RT_ZERO(m_interfaceVideoIn);
1744 }
1745
1746 /* Input interface. */
1747 m_interfaceInput.header.u64Version = 1;
1748 m_interfaceInput.header.u64Size = sizeof(m_interfaceInput);
1749
1750 m_interfaceCallbacksInput.header.u64Version = 1;
1751 m_interfaceCallbacksInput.header.u64Size = sizeof(m_interfaceCallbacksInput);
1752 m_interfaceCallbacksInput.VRDECallbackInputSetup = VRDECallbackInputSetup;
1753 m_interfaceCallbacksInput.VRDECallbackInputEvent = VRDECallbackInputEvent;
1754
1755 vrc = mpEntryPoints->VRDEGetInterface(mhServer,
1756 VRDE_INPUT_INTERFACE_NAME,
1757 &m_interfaceInput.header,
1758 &m_interfaceCallbacksInput.header,
1759 this);
1760 if (RT_SUCCESS(vrc))
1761 {
1762 LogRel(("VRDE: [%s]\n", VRDE_INPUT_INTERFACE_NAME));
1763 }
1764 else
1765 {
1766 RT_ZERO(m_interfaceInput);
1767 }
1768
1769 /* Since these interfaces are optional, it is always a success here. */
1770 vrc = VINF_SUCCESS;
1771 }
1772#ifdef VBOX_WITH_USB
1773 remoteUSBThreadStart();
1774#endif
1775
1776 /*
1777 * Re-init the server current state, which is usually obtained from events.
1778 */
1779 fetchCurrentState();
1780 }
1781 else
1782 {
1783 if (vrc != VERR_NET_ADDRESS_IN_USE)
1784 LogRel(("VRDE: Could not start the server rc = %Rrc\n", vrc));
1785 /* Don't unload the lib, because it prevents us trying again or
1786 because there may be other users? */
1787 }
1788 }
1789 }
1790
1791 return vrc;
1792}
1793
1794void ConsoleVRDPServer::fetchCurrentState(void)
1795{
1796 ComPtr<IMousePointerShape> mps;
1797 mConsole->i_getMouse()->COMGETTER(PointerShape)(mps.asOutParam());
1798 if (!mps.isNull())
1799 {
1800 BOOL visible, alpha;
1801 ULONG hotX, hotY, width, height;
1802 com::SafeArray <BYTE> shape;
1803
1804 mps->COMGETTER(Visible)(&visible);
1805 mps->COMGETTER(Alpha)(&alpha);
1806 mps->COMGETTER(HotX)(&hotX);
1807 mps->COMGETTER(HotY)(&hotY);
1808 mps->COMGETTER(Width)(&width);
1809 mps->COMGETTER(Height)(&height);
1810 mps->COMGETTER(Shape)(ComSafeArrayAsOutParam(shape));
1811
1812 onMousePointerShapeChange(visible, alpha, hotX, hotY, width, height, ComSafeArrayAsInParam(shape));
1813 }
1814}
1815
1816typedef struct H3DORInstance
1817{
1818 ConsoleVRDPServer *pThis;
1819 HVRDEIMAGE hImageBitmap;
1820 int32_t x;
1821 int32_t y;
1822 uint32_t w;
1823 uint32_t h;
1824 bool fCreated;
1825 bool fFallback;
1826 bool fTopDown;
1827} H3DORInstance;
1828
1829#define H3DORLOG Log
1830
1831/* static */ DECLCALLBACK(void) ConsoleVRDPServer::H3DORBegin(const void *pvContext, void **ppvInstance,
1832 const char *pszFormat)
1833{
1834 H3DORLOG(("H3DORBegin: ctx %p [%s]\n", pvContext, pszFormat));
1835
1836 H3DORInstance *p = (H3DORInstance *)RTMemAlloc(sizeof(H3DORInstance));
1837
1838 if (p)
1839 {
1840 p->pThis = (ConsoleVRDPServer *)pvContext;
1841 p->hImageBitmap = NULL;
1842 p->x = 0;
1843 p->y = 0;
1844 p->w = 0;
1845 p->h = 0;
1846 p->fCreated = false;
1847 p->fFallback = false;
1848
1849 /* Host 3D service passes the actual format of data in this redirect instance.
1850 * That is what will be in the H3DORFrame's parameters pvData and cbData.
1851 */
1852 if (RTStrICmp(pszFormat, H3DOR_FMT_RGBA_TOPDOWN) == 0)
1853 {
1854 /* Accept it. */
1855 p->fTopDown = true;
1856 }
1857 else if (RTStrICmp(pszFormat, H3DOR_FMT_RGBA) == 0)
1858 {
1859 /* Accept it. */
1860 p->fTopDown = false;
1861 }
1862 else
1863 {
1864 RTMemFree(p);
1865 p = NULL;
1866 }
1867 }
1868
1869 H3DORLOG(("H3DORBegin: ins %p\n", p));
1870
1871 /* Caller checks this for NULL. */
1872 *ppvInstance = p;
1873}
1874
1875/* static */ DECLCALLBACK(void) ConsoleVRDPServer::H3DORGeometry(void *pvInstance,
1876 int32_t x, int32_t y, uint32_t w, uint32_t h)
1877{
1878 H3DORLOG(("H3DORGeometry: ins %p %d,%d %dx%d\n", pvInstance, x, y, w, h));
1879
1880 H3DORInstance *p = (H3DORInstance *)pvInstance;
1881 Assert(p);
1882 Assert(p->pThis);
1883
1884 /* @todo find out what to do if size changes to 0x0 from non zero */
1885 if (w == 0 || h == 0)
1886 {
1887 /* Do nothing. */
1888 return;
1889 }
1890
1891 RTRECT rect;
1892 rect.xLeft = x;
1893 rect.yTop = y;
1894 rect.xRight = x + w;
1895 rect.yBottom = y + h;
1896
1897 if (p->hImageBitmap)
1898 {
1899 /* An image handle has been already created,
1900 * check if it has the same size as the reported geometry.
1901 */
1902 if ( p->x == x
1903 && p->y == y
1904 && p->w == w
1905 && p->h == h)
1906 {
1907 H3DORLOG(("H3DORGeometry: geometry not changed\n"));
1908 /* Do nothing. Continue using the existing handle. */
1909 }
1910 else
1911 {
1912 int rc = p->fFallback?
1913 VERR_NOT_SUPPORTED: /* Try to go out of fallback mode. */
1914 p->pThis->m_interfaceImage.VRDEImageGeometrySet(p->hImageBitmap, &rect);
1915 if (RT_SUCCESS(rc))
1916 {
1917 p->x = x;
1918 p->y = y;
1919 p->w = w;
1920 p->h = h;
1921 }
1922 else
1923 {
1924 /* The handle must be recreated. Delete existing handle here. */
1925 p->pThis->m_interfaceImage.VRDEImageHandleClose(p->hImageBitmap);
1926 p->hImageBitmap = NULL;
1927 }
1928 }
1929 }
1930
1931 if (!p->hImageBitmap)
1932 {
1933 /* Create a new bitmap handle. */
1934 uint32_t u32ScreenId = 0; /* @todo clip to corresponding screens.
1935 * Clipping can be done here or in VRDP server.
1936 * If VRDP does clipping, then uScreenId parameter
1937 * is not necessary and coords must be global.
1938 * (have to check which coords are used in opengl service).
1939 * Since all VRDE API uses a ScreenId,
1940 * the clipping must be done here in ConsoleVRDPServer
1941 */
1942 uint32_t fu32CompletionFlags = 0;
1943 p->fFallback = false;
1944 int rc = p->pThis->m_interfaceImage.VRDEImageHandleCreate(p->pThis->mhServer,
1945 &p->hImageBitmap,
1946 p,
1947 u32ScreenId,
1948 VRDE_IMAGE_F_CREATE_CONTENT_3D
1949 | VRDE_IMAGE_F_CREATE_WINDOW,
1950 &rect,
1951 VRDE_IMAGE_FMT_ID_BITMAP_BGRA8,
1952 NULL,
1953 0,
1954 &fu32CompletionFlags);
1955 if (RT_FAILURE(rc))
1956 {
1957 /* No support for a 3D + WINDOW. Try bitmap updates. */
1958 H3DORLOG(("H3DORGeometry: Fallback to bitmaps\n"));
1959 fu32CompletionFlags = 0;
1960 p->fFallback = true;
1961 rc = p->pThis->m_interfaceImage.VRDEImageHandleCreate(p->pThis->mhServer,
1962 &p->hImageBitmap,
1963 p,
1964 u32ScreenId,
1965 0,
1966 &rect,
1967 VRDE_IMAGE_FMT_ID_BITMAP_BGRA8,
1968 NULL,
1969 0,
1970 &fu32CompletionFlags);
1971 }
1972
1973 H3DORLOG(("H3DORGeometry: Image handle create %Rrc, flags 0x%RX32\n", rc, fu32CompletionFlags));
1974
1975 if (RT_SUCCESS(rc))
1976 {
1977 p->x = x;
1978 p->y = y;
1979 p->w = w;
1980 p->h = h;
1981
1982 if ((fu32CompletionFlags & VRDE_IMAGE_F_COMPLETE_ASYNC) == 0)
1983 {
1984 p->fCreated = true;
1985 }
1986 }
1987 else
1988 {
1989 p->hImageBitmap = NULL;
1990 p->w = 0;
1991 p->h = 0;
1992 }
1993 }
1994
1995 H3DORLOG(("H3DORGeometry: ins %p completed\n", pvInstance));
1996}
1997
1998/* static */ DECLCALLBACK(void) ConsoleVRDPServer::H3DORVisibleRegion(void *pvInstance,
1999 uint32_t cRects, const RTRECT *paRects)
2000{
2001 H3DORLOG(("H3DORVisibleRegion: ins %p %d\n", pvInstance, cRects));
2002
2003 H3DORInstance *p = (H3DORInstance *)pvInstance;
2004 Assert(p);
2005 Assert(p->pThis);
2006
2007 if (cRects == 0)
2008 {
2009 /* Complete image is visible. */
2010 RTRECT rect;
2011 rect.xLeft = p->x;
2012 rect.yTop = p->y;
2013 rect.xRight = p->x + p->w;
2014 rect.yBottom = p->y + p->h;
2015 p->pThis->m_interfaceImage.VRDEImageRegionSet (p->hImageBitmap,
2016 1,
2017 &rect);
2018 }
2019 else
2020 {
2021 p->pThis->m_interfaceImage.VRDEImageRegionSet (p->hImageBitmap,
2022 cRects,
2023 paRects);
2024 }
2025
2026 H3DORLOG(("H3DORVisibleRegion: ins %p completed\n", pvInstance));
2027}
2028
2029/* static */ DECLCALLBACK(void) ConsoleVRDPServer::H3DORFrame(void *pvInstance,
2030 void *pvData, uint32_t cbData)
2031{
2032 H3DORLOG(("H3DORFrame: ins %p %p %d\n", pvInstance, pvData, cbData));
2033
2034 H3DORInstance *p = (H3DORInstance *)pvInstance;
2035 Assert(p);
2036 Assert(p->pThis);
2037
2038 /* Currently only a topdown BGR0 bitmap format is supported. */
2039 VRDEIMAGEBITMAP image;
2040
2041 image.cWidth = p->w;
2042 image.cHeight = p->h;
2043 image.pvData = pvData;
2044 image.cbData = cbData;
2045 image.pvScanLine0 = (uint8_t *)pvData + (p->h - 1) * p->w * 4;
2046 image.iScanDelta = 4 * p->w;
2047 if (p->fTopDown)
2048 {
2049 image.iScanDelta = -image.iScanDelta;
2050 }
2051
2052 p->pThis->m_interfaceImage.VRDEImageUpdate (p->hImageBitmap,
2053 p->x,
2054 p->y,
2055 p->w,
2056 p->h,
2057 &image,
2058 sizeof(VRDEIMAGEBITMAP));
2059
2060 H3DORLOG(("H3DORFrame: ins %p completed\n", pvInstance));
2061}
2062
2063/* static */ DECLCALLBACK(void) ConsoleVRDPServer::H3DOREnd(void *pvInstance)
2064{
2065 H3DORLOG(("H3DOREnd: ins %p\n", pvInstance));
2066
2067 H3DORInstance *p = (H3DORInstance *)pvInstance;
2068 Assert(p);
2069 Assert(p->pThis);
2070
2071 p->pThis->m_interfaceImage.VRDEImageHandleClose(p->hImageBitmap);
2072
2073 RTMemFree(p);
2074
2075 H3DORLOG(("H3DOREnd: ins %p completed\n", pvInstance));
2076}
2077
2078/* static */ DECLCALLBACK(int) ConsoleVRDPServer::H3DORContextProperty(const void *pvContext, uint32_t index,
2079 void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut)
2080{
2081 int rc = VINF_SUCCESS;
2082
2083 H3DORLOG(("H3DORContextProperty: index %d\n", index));
2084
2085 if (index == H3DOR_PROP_FORMATS)
2086 {
2087 /* Return a comma separated list of supported formats. */
2088 uint32_t cbOut = (uint32_t)strlen(H3DOR_FMT_RGBA_TOPDOWN) + 1
2089 + (uint32_t)strlen(H3DOR_FMT_RGBA) + 1;
2090 if (cbOut <= cbBuffer)
2091 {
2092 char *pch = (char *)pvBuffer;
2093 memcpy(pch, H3DOR_FMT_RGBA_TOPDOWN, strlen(H3DOR_FMT_RGBA_TOPDOWN));
2094 pch += strlen(H3DOR_FMT_RGBA_TOPDOWN);
2095 *pch++ = ',';
2096 memcpy(pch, H3DOR_FMT_RGBA, strlen(H3DOR_FMT_RGBA));
2097 pch += strlen(H3DOR_FMT_RGBA);
2098 *pch++ = '\0';
2099 }
2100 else
2101 {
2102 rc = VERR_BUFFER_OVERFLOW;
2103 }
2104 *pcbOut = cbOut;
2105 }
2106 else
2107 {
2108 rc = VERR_NOT_SUPPORTED;
2109 }
2110
2111 H3DORLOG(("H3DORContextProperty: %Rrc\n", rc));
2112 return rc;
2113}
2114
2115void ConsoleVRDPServer::remote3DRedirect(bool fEnable)
2116{
2117 if (!m_fInterfaceImage)
2118 {
2119 /* No redirect without corresponding interface. */
2120 return;
2121 }
2122
2123 /* Check if 3D redirection has been enabled. It is enabled by default. */
2124 com::Bstr bstr;
2125 HRESULT hrc = mConsole->i_getVRDEServer()->GetVRDEProperty(Bstr("H3DRedirect/Enabled").raw(), bstr.asOutParam());
2126
2127 com::Utf8Str value = hrc == S_OK? bstr: "";
2128
2129 bool fAllowed = RTStrICmp(value.c_str(), "true") == 0
2130 || RTStrICmp(value.c_str(), "1") == 0
2131 || value.c_str()[0] == 0;
2132
2133 if (!fAllowed && fEnable)
2134 {
2135 return;
2136 }
2137
2138 /* Tell the host 3D service to redirect output using the ConsoleVRDPServer callbacks. */
2139 H3DOUTPUTREDIRECT outputRedirect =
2140 {
2141 this,
2142 H3DORBegin,
2143 H3DORGeometry,
2144 H3DORVisibleRegion,
2145 H3DORFrame,
2146 H3DOREnd,
2147 H3DORContextProperty
2148 };
2149
2150 if (!fEnable)
2151 {
2152 /* This will tell the service to disable rediection. */
2153 RT_ZERO(outputRedirect);
2154 }
2155
2156#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2157 VBOXCRCMDCTL_HGCM data;
2158 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
2159 data.Hdr.u32Function = SHCRGL_HOST_FN_SET_OUTPUT_REDIRECT;
2160
2161 data.aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
2162 data.aParms[0].u.pointer.addr = &outputRedirect;
2163 data.aParms[0].u.pointer.size = sizeof(outputRedirect);
2164
2165 int rc = mConsole->i_getDisplay()->i_crCtlSubmitSync(&data.Hdr, sizeof (data));
2166 if (!RT_SUCCESS(rc))
2167 {
2168 Log(("SHCRGL_HOST_FN_SET_CONSOLE failed with %Rrc\n", rc));
2169 return;
2170 }
2171
2172 LogRel(("VRDE: %s 3D redirect.\n", fEnable? "Enabled": "Disabled"));
2173# ifdef DEBUG_misha
2174 AssertFailed();
2175# endif
2176#endif
2177
2178 return;
2179}
2180
2181/* static */ DECLCALLBACK(int) ConsoleVRDPServer::VRDEImageCbNotify (void *pvContext,
2182 void *pvUser,
2183 HVRDEIMAGE hVideo,
2184 uint32_t u32Id,
2185 void *pvData,
2186 uint32_t cbData)
2187{
2188 H3DORLOG(("H3DOR: VRDEImageCbNotify: pvContext %p, pvUser %p, hVideo %p, u32Id %u, pvData %p, cbData %d\n",
2189 pvContext, pvUser, hVideo, u32Id, pvData, cbData));
2190
2191 ConsoleVRDPServer *pServer = static_cast<ConsoleVRDPServer*>(pvContext);
2192 H3DORInstance *p = (H3DORInstance *)pvUser;
2193 Assert(p);
2194 Assert(p->pThis);
2195 Assert(p->pThis == pServer);
2196
2197 if (u32Id == VRDE_IMAGE_NOTIFY_HANDLE_CREATE)
2198 {
2199 if (cbData != sizeof(uint32_t))
2200 {
2201 AssertFailed();
2202 return VERR_INVALID_PARAMETER;
2203 }
2204
2205 uint32_t u32StreamId = *(uint32_t *)pvData;
2206 H3DORLOG(("H3DOR: VRDE_IMAGE_NOTIFY_HANDLE_CREATE u32StreamId %d\n",
2207 u32StreamId));
2208
2209 if (u32StreamId != 0)
2210 {
2211 p->fCreated = true; // @todo not needed?
2212 }
2213 else
2214 {
2215 /* The stream has not been created. */
2216 }
2217 }
2218
2219 return VINF_SUCCESS;
2220}
2221
2222#undef H3DORLOG
2223
2224/* static */ DECLCALLBACK(int) ConsoleVRDPServer::VRDESCardCbNotify(void *pvContext,
2225 uint32_t u32Id,
2226 void *pvData,
2227 uint32_t cbData)
2228{
2229#ifdef VBOX_WITH_USB_CARDREADER
2230 ConsoleVRDPServer *pThis = static_cast<ConsoleVRDPServer*>(pvContext);
2231 UsbCardReader *pReader = pThis->mConsole->i_getUsbCardReader();
2232 return pReader->VRDENotify(u32Id, pvData, cbData);
2233#else
2234 NOREF(pvContext);
2235 NOREF(u32Id);
2236 NOREF(pvData);
2237 NOREF(cbData);
2238 return VERR_NOT_SUPPORTED;
2239#endif
2240}
2241
2242/* static */ DECLCALLBACK(int) ConsoleVRDPServer::VRDESCardCbResponse(void *pvContext,
2243 int rcRequest,
2244 void *pvUser,
2245 uint32_t u32Function,
2246 void *pvData,
2247 uint32_t cbData)
2248{
2249#ifdef VBOX_WITH_USB_CARDREADER
2250 ConsoleVRDPServer *pThis = static_cast<ConsoleVRDPServer*>(pvContext);
2251 UsbCardReader *pReader = pThis->mConsole->i_getUsbCardReader();
2252 return pReader->VRDEResponse(rcRequest, pvUser, u32Function, pvData, cbData);
2253#else
2254 NOREF(pvContext);
2255 NOREF(rcRequest);
2256 NOREF(pvUser);
2257 NOREF(u32Function);
2258 NOREF(pvData);
2259 NOREF(cbData);
2260 return VERR_NOT_SUPPORTED;
2261#endif
2262}
2263
2264int ConsoleVRDPServer::SCardRequest(void *pvUser, uint32_t u32Function, const void *pvData, uint32_t cbData)
2265{
2266 int rc = VINF_SUCCESS;
2267
2268 if (mhServer && mpEntryPoints && m_interfaceSCard.VRDESCardRequest)
2269 {
2270 rc = m_interfaceSCard.VRDESCardRequest(mhServer, pvUser, u32Function, pvData, cbData);
2271 }
2272 else
2273 {
2274 rc = VERR_NOT_SUPPORTED;
2275 }
2276
2277 return rc;
2278}
2279
2280
2281struct TSMFHOSTCHCTX;
2282struct TSMFVRDPCTX;
2283
2284typedef struct TSMFHOSTCHCTX
2285{
2286 ConsoleVRDPServer *pThis;
2287
2288 struct TSMFVRDPCTX *pVRDPCtx; /* NULL if no corresponding host channel context. */
2289
2290 void *pvDataReceived;
2291 uint32_t cbDataReceived;
2292 uint32_t cbDataAllocated;
2293} TSMFHOSTCHCTX;
2294
2295typedef struct TSMFVRDPCTX
2296{
2297 ConsoleVRDPServer *pThis;
2298
2299 VBOXHOSTCHANNELCALLBACKS *pCallbacks;
2300 void *pvCallbacks;
2301
2302 TSMFHOSTCHCTX *pHostChCtx; /* NULL if no corresponding host channel context. */
2303
2304 uint32_t u32ChannelHandle;
2305} TSMFVRDPCTX;
2306
2307static int tsmfContextsAlloc(TSMFHOSTCHCTX **ppHostChCtx, TSMFVRDPCTX **ppVRDPCtx)
2308{
2309 TSMFHOSTCHCTX *pHostChCtx = (TSMFHOSTCHCTX *)RTMemAllocZ(sizeof(TSMFHOSTCHCTX));
2310 if (!pHostChCtx)
2311 {
2312 return VERR_NO_MEMORY;
2313 }
2314
2315 TSMFVRDPCTX *pVRDPCtx = (TSMFVRDPCTX *)RTMemAllocZ(sizeof(TSMFVRDPCTX));
2316 if (!pVRDPCtx)
2317 {
2318 RTMemFree(pHostChCtx);
2319 return VERR_NO_MEMORY;
2320 }
2321
2322 *ppHostChCtx = pHostChCtx;
2323 *ppVRDPCtx = pVRDPCtx;
2324 return VINF_SUCCESS;
2325}
2326
2327int ConsoleVRDPServer::tsmfLock(void)
2328{
2329 int rc = RTCritSectEnter(&mTSMFLock);
2330 AssertRC(rc);
2331 return rc;
2332}
2333
2334void ConsoleVRDPServer::tsmfUnlock(void)
2335{
2336 RTCritSectLeave(&mTSMFLock);
2337}
2338
2339/* static */ DECLCALLBACK(int) ConsoleVRDPServer::tsmfHostChannelAttach(void *pvProvider,
2340 void **ppvChannel,
2341 uint32_t u32Flags,
2342 VBOXHOSTCHANNELCALLBACKS *pCallbacks,
2343 void *pvCallbacks)
2344{
2345 LogFlowFunc(("\n"));
2346
2347 ConsoleVRDPServer *pThis = static_cast<ConsoleVRDPServer*>(pvProvider);
2348
2349 /* Create 2 context structures: for the VRDP server and for the host service. */
2350 TSMFHOSTCHCTX *pHostChCtx = NULL;
2351 TSMFVRDPCTX *pVRDPCtx = NULL;
2352
2353 int rc = tsmfContextsAlloc(&pHostChCtx, &pVRDPCtx);
2354 if (RT_FAILURE(rc))
2355 {
2356 return rc;
2357 }
2358
2359 pHostChCtx->pThis = pThis;
2360 pHostChCtx->pVRDPCtx = pVRDPCtx;
2361
2362 pVRDPCtx->pThis = pThis;
2363 pVRDPCtx->pCallbacks = pCallbacks;
2364 pVRDPCtx->pvCallbacks = pvCallbacks;
2365 pVRDPCtx->pHostChCtx = pHostChCtx;
2366
2367 rc = pThis->m_interfaceTSMF.VRDETSMFChannelCreate(pThis->mhServer, pVRDPCtx, u32Flags);
2368
2369 if (RT_SUCCESS(rc))
2370 {
2371 /* @todo contexts should be in a list for accounting. */
2372 *ppvChannel = pHostChCtx;
2373 }
2374 else
2375 {
2376 RTMemFree(pHostChCtx);
2377 RTMemFree(pVRDPCtx);
2378 }
2379
2380 return rc;
2381}
2382
2383/* static */ DECLCALLBACK(void) ConsoleVRDPServer::tsmfHostChannelDetach(void *pvChannel)
2384{
2385 LogFlowFunc(("\n"));
2386
2387 TSMFHOSTCHCTX *pHostChCtx = (TSMFHOSTCHCTX *)pvChannel;
2388 ConsoleVRDPServer *pThis = pHostChCtx->pThis;
2389
2390 int rc = pThis->tsmfLock();
2391 if (RT_SUCCESS(rc))
2392 {
2393 bool fClose = false;
2394 uint32_t u32ChannelHandle = 0;
2395
2396 if (pHostChCtx->pVRDPCtx)
2397 {
2398 /* There is still a VRDP context for this channel. */
2399 pHostChCtx->pVRDPCtx->pHostChCtx = NULL;
2400 u32ChannelHandle = pHostChCtx->pVRDPCtx->u32ChannelHandle;
2401 fClose = true;
2402 }
2403
2404 pThis->tsmfUnlock();
2405
2406 RTMemFree(pHostChCtx);
2407
2408 if (fClose)
2409 {
2410 LogFlowFunc(("Closing VRDE channel %d.\n", u32ChannelHandle));
2411 pThis->m_interfaceTSMF.VRDETSMFChannelClose(pThis->mhServer, u32ChannelHandle);
2412 }
2413 else
2414 {
2415 LogFlowFunc(("No VRDE channel.\n"));
2416 }
2417 }
2418}
2419
2420/* static */ DECLCALLBACK(int) ConsoleVRDPServer::tsmfHostChannelSend(void *pvChannel,
2421 const void *pvData,
2422 uint32_t cbData)
2423{
2424 LogFlowFunc(("cbData %d\n", cbData));
2425
2426 TSMFHOSTCHCTX *pHostChCtx = (TSMFHOSTCHCTX *)pvChannel;
2427 ConsoleVRDPServer *pThis = pHostChCtx->pThis;
2428
2429 int rc = pThis->tsmfLock();
2430 if (RT_SUCCESS(rc))
2431 {
2432 bool fSend = false;
2433 uint32_t u32ChannelHandle = 0;
2434
2435 if (pHostChCtx->pVRDPCtx)
2436 {
2437 u32ChannelHandle = pHostChCtx->pVRDPCtx->u32ChannelHandle;
2438 fSend = true;
2439 }
2440
2441 pThis->tsmfUnlock();
2442
2443 if (fSend)
2444 {
2445 LogFlowFunc(("Send to VRDE channel %d.\n", u32ChannelHandle));
2446 rc = pThis->m_interfaceTSMF.VRDETSMFChannelSend(pThis->mhServer, u32ChannelHandle,
2447 pvData, cbData);
2448 }
2449 }
2450
2451 return rc;
2452}
2453
2454/* static */ DECLCALLBACK(int) ConsoleVRDPServer::tsmfHostChannelRecv(void *pvChannel,
2455 void *pvData,
2456 uint32_t cbData,
2457 uint32_t *pcbReceived,
2458 uint32_t *pcbRemaining)
2459{
2460 LogFlowFunc(("cbData %d\n", cbData));
2461
2462 TSMFHOSTCHCTX *pHostChCtx = (TSMFHOSTCHCTX *)pvChannel;
2463 ConsoleVRDPServer *pThis = pHostChCtx->pThis;
2464
2465 int rc = pThis->tsmfLock();
2466 if (RT_SUCCESS(rc))
2467 {
2468 uint32_t cbToCopy = RT_MIN(cbData, pHostChCtx->cbDataReceived);
2469 uint32_t cbRemaining = pHostChCtx->cbDataReceived - cbToCopy;
2470
2471 LogFlowFunc(("cbToCopy %d, cbRemaining %d\n", cbToCopy, cbRemaining));
2472
2473 if (cbToCopy != 0)
2474 {
2475 memcpy(pvData, pHostChCtx->pvDataReceived, cbToCopy);
2476
2477 if (cbRemaining != 0)
2478 {
2479 memmove(pHostChCtx->pvDataReceived, (uint8_t *)pHostChCtx->pvDataReceived + cbToCopy, cbRemaining);
2480 }
2481
2482 pHostChCtx->cbDataReceived = cbRemaining;
2483 }
2484
2485 pThis->tsmfUnlock();
2486
2487 *pcbRemaining = cbRemaining;
2488 *pcbReceived = cbToCopy;
2489 }
2490
2491 return rc;
2492}
2493
2494/* static */ DECLCALLBACK(int) ConsoleVRDPServer::tsmfHostChannelControl(void *pvChannel,
2495 uint32_t u32Code,
2496 const void *pvParm,
2497 uint32_t cbParm,
2498 const void *pvData,
2499 uint32_t cbData,
2500 uint32_t *pcbDataReturned)
2501{
2502 LogFlowFunc(("u32Code %u\n", u32Code));
2503
2504 if (!pvChannel)
2505 {
2506 /* Special case, the provider must answer rather than a channel instance. */
2507 if (u32Code == VBOX_HOST_CHANNEL_CTRL_EXISTS)
2508 {
2509 *pcbDataReturned = 0;
2510 return VINF_SUCCESS;
2511 }
2512
2513 return VERR_NOT_IMPLEMENTED;
2514 }
2515
2516 /* Channels do not support this. */
2517 return VERR_NOT_IMPLEMENTED;
2518}
2519
2520
2521void ConsoleVRDPServer::setupTSMF(void)
2522{
2523 if (m_interfaceTSMF.header.u64Size == 0)
2524 {
2525 return;
2526 }
2527
2528 /* Register with the host channel service. */
2529 VBOXHOSTCHANNELINTERFACE hostChannelInterface =
2530 {
2531 this,
2532 tsmfHostChannelAttach,
2533 tsmfHostChannelDetach,
2534 tsmfHostChannelSend,
2535 tsmfHostChannelRecv,
2536 tsmfHostChannelControl
2537 };
2538
2539 VBoxHostChannelHostRegister parms;
2540
2541 static char szProviderName[] = "/vrde/tsmf";
2542
2543 parms.name.type = VBOX_HGCM_SVC_PARM_PTR;
2544 parms.name.u.pointer.addr = &szProviderName[0];
2545 parms.name.u.pointer.size = sizeof(szProviderName);
2546
2547 parms.iface.type = VBOX_HGCM_SVC_PARM_PTR;
2548 parms.iface.u.pointer.addr = &hostChannelInterface;
2549 parms.iface.u.pointer.size = sizeof(hostChannelInterface);
2550
2551 VMMDev *pVMMDev = mConsole->i_getVMMDev();
2552
2553 if (!pVMMDev)
2554 {
2555 AssertMsgFailed(("setupTSMF no vmmdev\n"));
2556 return;
2557 }
2558
2559 int rc = pVMMDev->hgcmHostCall("VBoxHostChannel",
2560 VBOX_HOST_CHANNEL_HOST_FN_REGISTER,
2561 2,
2562 &parms.name);
2563
2564 if (!RT_SUCCESS(rc))
2565 {
2566 Log(("VBOX_HOST_CHANNEL_HOST_FN_REGISTER failed with %Rrc\n", rc));
2567 return;
2568 }
2569
2570 LogRel(("VRDE: Enabled TSMF channel.\n"));
2571
2572 return;
2573}
2574
2575/* @todo these defines must be in a header, which is used by guest component as well. */
2576#define VBOX_TSMF_HCH_CREATE_ACCEPTED (VBOX_HOST_CHANNEL_EVENT_USER + 0)
2577#define VBOX_TSMF_HCH_CREATE_DECLINED (VBOX_HOST_CHANNEL_EVENT_USER + 1)
2578#define VBOX_TSMF_HCH_DISCONNECTED (VBOX_HOST_CHANNEL_EVENT_USER + 2)
2579
2580/* static */ DECLCALLBACK(void) ConsoleVRDPServer::VRDETSMFCbNotify(void *pvContext,
2581 uint32_t u32Notification,
2582 void *pvChannel,
2583 const void *pvParm,
2584 uint32_t cbParm)
2585{
2586 int rc = VINF_SUCCESS;
2587
2588 ConsoleVRDPServer *pThis = static_cast<ConsoleVRDPServer*>(pvContext);
2589
2590 TSMFVRDPCTX *pVRDPCtx = (TSMFVRDPCTX *)pvChannel;
2591
2592 Assert(pVRDPCtx->pThis == pThis);
2593
2594 if (pVRDPCtx->pCallbacks == NULL)
2595 {
2596 LogFlowFunc(("tsmfHostChannel: Channel disconnected. Skipping.\n"));
2597 return;
2598 }
2599
2600 switch (u32Notification)
2601 {
2602 case VRDE_TSMF_N_CREATE_ACCEPTED:
2603 {
2604 VRDETSMFNOTIFYCREATEACCEPTED *p = (VRDETSMFNOTIFYCREATEACCEPTED *)pvParm;
2605 Assert(cbParm == sizeof(VRDETSMFNOTIFYCREATEACCEPTED));
2606
2607 LogFlowFunc(("tsmfHostChannel: VRDE_TSMF_N_CREATE_ACCEPTED(%p): p->u32ChannelHandle %d\n",
2608 pVRDPCtx, p->u32ChannelHandle));
2609
2610 pVRDPCtx->u32ChannelHandle = p->u32ChannelHandle;
2611
2612 pVRDPCtx->pCallbacks->HostChannelCallbackEvent(pVRDPCtx->pvCallbacks, pVRDPCtx->pHostChCtx,
2613 VBOX_TSMF_HCH_CREATE_ACCEPTED,
2614 NULL, 0);
2615 } break;
2616
2617 case VRDE_TSMF_N_CREATE_DECLINED:
2618 {
2619 LogFlowFunc(("tsmfHostChannel: VRDE_TSMF_N_CREATE_DECLINED(%p)\n", pVRDPCtx));
2620
2621 pVRDPCtx->pCallbacks->HostChannelCallbackEvent(pVRDPCtx->pvCallbacks, pVRDPCtx->pHostChCtx,
2622 VBOX_TSMF_HCH_CREATE_DECLINED,
2623 NULL, 0);
2624 } break;
2625
2626 case VRDE_TSMF_N_DATA:
2627 {
2628 /* Save the data in the intermediate buffer and send the event. */
2629 VRDETSMFNOTIFYDATA *p = (VRDETSMFNOTIFYDATA *)pvParm;
2630 Assert(cbParm == sizeof(VRDETSMFNOTIFYDATA));
2631
2632 LogFlowFunc(("tsmfHostChannel: VRDE_TSMF_N_DATA(%p): p->cbData %d\n", pVRDPCtx, p->cbData));
2633
2634 VBOXHOSTCHANNELEVENTRECV ev;
2635 ev.u32SizeAvailable = 0;
2636
2637 rc = pThis->tsmfLock();
2638
2639 if (RT_SUCCESS(rc))
2640 {
2641 TSMFHOSTCHCTX *pHostChCtx = pVRDPCtx->pHostChCtx;
2642
2643 if (pHostChCtx)
2644 {
2645 if (pHostChCtx->pvDataReceived)
2646 {
2647 uint32_t cbAlloc = p->cbData + pHostChCtx->cbDataReceived;
2648 pHostChCtx->pvDataReceived = RTMemRealloc(pHostChCtx->pvDataReceived, cbAlloc);
2649 memcpy((uint8_t *)pHostChCtx->pvDataReceived + pHostChCtx->cbDataReceived, p->pvData, p->cbData);
2650
2651 pHostChCtx->cbDataReceived += p->cbData;
2652 pHostChCtx->cbDataAllocated = cbAlloc;
2653 }
2654 else
2655 {
2656 pHostChCtx->pvDataReceived = RTMemAlloc(p->cbData);
2657 memcpy(pHostChCtx->pvDataReceived, p->pvData, p->cbData);
2658
2659 pHostChCtx->cbDataReceived = p->cbData;
2660 pHostChCtx->cbDataAllocated = p->cbData;
2661 }
2662
2663 ev.u32SizeAvailable = p->cbData;
2664 }
2665 else
2666 {
2667 LogFlowFunc(("tsmfHostChannel: VRDE_TSMF_N_DATA: no host channel. Skipping\n"));
2668 }
2669
2670 pThis->tsmfUnlock();
2671 }
2672
2673 pVRDPCtx->pCallbacks->HostChannelCallbackEvent(pVRDPCtx->pvCallbacks, pVRDPCtx->pHostChCtx,
2674 VBOX_HOST_CHANNEL_EVENT_RECV,
2675 &ev, sizeof(ev));
2676 } break;
2677
2678 case VRDE_TSMF_N_DISCONNECTED:
2679 {
2680 LogFlowFunc(("tsmfHostChannel: VRDE_TSMF_N_DISCONNECTED(%p)\n", pVRDPCtx));
2681
2682 pVRDPCtx->pCallbacks->HostChannelCallbackEvent(pVRDPCtx->pvCallbacks, pVRDPCtx->pHostChCtx,
2683 VBOX_TSMF_HCH_DISCONNECTED,
2684 NULL, 0);
2685
2686 /* The callback context will not be used anymore. */
2687 pVRDPCtx->pCallbacks->HostChannelCallbackDeleted(pVRDPCtx->pvCallbacks, pVRDPCtx->pHostChCtx);
2688 pVRDPCtx->pCallbacks = NULL;
2689 pVRDPCtx->pvCallbacks = NULL;
2690
2691 rc = pThis->tsmfLock();
2692 if (RT_SUCCESS(rc))
2693 {
2694 if (pVRDPCtx->pHostChCtx)
2695 {
2696 /* There is still a host channel context for this channel. */
2697 pVRDPCtx->pHostChCtx->pVRDPCtx = NULL;
2698 }
2699
2700 pThis->tsmfUnlock();
2701
2702 RT_ZERO(*pVRDPCtx);
2703 RTMemFree(pVRDPCtx);
2704 }
2705 } break;
2706
2707 default:
2708 {
2709 AssertFailed();
2710 } break;
2711 }
2712}
2713
2714/* static */ DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackVideoInNotify(void *pvCallback,
2715 uint32_t u32Id,
2716 const void *pvData,
2717 uint32_t cbData)
2718{
2719 ConsoleVRDPServer *pThis = static_cast<ConsoleVRDPServer*>(pvCallback);
2720 if (pThis->mEmWebcam)
2721 {
2722 pThis->mEmWebcam->EmWebcamCbNotify(u32Id, pvData, cbData);
2723 }
2724}
2725
2726/* static */ DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackVideoInDeviceDesc(void *pvCallback,
2727 int rcRequest,
2728 void *pDeviceCtx,
2729 void *pvUser,
2730 const VRDEVIDEOINDEVICEDESC *pDeviceDesc,
2731 uint32_t cbDevice)
2732{
2733 ConsoleVRDPServer *pThis = static_cast<ConsoleVRDPServer*>(pvCallback);
2734 if (pThis->mEmWebcam)
2735 {
2736 pThis->mEmWebcam->EmWebcamCbDeviceDesc(rcRequest, pDeviceCtx, pvUser, pDeviceDesc, cbDevice);
2737 }
2738}
2739
2740/* static */ DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackVideoInControl(void *pvCallback,
2741 int rcRequest,
2742 void *pDeviceCtx,
2743 void *pvUser,
2744 const VRDEVIDEOINCTRLHDR *pControl,
2745 uint32_t cbControl)
2746{
2747 ConsoleVRDPServer *pThis = static_cast<ConsoleVRDPServer*>(pvCallback);
2748 if (pThis->mEmWebcam)
2749 {
2750 pThis->mEmWebcam->EmWebcamCbControl(rcRequest, pDeviceCtx, pvUser, pControl, cbControl);
2751 }
2752}
2753
2754/* static */ DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackVideoInFrame(void *pvCallback,
2755 int rcRequest,
2756 void *pDeviceCtx,
2757 const VRDEVIDEOINPAYLOADHDR *pFrame,
2758 uint32_t cbFrame)
2759{
2760 ConsoleVRDPServer *pThis = static_cast<ConsoleVRDPServer*>(pvCallback);
2761 if (pThis->mEmWebcam)
2762 {
2763 pThis->mEmWebcam->EmWebcamCbFrame(rcRequest, pDeviceCtx, pFrame, cbFrame);
2764 }
2765}
2766
2767int ConsoleVRDPServer::VideoInDeviceAttach(const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle, void *pvDeviceCtx)
2768{
2769 int rc;
2770
2771 if (mhServer && mpEntryPoints && m_interfaceVideoIn.VRDEVideoInDeviceAttach)
2772 {
2773 rc = m_interfaceVideoIn.VRDEVideoInDeviceAttach(mhServer, pDeviceHandle, pvDeviceCtx);
2774 }
2775 else
2776 {
2777 rc = VERR_NOT_SUPPORTED;
2778 }
2779
2780 return rc;
2781}
2782
2783int ConsoleVRDPServer::VideoInDeviceDetach(const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle)
2784{
2785 int rc;
2786
2787 if (mhServer && mpEntryPoints && m_interfaceVideoIn.VRDEVideoInDeviceDetach)
2788 {
2789 rc = m_interfaceVideoIn.VRDEVideoInDeviceDetach(mhServer, pDeviceHandle);
2790 }
2791 else
2792 {
2793 rc = VERR_NOT_SUPPORTED;
2794 }
2795
2796 return rc;
2797}
2798
2799int ConsoleVRDPServer::VideoInGetDeviceDesc(void *pvUser, const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle)
2800{
2801 int rc;
2802
2803 if (mhServer && mpEntryPoints && m_interfaceVideoIn.VRDEVideoInGetDeviceDesc)
2804 {
2805 rc = m_interfaceVideoIn.VRDEVideoInGetDeviceDesc(mhServer, pvUser, pDeviceHandle);
2806 }
2807 else
2808 {
2809 rc = VERR_NOT_SUPPORTED;
2810 }
2811
2812 return rc;
2813}
2814
2815int ConsoleVRDPServer::VideoInControl(void *pvUser, const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle,
2816 const VRDEVIDEOINCTRLHDR *pReq, uint32_t cbReq)
2817{
2818 int rc;
2819
2820 if (mhServer && mpEntryPoints && m_interfaceVideoIn.VRDEVideoInControl)
2821 {
2822 rc = m_interfaceVideoIn.VRDEVideoInControl(mhServer, pvUser, pDeviceHandle, pReq, cbReq);
2823 }
2824 else
2825 {
2826 rc = VERR_NOT_SUPPORTED;
2827 }
2828
2829 return rc;
2830}
2831
2832
2833/* static */ DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackInputSetup(void *pvCallback,
2834 int rcRequest,
2835 uint32_t u32Method,
2836 const void *pvResult,
2837 uint32_t cbResult)
2838{
2839 NOREF(pvCallback);
2840 NOREF(rcRequest);
2841 NOREF(u32Method);
2842 NOREF(pvResult);
2843 NOREF(cbResult);
2844}
2845
2846/* static */ DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackInputEvent(void *pvCallback,
2847 uint32_t u32Method,
2848 const void *pvEvent,
2849 uint32_t cbEvent)
2850{
2851 ConsoleVRDPServer *pThis = static_cast<ConsoleVRDPServer*>(pvCallback);
2852
2853 if (u32Method == VRDE_INPUT_METHOD_TOUCH)
2854 {
2855 if (cbEvent >= sizeof(VRDEINPUTHEADER))
2856 {
2857 VRDEINPUTHEADER *pHeader = (VRDEINPUTHEADER *)pvEvent;
2858
2859 if (pHeader->u16EventId == VRDEINPUT_EVENTID_TOUCH)
2860 {
2861 IMouse *pMouse = pThis->mConsole->i_getMouse();
2862
2863 VRDEINPUT_TOUCH_EVENT_PDU *p = (VRDEINPUT_TOUCH_EVENT_PDU *)pHeader;
2864
2865 uint16_t iFrame;
2866 for (iFrame = 0; iFrame < p->u16FrameCount; iFrame++)
2867 {
2868 VRDEINPUT_TOUCH_FRAME *pFrame = &p->aFrames[iFrame];
2869
2870 com::SafeArray<LONG64> aContacts(pFrame->u16ContactCount);
2871
2872 uint16_t iContact;
2873 for (iContact = 0; iContact < pFrame->u16ContactCount; iContact++)
2874 {
2875 VRDEINPUT_CONTACT_DATA *pContact = &pFrame->aContacts[iContact];
2876
2877 int16_t x = (int16_t)(pContact->i32X + 1);
2878 int16_t y = (int16_t)(pContact->i32Y + 1);
2879 uint8_t contactId = pContact->u8ContactId;
2880 uint8_t contactState = TouchContactState_None;
2881
2882 if (pContact->u32ContactFlags & VRDEINPUT_CONTACT_FLAG_INRANGE)
2883 {
2884 contactState |= TouchContactState_InRange;
2885 }
2886 if (pContact->u32ContactFlags & VRDEINPUT_CONTACT_FLAG_INCONTACT)
2887 {
2888 contactState |= TouchContactState_InContact;
2889 }
2890
2891 aContacts[iContact] = RT_MAKE_U64_FROM_U16((uint16_t)x,
2892 (uint16_t)y,
2893 RT_MAKE_U16(contactId, contactState),
2894 0);
2895 }
2896
2897 if (pFrame->u64FrameOffset == 0)
2898 {
2899 pThis->mu64TouchInputTimestampMCS = 0;
2900 }
2901 else
2902 {
2903 pThis->mu64TouchInputTimestampMCS += pFrame->u64FrameOffset;
2904 }
2905
2906 pMouse->PutEventMultiTouch(pFrame->u16ContactCount,
2907 ComSafeArrayAsInParam(aContacts),
2908 (ULONG)(pThis->mu64TouchInputTimestampMCS / 1000)); /* Micro->milliseconds. */
2909 }
2910 }
2911 else if (pHeader->u16EventId == VRDEINPUT_EVENTID_DISMISS_HOVERING_CONTACT)
2912 {
2913 /* @todo */
2914 }
2915 else
2916 {
2917 AssertMsgFailed(("EventId %d\n", pHeader->u16EventId));
2918 }
2919 }
2920 }
2921}
2922
2923
2924void ConsoleVRDPServer::EnableConnections(void)
2925{
2926 if (mpEntryPoints && mhServer)
2927 {
2928 mpEntryPoints->VRDEEnableConnections(mhServer, true);
2929
2930 /* Setup the generic TSMF channel. */
2931 setupTSMF();
2932 }
2933}
2934
2935void ConsoleVRDPServer::DisconnectClient(uint32_t u32ClientId, bool fReconnect)
2936{
2937 if (mpEntryPoints && mhServer)
2938 {
2939 mpEntryPoints->VRDEDisconnect(mhServer, u32ClientId, fReconnect);
2940 }
2941}
2942
2943int ConsoleVRDPServer::MousePointer(BOOL alpha,
2944 ULONG xHot,
2945 ULONG yHot,
2946 ULONG width,
2947 ULONG height,
2948 const uint8_t *pu8Shape)
2949{
2950 int rc = VINF_SUCCESS;
2951
2952 if (mhServer && mpEntryPoints && m_interfaceMousePtr.VRDEMousePtr)
2953 {
2954 size_t cbMask = (((width + 7) / 8) * height + 3) & ~3;
2955 size_t cbData = width * height * 4;
2956
2957 size_t cbDstMask = alpha? 0: cbMask;
2958
2959 size_t cbPointer = sizeof(VRDEMOUSEPTRDATA) + cbDstMask + cbData;
2960 uint8_t *pu8Pointer = (uint8_t *)RTMemAlloc(cbPointer);
2961 if (pu8Pointer != NULL)
2962 {
2963 VRDEMOUSEPTRDATA *pPointer = (VRDEMOUSEPTRDATA *)pu8Pointer;
2964
2965 pPointer->u16HotX = (uint16_t)xHot;
2966 pPointer->u16HotY = (uint16_t)yHot;
2967 pPointer->u16Width = (uint16_t)width;
2968 pPointer->u16Height = (uint16_t)height;
2969 pPointer->u16MaskLen = (uint16_t)cbDstMask;
2970 pPointer->u32DataLen = (uint32_t)cbData;
2971
2972 /* AND mask. */
2973 uint8_t *pu8Mask = pu8Pointer + sizeof(VRDEMOUSEPTRDATA);
2974 if (cbDstMask)
2975 {
2976 memcpy(pu8Mask, pu8Shape, cbDstMask);
2977 }
2978
2979 /* XOR mask */
2980 uint8_t *pu8Data = pu8Mask + pPointer->u16MaskLen;
2981 memcpy(pu8Data, pu8Shape + cbMask, cbData);
2982
2983 m_interfaceMousePtr.VRDEMousePtr(mhServer, pPointer);
2984
2985 RTMemFree(pu8Pointer);
2986 }
2987 else
2988 {
2989 rc = VERR_NO_MEMORY;
2990 }
2991 }
2992 else
2993 {
2994 rc = VERR_NOT_SUPPORTED;
2995 }
2996
2997 return rc;
2998}
2999
3000void ConsoleVRDPServer::MousePointerUpdate(const VRDECOLORPOINTER *pPointer)
3001{
3002 if (mpEntryPoints && mhServer)
3003 {
3004 mpEntryPoints->VRDEColorPointer(mhServer, pPointer);
3005 }
3006}
3007
3008void ConsoleVRDPServer::MousePointerHide(void)
3009{
3010 if (mpEntryPoints && mhServer)
3011 {
3012 mpEntryPoints->VRDEHidePointer(mhServer);
3013 }
3014}
3015
3016void ConsoleVRDPServer::Stop(void)
3017{
3018 Assert(VALID_PTR(this)); /** @todo r=bird: there are(/was) some odd cases where this buster was invalid on
3019 * linux. Just remove this when it's 100% sure that problem has been fixed. */
3020
3021#ifdef VBOX_WITH_USB
3022 remoteUSBThreadStop();
3023#endif /* VBOX_WITH_USB */
3024
3025 if (mhServer)
3026 {
3027 HVRDESERVER hServer = mhServer;
3028
3029 /* Reset the handle to avoid further calls to the server. */
3030 mhServer = 0;
3031
3032 /* Workaround for VM process hangs on termination.
3033 *
3034 * Make sure that the server is not currently processing a resize.
3035 * mhServer 0 will not allow to enter the server again.
3036 * Wait until any current resize returns from the server.
3037 */
3038 if (mcInResize)
3039 {
3040 LogRel(("VRDP: waiting for resize %d\n", mcInResize));
3041
3042 int i = 0;
3043 while (mcInResize && ++i < 100)
3044 {
3045 RTThreadSleep(10);
3046 }
3047 }
3048
3049 if (mpEntryPoints && hServer)
3050 {
3051 mpEntryPoints->VRDEDestroy(hServer);
3052 }
3053 }
3054
3055 mpfnAuthEntry = NULL;
3056 mpfnAuthEntry2 = NULL;
3057 mpfnAuthEntry3 = NULL;
3058
3059 if (mAuthLibrary)
3060 {
3061 RTLdrClose(mAuthLibrary);
3062 mAuthLibrary = 0;
3063 }
3064}
3065
3066/* Worker thread for Remote USB. The thread polls the clients for
3067 * the list of attached USB devices.
3068 * The thread is also responsible for attaching/detaching devices
3069 * to/from the VM.
3070 *
3071 * It is expected that attaching/detaching is not a frequent operation.
3072 *
3073 * The thread is always running when the VRDP server is active.
3074 *
3075 * The thread scans backends and requests the device list every 2 seconds.
3076 *
3077 * When device list is available, the thread calls the Console to process it.
3078 *
3079 */
3080#define VRDP_DEVICE_LIST_PERIOD_MS (2000)
3081
3082#ifdef VBOX_WITH_USB
3083static DECLCALLBACK(int) threadRemoteUSB(RTTHREAD self, void *pvUser)
3084{
3085 ConsoleVRDPServer *pOwner = (ConsoleVRDPServer *)pvUser;
3086
3087 LogFlow(("Console::threadRemoteUSB: start. owner = %p.\n", pOwner));
3088
3089 pOwner->notifyRemoteUSBThreadRunning(self);
3090
3091 while (pOwner->isRemoteUSBThreadRunning())
3092 {
3093 RemoteUSBBackend *pRemoteUSBBackend = NULL;
3094
3095 while ((pRemoteUSBBackend = pOwner->usbBackendGetNext(pRemoteUSBBackend)) != NULL)
3096 {
3097 pRemoteUSBBackend->PollRemoteDevices();
3098 }
3099
3100 pOwner->waitRemoteUSBThreadEvent(VRDP_DEVICE_LIST_PERIOD_MS);
3101
3102 LogFlow(("Console::threadRemoteUSB: iteration. owner = %p.\n", pOwner));
3103 }
3104
3105 return VINF_SUCCESS;
3106}
3107
3108void ConsoleVRDPServer::notifyRemoteUSBThreadRunning(RTTHREAD thread)
3109{
3110 mUSBBackends.thread = thread;
3111 mUSBBackends.fThreadRunning = true;
3112 int rc = RTThreadUserSignal(thread);
3113 AssertRC(rc);
3114}
3115
3116bool ConsoleVRDPServer::isRemoteUSBThreadRunning(void)
3117{
3118 return mUSBBackends.fThreadRunning;
3119}
3120
3121void ConsoleVRDPServer::waitRemoteUSBThreadEvent(RTMSINTERVAL cMillies)
3122{
3123 int rc = RTSemEventWait(mUSBBackends.event, cMillies);
3124 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
3125 NOREF(rc);
3126}
3127
3128void ConsoleVRDPServer::remoteUSBThreadStart(void)
3129{
3130 int rc = RTSemEventCreate(&mUSBBackends.event);
3131
3132 if (RT_FAILURE(rc))
3133 {
3134 AssertFailed();
3135 mUSBBackends.event = 0;
3136 }
3137
3138 if (RT_SUCCESS(rc))
3139 {
3140 rc = RTThreadCreate(&mUSBBackends.thread, threadRemoteUSB, this, 65536,
3141 RTTHREADTYPE_VRDP_IO, RTTHREADFLAGS_WAITABLE, "remote usb");
3142 }
3143
3144 if (RT_FAILURE(rc))
3145 {
3146 LogRel(("Warning: could not start the remote USB thread, rc = %Rrc!!!\n", rc));
3147 mUSBBackends.thread = NIL_RTTHREAD;
3148 }
3149 else
3150 {
3151 /* Wait until the thread is ready. */
3152 rc = RTThreadUserWait(mUSBBackends.thread, 60000);
3153 AssertRC(rc);
3154 Assert (mUSBBackends.fThreadRunning || RT_FAILURE(rc));
3155 }
3156}
3157
3158void ConsoleVRDPServer::remoteUSBThreadStop(void)
3159{
3160 mUSBBackends.fThreadRunning = false;
3161
3162 if (mUSBBackends.thread != NIL_RTTHREAD)
3163 {
3164 Assert (mUSBBackends.event != 0);
3165
3166 RTSemEventSignal(mUSBBackends.event);
3167
3168 int rc = RTThreadWait(mUSBBackends.thread, 60000, NULL);
3169 AssertRC(rc);
3170
3171 mUSBBackends.thread = NIL_RTTHREAD;
3172 }
3173
3174 if (mUSBBackends.event)
3175 {
3176 RTSemEventDestroy(mUSBBackends.event);
3177 mUSBBackends.event = 0;
3178 }
3179}
3180#endif /* VBOX_WITH_USB */
3181
3182typedef struct AuthCtx
3183{
3184 AuthResult result;
3185
3186 PAUTHENTRY3 pfnAuthEntry3;
3187 PAUTHENTRY2 pfnAuthEntry2;
3188 PAUTHENTRY pfnAuthEntry;
3189
3190 const char *pszCaller;
3191 PAUTHUUID pUuid;
3192 AuthGuestJudgement guestJudgement;
3193 const char *pszUser;
3194 const char *pszPassword;
3195 const char *pszDomain;
3196 int fLogon;
3197 unsigned clientId;
3198} AuthCtx;
3199
3200static DECLCALLBACK(int) authThread(RTTHREAD self, void *pvUser)
3201{
3202 AuthCtx *pCtx = (AuthCtx *)pvUser;
3203
3204 if (pCtx->pfnAuthEntry3)
3205 {
3206 pCtx->result = pCtx->pfnAuthEntry3(pCtx->pszCaller, pCtx->pUuid, pCtx->guestJudgement,
3207 pCtx->pszUser, pCtx->pszPassword, pCtx->pszDomain,
3208 pCtx->fLogon, pCtx->clientId);
3209 }
3210 else if (pCtx->pfnAuthEntry2)
3211 {
3212 pCtx->result = pCtx->pfnAuthEntry2(pCtx->pUuid, pCtx->guestJudgement,
3213 pCtx->pszUser, pCtx->pszPassword, pCtx->pszDomain,
3214 pCtx->fLogon, pCtx->clientId);
3215 }
3216 else if (pCtx->pfnAuthEntry)
3217 {
3218 pCtx->result = pCtx->pfnAuthEntry(pCtx->pUuid, pCtx->guestJudgement,
3219 pCtx->pszUser, pCtx->pszPassword, pCtx->pszDomain);
3220 }
3221 return VINF_SUCCESS;
3222}
3223
3224static AuthResult authCall(AuthCtx *pCtx)
3225{
3226 AuthResult result = AuthResultAccessDenied;
3227
3228 /* Use a separate thread because external modules might need a lot of stack space. */
3229 RTTHREAD thread = NIL_RTTHREAD;
3230 int rc = RTThreadCreate(&thread, authThread, pCtx, 512*_1K,
3231 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "VRDEAuth");
3232 LogFlow(("authCall: RTThreadCreate %Rrc\n", rc));
3233
3234 if (RT_SUCCESS(rc))
3235 {
3236 rc = RTThreadWait(thread, RT_INDEFINITE_WAIT, NULL);
3237 LogFlow(("authCall: RTThreadWait %Rrc\n", rc));
3238 }
3239
3240 if (RT_SUCCESS(rc))
3241 {
3242 /* Only update the result if the thread finished without errors. */
3243 result = pCtx->result;
3244 }
3245 else
3246 {
3247 LogRel(("AUTH: unable to execute the auth thread %Rrc\n", rc));
3248 }
3249
3250 return result;
3251}
3252
3253AuthResult ConsoleVRDPServer::Authenticate(const Guid &uuid, AuthGuestJudgement guestJudgement,
3254 const char *pszUser, const char *pszPassword, const char *pszDomain,
3255 uint32_t u32ClientId)
3256{
3257 AUTHUUID rawuuid;
3258
3259 memcpy(rawuuid, uuid.raw(), sizeof(rawuuid));
3260
3261 LogFlow(("ConsoleVRDPServer::Authenticate: uuid = %RTuuid, guestJudgement = %d, pszUser = %s, pszPassword = %s, pszDomain = %s, u32ClientId = %d\n",
3262 rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, u32ClientId));
3263
3264 /*
3265 * Called only from VRDP input thread. So thread safety is not required.
3266 */
3267
3268 if (!mAuthLibrary)
3269 {
3270 /* Load the external authentication library. */
3271 Bstr authLibrary;
3272 mConsole->i_getVRDEServer()->COMGETTER(AuthLibrary)(authLibrary.asOutParam());
3273
3274 Utf8Str filename = authLibrary;
3275
3276 LogRel(("AUTH: loading external authentication library '%ls'\n", authLibrary.raw()));
3277
3278 int rc;
3279 if (RTPathHavePath(filename.c_str()))
3280 rc = RTLdrLoad(filename.c_str(), &mAuthLibrary);
3281 else
3282 {
3283 rc = RTLdrLoadAppPriv(filename.c_str(), &mAuthLibrary);
3284 if (RT_FAILURE(rc))
3285 {
3286 /* Backward compatibility with old default 'VRDPAuth' name.
3287 * Try to load new default 'VBoxAuth' instead.
3288 */
3289 if (filename == "VRDPAuth")
3290 {
3291 LogRel(("AUTH: ConsoleVRDPServer::Authenticate: loading external authentication library VBoxAuth\n"));
3292 rc = RTLdrLoadAppPriv("VBoxAuth", &mAuthLibrary);
3293 }
3294 }
3295 }
3296
3297 if (RT_FAILURE(rc))
3298 LogRel(("AUTH: Failed to load external authentication library. Error code: %Rrc\n", rc));
3299
3300 if (RT_SUCCESS(rc))
3301 {
3302 typedef struct AuthEntryInfoStruct
3303 {
3304 const char *pszName;
3305 void **ppvAddress;
3306
3307 } AuthEntryInfo;
3308 AuthEntryInfo entries[] =
3309 {
3310 { AUTHENTRY3_NAME, (void **)&mpfnAuthEntry3 },
3311 { AUTHENTRY2_NAME, (void **)&mpfnAuthEntry2 },
3312 { AUTHENTRY_NAME, (void **)&mpfnAuthEntry },
3313 { NULL, NULL }
3314 };
3315
3316 /* Get the entry point. */
3317 AuthEntryInfo *pEntryInfo = &entries[0];
3318 while (pEntryInfo->pszName)
3319 {
3320 *pEntryInfo->ppvAddress = NULL;
3321
3322 int rc2 = RTLdrGetSymbol(mAuthLibrary, pEntryInfo->pszName, pEntryInfo->ppvAddress);
3323 if (RT_SUCCESS(rc2))
3324 {
3325 /* Found an entry point. */
3326 LogRel(("AUTH: Using entry point '%s'.\n", pEntryInfo->pszName));
3327 rc = VINF_SUCCESS;
3328 break;
3329 }
3330
3331 if (rc2 != VERR_SYMBOL_NOT_FOUND)
3332 {
3333 LogRel(("AUTH: Could not resolve import '%s'. Error code: %Rrc\n", pEntryInfo->pszName, rc2));
3334 }
3335 rc = rc2;
3336
3337 pEntryInfo++;
3338 }
3339 }
3340
3341 if (RT_FAILURE(rc))
3342 {
3343 mConsole->setError(E_FAIL,
3344 mConsole->tr("Could not load the external authentication library '%s' (%Rrc)"),
3345 filename.c_str(),
3346 rc);
3347
3348 mpfnAuthEntry = NULL;
3349 mpfnAuthEntry2 = NULL;
3350 mpfnAuthEntry3 = NULL;
3351
3352 if (mAuthLibrary)
3353 {
3354 RTLdrClose(mAuthLibrary);
3355 mAuthLibrary = 0;
3356 }
3357
3358 return AuthResultAccessDenied;
3359 }
3360 }
3361
3362 Assert(mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2 || mpfnAuthEntry3));
3363
3364 AuthCtx ctx;
3365 ctx.result = AuthResultAccessDenied; /* Denied by default. */
3366 ctx.pfnAuthEntry3 = mpfnAuthEntry3;
3367 ctx.pfnAuthEntry2 = mpfnAuthEntry2;
3368 ctx.pfnAuthEntry = mpfnAuthEntry;
3369 ctx.pszCaller = "vrde";
3370 ctx.pUuid = &rawuuid;
3371 ctx.guestJudgement = guestJudgement;
3372 ctx.pszUser = pszUser;
3373 ctx.pszPassword = pszPassword;
3374 ctx.pszDomain = pszDomain;
3375 ctx.fLogon = true;
3376 ctx.clientId = u32ClientId;
3377
3378 AuthResult result = authCall(&ctx);
3379
3380 switch (result)
3381 {
3382 case AuthResultAccessDenied:
3383 LogRel(("AUTH: external authentication module returned 'access denied'\n"));
3384 break;
3385 case AuthResultAccessGranted:
3386 LogRel(("AUTH: external authentication module returned 'access granted'\n"));
3387 break;
3388 case AuthResultDelegateToGuest:
3389 LogRel(("AUTH: external authentication module returned 'delegate request to guest'\n"));
3390 break;
3391 default:
3392 LogRel(("AUTH: external authentication module returned incorrect return code %d\n", result));
3393 result = AuthResultAccessDenied;
3394 }
3395
3396 LogFlow(("ConsoleVRDPServer::Authenticate: result = %d\n", result));
3397
3398 return result;
3399}
3400
3401void ConsoleVRDPServer::AuthDisconnect(const Guid &uuid, uint32_t u32ClientId)
3402{
3403 AUTHUUID rawuuid;
3404
3405 memcpy(rawuuid, uuid.raw(), sizeof(rawuuid));
3406
3407 LogFlow(("ConsoleVRDPServer::AuthDisconnect: uuid = %RTuuid, u32ClientId = %d\n",
3408 rawuuid, u32ClientId));
3409
3410 Assert(mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2 || mpfnAuthEntry3));
3411
3412 AuthCtx ctx;
3413 ctx.result = AuthResultAccessDenied; /* Not used. */
3414 ctx.pfnAuthEntry3 = mpfnAuthEntry3;
3415 ctx.pfnAuthEntry2 = mpfnAuthEntry2;
3416 ctx.pfnAuthEntry = NULL; /* Does not use disconnect notification. */
3417 ctx.pszCaller = "vrde";
3418 ctx.pUuid = &rawuuid;
3419 ctx.guestJudgement = AuthGuestNotAsked;
3420 ctx.pszUser = NULL;
3421 ctx.pszPassword = NULL;
3422 ctx.pszDomain = NULL;
3423 ctx.fLogon = false;
3424 ctx.clientId = u32ClientId;
3425
3426 authCall(&ctx);
3427}
3428
3429int ConsoleVRDPServer::lockConsoleVRDPServer(void)
3430{
3431 int rc = RTCritSectEnter(&mCritSect);
3432 AssertRC(rc);
3433 return rc;
3434}
3435
3436void ConsoleVRDPServer::unlockConsoleVRDPServer(void)
3437{
3438 RTCritSectLeave(&mCritSect);
3439}
3440
3441DECLCALLBACK(int) ConsoleVRDPServer::ClipboardCallback(void *pvCallback,
3442 uint32_t u32ClientId,
3443 uint32_t u32Function,
3444 uint32_t u32Format,
3445 const void *pvData,
3446 uint32_t cbData)
3447{
3448 LogFlowFunc(("pvCallback = %p, u32ClientId = %d, u32Function = %d, u32Format = 0x%08X, pvData = %p, cbData = %d\n",
3449 pvCallback, u32ClientId, u32Function, u32Format, pvData, cbData));
3450
3451 int rc = VINF_SUCCESS;
3452
3453 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvCallback);
3454
3455 NOREF(u32ClientId);
3456
3457 switch (u32Function)
3458 {
3459 case VRDE_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE:
3460 {
3461 if (pServer->mpfnClipboardCallback)
3462 {
3463 pServer->mpfnClipboardCallback(VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE,
3464 u32Format,
3465 (void *)pvData,
3466 cbData);
3467 }
3468 } break;
3469
3470 case VRDE_CLIPBOARD_FUNCTION_DATA_READ:
3471 {
3472 if (pServer->mpfnClipboardCallback)
3473 {
3474 pServer->mpfnClipboardCallback(VBOX_CLIPBOARD_EXT_FN_DATA_READ,
3475 u32Format,
3476 (void *)pvData,
3477 cbData);
3478 }
3479 } break;
3480
3481 default:
3482 rc = VERR_NOT_SUPPORTED;
3483 }
3484
3485 return rc;
3486}
3487
3488DECLCALLBACK(int) ConsoleVRDPServer::ClipboardServiceExtension(void *pvExtension,
3489 uint32_t u32Function,
3490 void *pvParms,
3491 uint32_t cbParms)
3492{
3493 LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
3494 pvExtension, u32Function, pvParms, cbParms));
3495
3496 int rc = VINF_SUCCESS;
3497
3498 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvExtension);
3499
3500 VBOXCLIPBOARDEXTPARMS *pParms = (VBOXCLIPBOARDEXTPARMS *)pvParms;
3501
3502 switch (u32Function)
3503 {
3504 case VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK:
3505 {
3506 pServer->mpfnClipboardCallback = pParms->u.pfnCallback;
3507 } break;
3508
3509 case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
3510 {
3511 /* The guest announces clipboard formats. This must be delivered to all clients. */
3512 if (mpEntryPoints && pServer->mhServer)
3513 {
3514 mpEntryPoints->VRDEClipboard(pServer->mhServer,
3515 VRDE_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE,
3516 pParms->u32Format,
3517 NULL,
3518 0,
3519 NULL);
3520 }
3521 } break;
3522
3523 case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
3524 {
3525 /* The clipboard service expects that the pvData buffer will be filled
3526 * with clipboard data. The server returns the data from the client that
3527 * announced the requested format most recently.
3528 */
3529 if (mpEntryPoints && pServer->mhServer)
3530 {
3531 mpEntryPoints->VRDEClipboard(pServer->mhServer,
3532 VRDE_CLIPBOARD_FUNCTION_DATA_READ,
3533 pParms->u32Format,
3534 pParms->u.pvData,
3535 pParms->cbData,
3536 &pParms->cbData);
3537 }
3538 } break;
3539
3540 case VBOX_CLIPBOARD_EXT_FN_DATA_WRITE:
3541 {
3542 if (mpEntryPoints && pServer->mhServer)
3543 {
3544 mpEntryPoints->VRDEClipboard(pServer->mhServer,
3545 VRDE_CLIPBOARD_FUNCTION_DATA_WRITE,
3546 pParms->u32Format,
3547 pParms->u.pvData,
3548 pParms->cbData,
3549 NULL);
3550 }
3551 } break;
3552
3553 default:
3554 rc = VERR_NOT_SUPPORTED;
3555 }
3556
3557 return rc;
3558}
3559
3560void ConsoleVRDPServer::ClipboardCreate(uint32_t u32ClientId)
3561{
3562 int rc = lockConsoleVRDPServer();
3563
3564 if (RT_SUCCESS(rc))
3565 {
3566 if (mcClipboardRefs == 0)
3567 {
3568 rc = HGCMHostRegisterServiceExtension(&mhClipboard, "VBoxSharedClipboard", ClipboardServiceExtension, this);
3569
3570 if (RT_SUCCESS(rc))
3571 {
3572 mcClipboardRefs++;
3573 }
3574 }
3575
3576 unlockConsoleVRDPServer();
3577 }
3578}
3579
3580void ConsoleVRDPServer::ClipboardDelete(uint32_t u32ClientId)
3581{
3582 int rc = lockConsoleVRDPServer();
3583
3584 if (RT_SUCCESS(rc))
3585 {
3586 mcClipboardRefs--;
3587
3588 if (mcClipboardRefs == 0)
3589 {
3590 HGCMHostUnregisterServiceExtension(mhClipboard);
3591 }
3592
3593 unlockConsoleVRDPServer();
3594 }
3595}
3596
3597/* That is called on INPUT thread of the VRDP server.
3598 * The ConsoleVRDPServer keeps a list of created backend instances.
3599 */
3600void ConsoleVRDPServer::USBBackendCreate(uint32_t u32ClientId, void **ppvIntercept)
3601{
3602#ifdef VBOX_WITH_USB
3603 LogFlow(("ConsoleVRDPServer::USBBackendCreate: u32ClientId = %d\n", u32ClientId));
3604
3605 /* Create a new instance of the USB backend for the new client. */
3606 RemoteUSBBackend *pRemoteUSBBackend = new RemoteUSBBackend(mConsole, this, u32ClientId);
3607
3608 if (pRemoteUSBBackend)
3609 {
3610 pRemoteUSBBackend->AddRef(); /* 'Release' called in USBBackendDelete. */
3611
3612 /* Append the new instance in the list. */
3613 int rc = lockConsoleVRDPServer();
3614
3615 if (RT_SUCCESS(rc))
3616 {
3617 pRemoteUSBBackend->pNext = mUSBBackends.pHead;
3618 if (mUSBBackends.pHead)
3619 {
3620 mUSBBackends.pHead->pPrev = pRemoteUSBBackend;
3621 }
3622 else
3623 {
3624 mUSBBackends.pTail = pRemoteUSBBackend;
3625 }
3626
3627 mUSBBackends.pHead = pRemoteUSBBackend;
3628
3629 unlockConsoleVRDPServer();
3630
3631 if (ppvIntercept)
3632 {
3633 *ppvIntercept = pRemoteUSBBackend;
3634 }
3635 }
3636
3637 if (RT_FAILURE(rc))
3638 {
3639 pRemoteUSBBackend->Release();
3640 }
3641 }
3642#endif /* VBOX_WITH_USB */
3643}
3644
3645void ConsoleVRDPServer::USBBackendDelete(uint32_t u32ClientId)
3646{
3647#ifdef VBOX_WITH_USB
3648 LogFlow(("ConsoleVRDPServer::USBBackendDelete: u32ClientId = %d\n", u32ClientId));
3649
3650 RemoteUSBBackend *pRemoteUSBBackend = NULL;
3651
3652 /* Find the instance. */
3653 int rc = lockConsoleVRDPServer();
3654
3655 if (RT_SUCCESS(rc))
3656 {
3657 pRemoteUSBBackend = usbBackendFind(u32ClientId);
3658
3659 if (pRemoteUSBBackend)
3660 {
3661 /* Notify that it will be deleted. */
3662 pRemoteUSBBackend->NotifyDelete();
3663 }
3664
3665 unlockConsoleVRDPServer();
3666 }
3667
3668 if (pRemoteUSBBackend)
3669 {
3670 /* Here the instance has been excluded from the list and can be dereferenced. */
3671 pRemoteUSBBackend->Release();
3672 }
3673#endif
3674}
3675
3676void *ConsoleVRDPServer::USBBackendRequestPointer(uint32_t u32ClientId, const Guid *pGuid)
3677{
3678#ifdef VBOX_WITH_USB
3679 RemoteUSBBackend *pRemoteUSBBackend = NULL;
3680
3681 /* Find the instance. */
3682 int rc = lockConsoleVRDPServer();
3683
3684 if (RT_SUCCESS(rc))
3685 {
3686 pRemoteUSBBackend = usbBackendFind(u32ClientId);
3687
3688 if (pRemoteUSBBackend)
3689 {
3690 /* Inform the backend instance that it is referenced by the Guid. */
3691 bool fAdded = pRemoteUSBBackend->addUUID(pGuid);
3692
3693 if (fAdded)
3694 {
3695 /* Reference the instance because its pointer is being taken. */
3696 pRemoteUSBBackend->AddRef(); /* 'Release' is called in USBBackendReleasePointer. */
3697 }
3698 else
3699 {
3700 pRemoteUSBBackend = NULL;
3701 }
3702 }
3703
3704 unlockConsoleVRDPServer();
3705 }
3706
3707 if (pRemoteUSBBackend)
3708 {
3709 return pRemoteUSBBackend->GetBackendCallbackPointer();
3710 }
3711
3712#endif
3713 return NULL;
3714}
3715
3716void ConsoleVRDPServer::USBBackendReleasePointer(const Guid *pGuid)
3717{
3718#ifdef VBOX_WITH_USB
3719 RemoteUSBBackend *pRemoteUSBBackend = NULL;
3720
3721 /* Find the instance. */
3722 int rc = lockConsoleVRDPServer();
3723
3724 if (RT_SUCCESS(rc))
3725 {
3726 pRemoteUSBBackend = usbBackendFindByUUID(pGuid);
3727
3728 if (pRemoteUSBBackend)
3729 {
3730 pRemoteUSBBackend->removeUUID(pGuid);
3731 }
3732
3733 unlockConsoleVRDPServer();
3734
3735 if (pRemoteUSBBackend)
3736 {
3737 pRemoteUSBBackend->Release();
3738 }
3739 }
3740#endif
3741}
3742
3743RemoteUSBBackend *ConsoleVRDPServer::usbBackendGetNext(RemoteUSBBackend *pRemoteUSBBackend)
3744{
3745 LogFlow(("ConsoleVRDPServer::usbBackendGetNext: pBackend = %p\n", pRemoteUSBBackend));
3746
3747 RemoteUSBBackend *pNextRemoteUSBBackend = NULL;
3748#ifdef VBOX_WITH_USB
3749
3750 int rc = lockConsoleVRDPServer();
3751
3752 if (RT_SUCCESS(rc))
3753 {
3754 if (pRemoteUSBBackend == NULL)
3755 {
3756 /* The first backend in the list is requested. */
3757 pNextRemoteUSBBackend = mUSBBackends.pHead;
3758 }
3759 else
3760 {
3761 /* Get pointer to the next backend. */
3762 pNextRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
3763 }
3764
3765 if (pNextRemoteUSBBackend)
3766 {
3767 pNextRemoteUSBBackend->AddRef();
3768 }
3769
3770 unlockConsoleVRDPServer();
3771
3772 if (pRemoteUSBBackend)
3773 {
3774 pRemoteUSBBackend->Release();
3775 }
3776 }
3777#endif
3778
3779 return pNextRemoteUSBBackend;
3780}
3781
3782#ifdef VBOX_WITH_USB
3783/* Internal method. Called under the ConsoleVRDPServerLock. */
3784RemoteUSBBackend *ConsoleVRDPServer::usbBackendFind(uint32_t u32ClientId)
3785{
3786 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
3787
3788 while (pRemoteUSBBackend)
3789 {
3790 if (pRemoteUSBBackend->ClientId() == u32ClientId)
3791 {
3792 break;
3793 }
3794
3795 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
3796 }
3797
3798 return pRemoteUSBBackend;
3799}
3800
3801/* Internal method. Called under the ConsoleVRDPServerLock. */
3802RemoteUSBBackend *ConsoleVRDPServer::usbBackendFindByUUID(const Guid *pGuid)
3803{
3804 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
3805
3806 while (pRemoteUSBBackend)
3807 {
3808 if (pRemoteUSBBackend->findUUID(pGuid))
3809 {
3810 break;
3811 }
3812
3813 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
3814 }
3815
3816 return pRemoteUSBBackend;
3817}
3818#endif
3819
3820/* Internal method. Called by the backend destructor. */
3821void ConsoleVRDPServer::usbBackendRemoveFromList(RemoteUSBBackend *pRemoteUSBBackend)
3822{
3823#ifdef VBOX_WITH_USB
3824 int rc = lockConsoleVRDPServer();
3825 AssertRC(rc);
3826
3827 /* Exclude the found instance from the list. */
3828 if (pRemoteUSBBackend->pNext)
3829 {
3830 pRemoteUSBBackend->pNext->pPrev = pRemoteUSBBackend->pPrev;
3831 }
3832 else
3833 {
3834 mUSBBackends.pTail = (RemoteUSBBackend *)pRemoteUSBBackend->pPrev;
3835 }
3836
3837 if (pRemoteUSBBackend->pPrev)
3838 {
3839 pRemoteUSBBackend->pPrev->pNext = pRemoteUSBBackend->pNext;
3840 }
3841 else
3842 {
3843 mUSBBackends.pHead = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
3844 }
3845
3846 pRemoteUSBBackend->pNext = pRemoteUSBBackend->pPrev = NULL;
3847
3848 unlockConsoleVRDPServer();
3849#endif
3850}
3851
3852
3853void ConsoleVRDPServer::SendUpdate(unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate) const
3854{
3855 if (mpEntryPoints && mhServer)
3856 {
3857 mpEntryPoints->VRDEUpdate(mhServer, uScreenId, pvUpdate, cbUpdate);
3858 }
3859}
3860
3861void ConsoleVRDPServer::SendResize(void)
3862{
3863 if (mpEntryPoints && mhServer)
3864 {
3865 ++mcInResize;
3866 mpEntryPoints->VRDEResize(mhServer);
3867 --mcInResize;
3868 }
3869}
3870
3871void ConsoleVRDPServer::SendUpdateBitmap(unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h) const
3872{
3873 VRDEORDERHDR update;
3874 update.x = x;
3875 update.y = y;
3876 update.w = w;
3877 update.h = h;
3878 if (mpEntryPoints && mhServer)
3879 {
3880 mpEntryPoints->VRDEUpdate(mhServer, uScreenId, &update, sizeof(update));
3881 }
3882}
3883
3884void ConsoleVRDPServer::SendAudioSamples(void *pvSamples, uint32_t cSamples, VRDEAUDIOFORMAT format) const
3885{
3886 if (mpEntryPoints && mhServer)
3887 {
3888 mpEntryPoints->VRDEAudioSamples(mhServer, pvSamples, cSamples, format);
3889 }
3890}
3891
3892void ConsoleVRDPServer::SendAudioVolume(uint16_t left, uint16_t right) const
3893{
3894 if (mpEntryPoints && mhServer)
3895 {
3896 mpEntryPoints->VRDEAudioVolume(mhServer, left, right);
3897 }
3898}
3899
3900void ConsoleVRDPServer::SendUSBRequest(uint32_t u32ClientId, void *pvParms, uint32_t cbParms) const
3901{
3902 if (mpEntryPoints && mhServer)
3903 {
3904 mpEntryPoints->VRDEUSBRequest(mhServer, u32ClientId, pvParms, cbParms);
3905 }
3906}
3907
3908/* @todo rc not needed? */
3909int ConsoleVRDPServer::SendAudioInputBegin(void **ppvUserCtx,
3910 void *pvContext,
3911 uint32_t cSamples,
3912 uint32_t iSampleHz,
3913 uint32_t cChannels,
3914 uint32_t cBits)
3915{
3916 if (mpEntryPoints && mhServer && mpEntryPoints->VRDEAudioInOpen)
3917 {
3918 uint32_t u32ClientId = ASMAtomicReadU32(&mu32AudioInputClientId);
3919 if (u32ClientId != 0) /* 0 would mean broadcast to all clients. */
3920 {
3921 VRDEAUDIOFORMAT audioFormat = VRDE_AUDIO_FMT_MAKE(iSampleHz, cChannels, cBits, 0);
3922 mpEntryPoints->VRDEAudioInOpen (mhServer,
3923 pvContext,
3924 u32ClientId,
3925 audioFormat,
3926 cSamples);
3927#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
3928 //*ppvUserCtx = NULL;
3929#else
3930 *ppvUserCtx = NULL; /* This is the ConsoleVRDPServer context.
3931- * Currently not used because only one client is allowed to
3932- * do audio input and the client id is saved by the ConsoleVRDPServer.
3933- */
3934#endif
3935
3936 return VINF_SUCCESS;
3937 }
3938 }
3939 return VERR_NOT_SUPPORTED;
3940}
3941
3942void ConsoleVRDPServer::SendAudioInputEnd(void *pvUserCtx)
3943{
3944 if (mpEntryPoints && mhServer && mpEntryPoints->VRDEAudioInClose)
3945 {
3946 uint32_t u32ClientId = ASMAtomicReadU32(&mu32AudioInputClientId);
3947 if (u32ClientId != 0) /* 0 would mean broadcast to all clients. */
3948 {
3949 mpEntryPoints->VRDEAudioInClose(mhServer, u32ClientId);
3950 }
3951 }
3952}
3953
3954
3955void ConsoleVRDPServer::QueryInfo(uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const
3956{
3957 if (index == VRDE_QI_PORT)
3958 {
3959 uint32_t cbOut = sizeof(int32_t);
3960
3961 if (cbBuffer >= cbOut)
3962 {
3963 *pcbOut = cbOut;
3964 *(int32_t *)pvBuffer = (int32_t)mVRDPBindPort;
3965 }
3966 }
3967 else if (mpEntryPoints && mhServer)
3968 {
3969 mpEntryPoints->VRDEQueryInfo(mhServer, index, pvBuffer, cbBuffer, pcbOut);
3970 }
3971}
3972
3973/* static */ int ConsoleVRDPServer::loadVRDPLibrary(const char *pszLibraryName)
3974{
3975 int rc = VINF_SUCCESS;
3976
3977 if (mVRDPLibrary == NIL_RTLDRMOD)
3978 {
3979 RTERRINFOSTATIC ErrInfo;
3980 RTErrInfoInitStatic(&ErrInfo);
3981
3982 if (RTPathHavePath(pszLibraryName))
3983 rc = SUPR3HardenedLdrLoadPlugIn(pszLibraryName, &mVRDPLibrary, &ErrInfo.Core);
3984 else
3985 rc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &mVRDPLibrary, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
3986 if (RT_SUCCESS(rc))
3987 {
3988 struct SymbolEntry
3989 {
3990 const char *name;
3991 void **ppfn;
3992 };
3993
3994 #define DEFSYMENTRY(a) { #a, (void**)&mpfn##a }
3995
3996 static const struct SymbolEntry s_aSymbols[] =
3997 {
3998 DEFSYMENTRY(VRDECreateServer)
3999 };
4000
4001 #undef DEFSYMENTRY
4002
4003 for (unsigned i = 0; i < RT_ELEMENTS(s_aSymbols); i++)
4004 {
4005 rc = RTLdrGetSymbol(mVRDPLibrary, s_aSymbols[i].name, s_aSymbols[i].ppfn);
4006
4007 if (RT_FAILURE(rc))
4008 {
4009 LogRel(("VRDE: Error resolving symbol '%s', rc %Rrc.\n", s_aSymbols[i].name, rc));
4010 break;
4011 }
4012 }
4013 }
4014 else
4015 {
4016 if (RTErrInfoIsSet(&ErrInfo.Core))
4017 LogRel(("VRDE: Error loading the library '%s': %s (%Rrc)\n", pszLibraryName, ErrInfo.Core.pszMsg, rc));
4018 else
4019 LogRel(("VRDE: Error loading the library '%s' rc = %Rrc.\n", pszLibraryName, rc));
4020
4021 mVRDPLibrary = NIL_RTLDRMOD;
4022 }
4023 }
4024
4025 if (RT_FAILURE(rc))
4026 {
4027 if (mVRDPLibrary != NIL_RTLDRMOD)
4028 {
4029 RTLdrClose(mVRDPLibrary);
4030 mVRDPLibrary = NIL_RTLDRMOD;
4031 }
4032 }
4033
4034 return rc;
4035}
4036
4037/*
4038 * IVRDEServerInfo implementation.
4039 */
4040// constructor / destructor
4041/////////////////////////////////////////////////////////////////////////////
4042
4043VRDEServerInfo::VRDEServerInfo()
4044 : mParent(NULL)
4045{
4046}
4047
4048VRDEServerInfo::~VRDEServerInfo()
4049{
4050}
4051
4052
4053HRESULT VRDEServerInfo::FinalConstruct()
4054{
4055 return BaseFinalConstruct();
4056}
4057
4058void VRDEServerInfo::FinalRelease()
4059{
4060 uninit();
4061 BaseFinalRelease();
4062}
4063
4064// public methods only for internal purposes
4065/////////////////////////////////////////////////////////////////////////////
4066
4067/**
4068 * Initializes the guest object.
4069 */
4070HRESULT VRDEServerInfo::init(Console *aParent)
4071{
4072 LogFlowThisFunc(("aParent=%p\n", aParent));
4073
4074 ComAssertRet(aParent, E_INVALIDARG);
4075
4076 /* Enclose the state transition NotReady->InInit->Ready */
4077 AutoInitSpan autoInitSpan(this);
4078 AssertReturn(autoInitSpan.isOk(), E_FAIL);
4079
4080 unconst(mParent) = aParent;
4081
4082 /* Confirm a successful initialization */
4083 autoInitSpan.setSucceeded();
4084
4085 return S_OK;
4086}
4087
4088/**
4089 * Uninitializes the instance and sets the ready flag to FALSE.
4090 * Called either from FinalRelease() or by the parent when it gets destroyed.
4091 */
4092void VRDEServerInfo::uninit()
4093{
4094 LogFlowThisFunc(("\n"));
4095
4096 /* Enclose the state transition Ready->InUninit->NotReady */
4097 AutoUninitSpan autoUninitSpan(this);
4098 if (autoUninitSpan.uninitDone())
4099 return;
4100
4101 unconst(mParent) = NULL;
4102}
4103
4104// IVRDEServerInfo properties
4105/////////////////////////////////////////////////////////////////////////////
4106
4107#define IMPL_GETTER_BOOL(_aType, _aName, _aIndex) \
4108 HRESULT VRDEServerInfo::get##_aName(_aType *a##_aName) \
4109 { \
4110 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
4111 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
4112 \
4113 uint32_t value; \
4114 uint32_t cbOut = 0; \
4115 \
4116 mParent->i_consoleVRDPServer()->QueryInfo \
4117 (_aIndex, &value, sizeof(value), &cbOut); \
4118 \
4119 *a##_aName = cbOut? !!value: FALSE; \
4120 \
4121 return S_OK; \
4122 } \
4123 extern void IMPL_GETTER_BOOL_DUMMY(void)
4124
4125#define IMPL_GETTER_SCALAR(_aType, _aName, _aIndex, _aValueMask) \
4126 HRESULT VRDEServerInfo::get##_aName(_aType *a##_aName) \
4127 { \
4128 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
4129 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
4130 \
4131 _aType value; \
4132 uint32_t cbOut = 0; \
4133 \
4134 mParent->i_consoleVRDPServer()->QueryInfo \
4135 (_aIndex, &value, sizeof(value), &cbOut); \
4136 \
4137 if (_aValueMask) value &= (_aValueMask); \
4138 *a##_aName = cbOut? value: 0; \
4139 \
4140 return S_OK; \
4141 } \
4142 extern void IMPL_GETTER_SCALAR_DUMMY(void)
4143
4144#define IMPL_GETTER_UTF8STR(_aType, _aName, _aIndex) \
4145 HRESULT VRDEServerInfo::get##_aName(_aType &a##_aName) \
4146 { \
4147 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
4148 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
4149 \
4150 uint32_t cbOut = 0; \
4151 \
4152 mParent->i_consoleVRDPServer()->QueryInfo \
4153 (_aIndex, NULL, 0, &cbOut); \
4154 \
4155 if (cbOut == 0) \
4156 { \
4157 a##_aName = Utf8Str::Empty; \
4158 return S_OK; \
4159 } \
4160 \
4161 char *pchBuffer = (char *)RTMemTmpAlloc(cbOut); \
4162 \
4163 if (!pchBuffer) \
4164 { \
4165 Log(("VRDEServerInfo::" \
4166 #_aName \
4167 ": Failed to allocate memory %d bytes\n", cbOut)); \
4168 return E_OUTOFMEMORY; \
4169 } \
4170 \
4171 mParent->i_consoleVRDPServer()->QueryInfo \
4172 (_aIndex, pchBuffer, cbOut, &cbOut); \
4173 \
4174 a##_aName = pchBuffer; \
4175 \
4176 RTMemTmpFree(pchBuffer); \
4177 \
4178 return S_OK; \
4179 } \
4180 extern void IMPL_GETTER_BSTR_DUMMY(void)
4181
4182IMPL_GETTER_BOOL (BOOL, Active, VRDE_QI_ACTIVE);
4183IMPL_GETTER_SCALAR (LONG, Port, VRDE_QI_PORT, 0);
4184IMPL_GETTER_SCALAR (ULONG, NumberOfClients, VRDE_QI_NUMBER_OF_CLIENTS, 0);
4185IMPL_GETTER_SCALAR (LONG64, BeginTime, VRDE_QI_BEGIN_TIME, 0);
4186IMPL_GETTER_SCALAR (LONG64, EndTime, VRDE_QI_END_TIME, 0);
4187IMPL_GETTER_SCALAR (LONG64, BytesSent, VRDE_QI_BYTES_SENT, INT64_MAX);
4188IMPL_GETTER_SCALAR (LONG64, BytesSentTotal, VRDE_QI_BYTES_SENT_TOTAL, INT64_MAX);
4189IMPL_GETTER_SCALAR (LONG64, BytesReceived, VRDE_QI_BYTES_RECEIVED, INT64_MAX);
4190IMPL_GETTER_SCALAR (LONG64, BytesReceivedTotal, VRDE_QI_BYTES_RECEIVED_TOTAL, INT64_MAX);
4191IMPL_GETTER_UTF8STR(Utf8Str, User, VRDE_QI_USER);
4192IMPL_GETTER_UTF8STR(Utf8Str, Domain, VRDE_QI_DOMAIN);
4193IMPL_GETTER_UTF8STR(Utf8Str, ClientName, VRDE_QI_CLIENT_NAME);
4194IMPL_GETTER_UTF8STR(Utf8Str, ClientIP, VRDE_QI_CLIENT_IP);
4195IMPL_GETTER_SCALAR (ULONG, ClientVersion, VRDE_QI_CLIENT_VERSION, 0);
4196IMPL_GETTER_SCALAR (ULONG, EncryptionStyle, VRDE_QI_ENCRYPTION_STYLE, 0);
4197
4198#undef IMPL_GETTER_UTF8STR
4199#undef IMPL_GETTER_SCALAR
4200#undef IMPL_GETTER_BOOL
4201/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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