VirtualBox

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

Last change on this file since 68798 was 67914, checked in by vboxsync, 7 years ago

src-client: Define LOG_GROUP according to interface or similar.

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