VirtualBox

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

Last change on this file since 73003 was 73003, checked in by vboxsync, 6 years ago

Main: Use setErrorBoth when we've got a VBox status code handy. (The COM status codes aren't too specfic and this may help us decode error messages and provide an alternative to strstr for API clients. setErrorBoth isn't new, btw.)

  • 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 73003 2018-07-09 11:09:32Z vboxsync $ */
2/** @file
3 * VBox Console VRDP helper class.
4 */
5
6/*
7 * Copyright (C) 2006-2018 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_AUDIO_VRDE
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_AUDIO_VRDE
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_AUDIO_VRDE
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_AUDIO_VRDE
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_AUDIO_VRDE */
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 vrc = AuthLibLoad(&mAuthLibCtx, filename.c_str());
3204 if (RT_FAILURE(vrc))
3205 {
3206 mConsole->setErrorBoth(E_FAIL, vrc, mConsole->tr("Could not load the external authentication library '%s' (%Rrc)"),
3207 filename.c_str(), vrc);
3208 return AuthResultAccessDenied;
3209 }
3210 }
3211
3212 result = AuthLibAuthenticate(&mAuthLibCtx,
3213 uuid.raw(), guestJudgement,
3214 pszUser, pszPassword, pszDomain,
3215 u32ClientId);
3216#endif /* !VBOX_WITH_VRDEAUTH_IN_VBOXSVC */
3217
3218 switch (result)
3219 {
3220 case AuthResultAccessDenied:
3221 LogRel(("AUTH: external authentication module returned 'access denied'\n"));
3222 break;
3223 case AuthResultAccessGranted:
3224 LogRel(("AUTH: external authentication module returned 'access granted'\n"));
3225 break;
3226 case AuthResultDelegateToGuest:
3227 LogRel(("AUTH: external authentication module returned 'delegate request to guest'\n"));
3228 break;
3229 default:
3230 LogRel(("AUTH: external authentication module returned incorrect return code %d\n", result));
3231 result = AuthResultAccessDenied;
3232 }
3233
3234 LogFlowFunc(("result = %d\n", result));
3235
3236 return result;
3237}
3238
3239void ConsoleVRDPServer::AuthDisconnect(const Guid &uuid, uint32_t u32ClientId)
3240{
3241 LogFlow(("ConsoleVRDPServer::AuthDisconnect: uuid = %RTuuid, u32ClientId = %d\n",
3242 uuid.raw(), u32ClientId));
3243
3244#ifdef VBOX_WITH_VRDEAUTH_IN_VBOXSVC
3245 try
3246 {
3247 /* Init auth parameters. Order is important. */
3248 SafeArray<BSTR> authParams;
3249 Bstr("VRDEAUTHDISCONNECT").detachTo(authParams.appendedRaw());
3250 Bstr(uuid.toUtf16() ).detachTo(authParams.appendedRaw());
3251 BstrFmt("%u", u32ClientId).detachTo(authParams.appendedRaw());
3252
3253 Bstr authResult;
3254 HRESULT hr = mConsole->mControl->AuthenticateExternal(ComSafeArrayAsInParam(authParams),
3255 authResult.asOutParam());
3256 LogFlowFunc(("%Rhrc [%ls]\n", hr, authResult.raw())); NOREF(hr);
3257 }
3258 catch (std::bad_alloc)
3259 {
3260 }
3261#else
3262 AuthLibDisconnect(&mAuthLibCtx, uuid.raw(), u32ClientId);
3263#endif /* !VBOX_WITH_VRDEAUTH_IN_VBOXSVC */
3264}
3265
3266int ConsoleVRDPServer::lockConsoleVRDPServer(void)
3267{
3268 int rc = RTCritSectEnter(&mCritSect);
3269 AssertRC(rc);
3270 return rc;
3271}
3272
3273void ConsoleVRDPServer::unlockConsoleVRDPServer(void)
3274{
3275 RTCritSectLeave(&mCritSect);
3276}
3277
3278DECLCALLBACK(int) ConsoleVRDPServer::ClipboardCallback(void *pvCallback,
3279 uint32_t u32ClientId,
3280 uint32_t u32Function,
3281 uint32_t u32Format,
3282 const void *pvData,
3283 uint32_t cbData)
3284{
3285 LogFlowFunc(("pvCallback = %p, u32ClientId = %d, u32Function = %d, u32Format = 0x%08X, pvData = %p, cbData = %d\n",
3286 pvCallback, u32ClientId, u32Function, u32Format, pvData, cbData));
3287
3288 int rc = VINF_SUCCESS;
3289
3290 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvCallback);
3291
3292 NOREF(u32ClientId);
3293
3294 switch (u32Function)
3295 {
3296 case VRDE_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE:
3297 {
3298 if (pServer->mpfnClipboardCallback)
3299 {
3300 pServer->mpfnClipboardCallback(VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE,
3301 u32Format,
3302 (void *)pvData,
3303 cbData);
3304 }
3305 } break;
3306
3307 case VRDE_CLIPBOARD_FUNCTION_DATA_READ:
3308 {
3309 if (pServer->mpfnClipboardCallback)
3310 {
3311 pServer->mpfnClipboardCallback(VBOX_CLIPBOARD_EXT_FN_DATA_READ,
3312 u32Format,
3313 (void *)pvData,
3314 cbData);
3315 }
3316 } break;
3317
3318 default:
3319 rc = VERR_NOT_SUPPORTED;
3320 }
3321
3322 return rc;
3323}
3324
3325DECLCALLBACK(int) ConsoleVRDPServer::ClipboardServiceExtension(void *pvExtension,
3326 uint32_t u32Function,
3327 void *pvParms,
3328 uint32_t cbParms)
3329{
3330 RT_NOREF(cbParms);
3331 LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
3332 pvExtension, u32Function, pvParms, cbParms));
3333
3334 int rc = VINF_SUCCESS;
3335
3336 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvExtension);
3337
3338 VBOXCLIPBOARDEXTPARMS *pParms = (VBOXCLIPBOARDEXTPARMS *)pvParms;
3339
3340 switch (u32Function)
3341 {
3342 case VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK:
3343 {
3344 pServer->mpfnClipboardCallback = pParms->u.pfnCallback;
3345 } break;
3346
3347 case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
3348 {
3349 /* The guest announces clipboard formats. This must be delivered to all clients. */
3350 if (mpEntryPoints && pServer->mhServer)
3351 {
3352 mpEntryPoints->VRDEClipboard(pServer->mhServer,
3353 VRDE_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE,
3354 pParms->u32Format,
3355 NULL,
3356 0,
3357 NULL);
3358 }
3359 } break;
3360
3361 case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
3362 {
3363 /* The clipboard service expects that the pvData buffer will be filled
3364 * with clipboard data. The server returns the data from the client that
3365 * announced the requested format most recently.
3366 */
3367 if (mpEntryPoints && pServer->mhServer)
3368 {
3369 mpEntryPoints->VRDEClipboard(pServer->mhServer,
3370 VRDE_CLIPBOARD_FUNCTION_DATA_READ,
3371 pParms->u32Format,
3372 pParms->u.pvData,
3373 pParms->cbData,
3374 &pParms->cbData);
3375 }
3376 } break;
3377
3378 case VBOX_CLIPBOARD_EXT_FN_DATA_WRITE:
3379 {
3380 if (mpEntryPoints && pServer->mhServer)
3381 {
3382 mpEntryPoints->VRDEClipboard(pServer->mhServer,
3383 VRDE_CLIPBOARD_FUNCTION_DATA_WRITE,
3384 pParms->u32Format,
3385 pParms->u.pvData,
3386 pParms->cbData,
3387 NULL);
3388 }
3389 } break;
3390
3391 default:
3392 rc = VERR_NOT_SUPPORTED;
3393 }
3394
3395 return rc;
3396}
3397
3398void ConsoleVRDPServer::ClipboardCreate(uint32_t u32ClientId)
3399{
3400 RT_NOREF(u32ClientId);
3401 int rc = lockConsoleVRDPServer();
3402
3403 if (RT_SUCCESS(rc))
3404 {
3405 if (mcClipboardRefs == 0)
3406 {
3407 rc = HGCMHostRegisterServiceExtension(&mhClipboard, "VBoxSharedClipboard", ClipboardServiceExtension, this);
3408
3409 if (RT_SUCCESS(rc))
3410 {
3411 mcClipboardRefs++;
3412 }
3413 }
3414
3415 unlockConsoleVRDPServer();
3416 }
3417}
3418
3419void ConsoleVRDPServer::ClipboardDelete(uint32_t u32ClientId)
3420{
3421 RT_NOREF(u32ClientId);
3422 int rc = lockConsoleVRDPServer();
3423
3424 if (RT_SUCCESS(rc))
3425 {
3426 mcClipboardRefs--;
3427
3428 if (mcClipboardRefs == 0)
3429 {
3430 HGCMHostUnregisterServiceExtension(mhClipboard);
3431 }
3432
3433 unlockConsoleVRDPServer();
3434 }
3435}
3436
3437/* That is called on INPUT thread of the VRDP server.
3438 * The ConsoleVRDPServer keeps a list of created backend instances.
3439 */
3440void ConsoleVRDPServer::USBBackendCreate(uint32_t u32ClientId, void **ppvIntercept)
3441{
3442#ifdef VBOX_WITH_USB
3443 LogFlow(("ConsoleVRDPServer::USBBackendCreate: u32ClientId = %d\n", u32ClientId));
3444
3445 /* Create a new instance of the USB backend for the new client. */
3446 RemoteUSBBackend *pRemoteUSBBackend = new RemoteUSBBackend(mConsole, this, u32ClientId);
3447
3448 if (pRemoteUSBBackend)
3449 {
3450 pRemoteUSBBackend->AddRef(); /* 'Release' called in USBBackendDelete. */
3451
3452 /* Append the new instance in the list. */
3453 int rc = lockConsoleVRDPServer();
3454
3455 if (RT_SUCCESS(rc))
3456 {
3457 pRemoteUSBBackend->pNext = mUSBBackends.pHead;
3458 if (mUSBBackends.pHead)
3459 {
3460 mUSBBackends.pHead->pPrev = pRemoteUSBBackend;
3461 }
3462 else
3463 {
3464 mUSBBackends.pTail = pRemoteUSBBackend;
3465 }
3466
3467 mUSBBackends.pHead = pRemoteUSBBackend;
3468
3469 unlockConsoleVRDPServer();
3470
3471 if (ppvIntercept)
3472 {
3473 *ppvIntercept = pRemoteUSBBackend;
3474 }
3475 }
3476
3477 if (RT_FAILURE(rc))
3478 {
3479 pRemoteUSBBackend->Release();
3480 }
3481 }
3482#endif /* VBOX_WITH_USB */
3483}
3484
3485void ConsoleVRDPServer::USBBackendDelete(uint32_t u32ClientId)
3486{
3487#ifdef VBOX_WITH_USB
3488 LogFlow(("ConsoleVRDPServer::USBBackendDelete: u32ClientId = %d\n", u32ClientId));
3489
3490 RemoteUSBBackend *pRemoteUSBBackend = NULL;
3491
3492 /* Find the instance. */
3493 int rc = lockConsoleVRDPServer();
3494
3495 if (RT_SUCCESS(rc))
3496 {
3497 pRemoteUSBBackend = usbBackendFind(u32ClientId);
3498
3499 if (pRemoteUSBBackend)
3500 {
3501 /* Notify that it will be deleted. */
3502 pRemoteUSBBackend->NotifyDelete();
3503 }
3504
3505 unlockConsoleVRDPServer();
3506 }
3507
3508 if (pRemoteUSBBackend)
3509 {
3510 /* Here the instance has been excluded from the list and can be dereferenced. */
3511 pRemoteUSBBackend->Release();
3512 }
3513#endif
3514}
3515
3516void *ConsoleVRDPServer::USBBackendRequestPointer(uint32_t u32ClientId, const Guid *pGuid)
3517{
3518#ifdef VBOX_WITH_USB
3519 RemoteUSBBackend *pRemoteUSBBackend = NULL;
3520
3521 /* Find the instance. */
3522 int rc = lockConsoleVRDPServer();
3523
3524 if (RT_SUCCESS(rc))
3525 {
3526 pRemoteUSBBackend = usbBackendFind(u32ClientId);
3527
3528 if (pRemoteUSBBackend)
3529 {
3530 /* Inform the backend instance that it is referenced by the Guid. */
3531 bool fAdded = pRemoteUSBBackend->addUUID(pGuid);
3532
3533 if (fAdded)
3534 {
3535 /* Reference the instance because its pointer is being taken. */
3536 pRemoteUSBBackend->AddRef(); /* 'Release' is called in USBBackendReleasePointer. */
3537 }
3538 else
3539 {
3540 pRemoteUSBBackend = NULL;
3541 }
3542 }
3543
3544 unlockConsoleVRDPServer();
3545 }
3546
3547 if (pRemoteUSBBackend)
3548 {
3549 return pRemoteUSBBackend->GetBackendCallbackPointer();
3550 }
3551
3552#endif
3553 return NULL;
3554}
3555
3556void ConsoleVRDPServer::USBBackendReleasePointer(const Guid *pGuid)
3557{
3558#ifdef VBOX_WITH_USB
3559 RemoteUSBBackend *pRemoteUSBBackend = NULL;
3560
3561 /* Find the instance. */
3562 int rc = lockConsoleVRDPServer();
3563
3564 if (RT_SUCCESS(rc))
3565 {
3566 pRemoteUSBBackend = usbBackendFindByUUID(pGuid);
3567
3568 if (pRemoteUSBBackend)
3569 {
3570 pRemoteUSBBackend->removeUUID(pGuid);
3571 }
3572
3573 unlockConsoleVRDPServer();
3574
3575 if (pRemoteUSBBackend)
3576 {
3577 pRemoteUSBBackend->Release();
3578 }
3579 }
3580#endif
3581}
3582
3583RemoteUSBBackend *ConsoleVRDPServer::usbBackendGetNext(RemoteUSBBackend *pRemoteUSBBackend)
3584{
3585 LogFlow(("ConsoleVRDPServer::usbBackendGetNext: pBackend = %p\n", pRemoteUSBBackend));
3586
3587 RemoteUSBBackend *pNextRemoteUSBBackend = NULL;
3588#ifdef VBOX_WITH_USB
3589
3590 int rc = lockConsoleVRDPServer();
3591
3592 if (RT_SUCCESS(rc))
3593 {
3594 if (pRemoteUSBBackend == NULL)
3595 {
3596 /* The first backend in the list is requested. */
3597 pNextRemoteUSBBackend = mUSBBackends.pHead;
3598 }
3599 else
3600 {
3601 /* Get pointer to the next backend. */
3602 pNextRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
3603 }
3604
3605 if (pNextRemoteUSBBackend)
3606 {
3607 pNextRemoteUSBBackend->AddRef();
3608 }
3609
3610 unlockConsoleVRDPServer();
3611
3612 if (pRemoteUSBBackend)
3613 {
3614 pRemoteUSBBackend->Release();
3615 }
3616 }
3617#endif
3618
3619 return pNextRemoteUSBBackend;
3620}
3621
3622#ifdef VBOX_WITH_USB
3623/* Internal method. Called under the ConsoleVRDPServerLock. */
3624RemoteUSBBackend *ConsoleVRDPServer::usbBackendFind(uint32_t u32ClientId)
3625{
3626 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
3627
3628 while (pRemoteUSBBackend)
3629 {
3630 if (pRemoteUSBBackend->ClientId() == u32ClientId)
3631 {
3632 break;
3633 }
3634
3635 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
3636 }
3637
3638 return pRemoteUSBBackend;
3639}
3640
3641/* Internal method. Called under the ConsoleVRDPServerLock. */
3642RemoteUSBBackend *ConsoleVRDPServer::usbBackendFindByUUID(const Guid *pGuid)
3643{
3644 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
3645
3646 while (pRemoteUSBBackend)
3647 {
3648 if (pRemoteUSBBackend->findUUID(pGuid))
3649 {
3650 break;
3651 }
3652
3653 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
3654 }
3655
3656 return pRemoteUSBBackend;
3657}
3658#endif
3659
3660/* Internal method. Called by the backend destructor. */
3661void ConsoleVRDPServer::usbBackendRemoveFromList(RemoteUSBBackend *pRemoteUSBBackend)
3662{
3663#ifdef VBOX_WITH_USB
3664 int rc = lockConsoleVRDPServer();
3665 AssertRC(rc);
3666
3667 /* Exclude the found instance from the list. */
3668 if (pRemoteUSBBackend->pNext)
3669 {
3670 pRemoteUSBBackend->pNext->pPrev = pRemoteUSBBackend->pPrev;
3671 }
3672 else
3673 {
3674 mUSBBackends.pTail = (RemoteUSBBackend *)pRemoteUSBBackend->pPrev;
3675 }
3676
3677 if (pRemoteUSBBackend->pPrev)
3678 {
3679 pRemoteUSBBackend->pPrev->pNext = pRemoteUSBBackend->pNext;
3680 }
3681 else
3682 {
3683 mUSBBackends.pHead = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
3684 }
3685
3686 pRemoteUSBBackend->pNext = pRemoteUSBBackend->pPrev = NULL;
3687
3688 unlockConsoleVRDPServer();
3689#endif
3690}
3691
3692
3693void ConsoleVRDPServer::SendUpdate(unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate) const
3694{
3695 if (mpEntryPoints && mhServer)
3696 {
3697 mpEntryPoints->VRDEUpdate(mhServer, uScreenId, pvUpdate, cbUpdate);
3698 }
3699}
3700
3701void ConsoleVRDPServer::SendResize(void)
3702{
3703 if (mpEntryPoints && mhServer)
3704 {
3705 ++mcInResize;
3706 mpEntryPoints->VRDEResize(mhServer);
3707 --mcInResize;
3708 }
3709}
3710
3711void ConsoleVRDPServer::SendUpdateBitmap(unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h) const
3712{
3713 VRDEORDERHDR update;
3714 update.x = (uint16_t)x;
3715 update.y = (uint16_t)y;
3716 update.w = (uint16_t)w;
3717 update.h = (uint16_t)h;
3718 if (mpEntryPoints && mhServer)
3719 {
3720 mpEntryPoints->VRDEUpdate(mhServer, uScreenId, &update, sizeof(update));
3721 }
3722}
3723
3724void ConsoleVRDPServer::SendAudioSamples(void *pvSamples, uint32_t cSamples, VRDEAUDIOFORMAT format) const
3725{
3726 if (mpEntryPoints && mhServer)
3727 {
3728 mpEntryPoints->VRDEAudioSamples(mhServer, pvSamples, cSamples, format);
3729 }
3730}
3731
3732void ConsoleVRDPServer::SendAudioVolume(uint16_t left, uint16_t right) const
3733{
3734 if (mpEntryPoints && mhServer)
3735 {
3736 mpEntryPoints->VRDEAudioVolume(mhServer, left, right);
3737 }
3738}
3739
3740void ConsoleVRDPServer::SendUSBRequest(uint32_t u32ClientId, void *pvParms, uint32_t cbParms) const
3741{
3742 if (mpEntryPoints && mhServer)
3743 {
3744 mpEntryPoints->VRDEUSBRequest(mhServer, u32ClientId, pvParms, cbParms);
3745 }
3746}
3747
3748int ConsoleVRDPServer::SendAudioInputBegin(void **ppvUserCtx,
3749 void *pvContext,
3750 uint32_t cSamples,
3751 uint32_t iSampleHz,
3752 uint32_t cChannels,
3753 uint32_t cBits)
3754{
3755 if ( mhServer
3756 && mpEntryPoints && mpEntryPoints->VRDEAudioInOpen)
3757 {
3758 uint32_t u32ClientId = ASMAtomicReadU32(&mu32AudioInputClientId);
3759 if (u32ClientId != 0) /* 0 would mean broadcast to all clients. */
3760 {
3761 VRDEAUDIOFORMAT audioFormat = VRDE_AUDIO_FMT_MAKE(iSampleHz, cChannels, cBits, 0);
3762 mpEntryPoints->VRDEAudioInOpen(mhServer,
3763 pvContext,
3764 u32ClientId,
3765 audioFormat,
3766 cSamples);
3767 if (ppvUserCtx)
3768 *ppvUserCtx = NULL; /* This is the ConsoleVRDPServer context.
3769 * Currently not used because only one client is allowed to
3770 * do audio input and the client ID is saved by the ConsoleVRDPServer.
3771 */
3772 return VINF_SUCCESS;
3773 }
3774 }
3775
3776 /*
3777 * Not supported or no client connected.
3778 */
3779 return VERR_NOT_SUPPORTED;
3780}
3781
3782void ConsoleVRDPServer::SendAudioInputEnd(void *pvUserCtx)
3783{
3784 RT_NOREF(pvUserCtx);
3785 if (mpEntryPoints && mhServer && mpEntryPoints->VRDEAudioInClose)
3786 {
3787 uint32_t u32ClientId = ASMAtomicReadU32(&mu32AudioInputClientId);
3788 if (u32ClientId != 0) /* 0 would mean broadcast to all clients. */
3789 {
3790 mpEntryPoints->VRDEAudioInClose(mhServer, u32ClientId);
3791 }
3792 }
3793}
3794
3795void ConsoleVRDPServer::QueryInfo(uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const
3796{
3797 if (index == VRDE_QI_PORT)
3798 {
3799 uint32_t cbOut = sizeof(int32_t);
3800
3801 if (cbBuffer >= cbOut)
3802 {
3803 *pcbOut = cbOut;
3804 *(int32_t *)pvBuffer = (int32_t)mVRDPBindPort;
3805 }
3806 }
3807 else if (mpEntryPoints && mhServer)
3808 {
3809 mpEntryPoints->VRDEQueryInfo(mhServer, index, pvBuffer, cbBuffer, pcbOut);
3810 }
3811}
3812
3813/* static */ int ConsoleVRDPServer::loadVRDPLibrary(const char *pszLibraryName)
3814{
3815 int rc = VINF_SUCCESS;
3816
3817 if (mVRDPLibrary == NIL_RTLDRMOD)
3818 {
3819 RTERRINFOSTATIC ErrInfo;
3820 RTErrInfoInitStatic(&ErrInfo);
3821
3822 if (RTPathHavePath(pszLibraryName))
3823 rc = SUPR3HardenedLdrLoadPlugIn(pszLibraryName, &mVRDPLibrary, &ErrInfo.Core);
3824 else
3825 rc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &mVRDPLibrary, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
3826 if (RT_SUCCESS(rc))
3827 {
3828 struct SymbolEntry
3829 {
3830 const char *name;
3831 void **ppfn;
3832 };
3833
3834 #define DEFSYMENTRY(a) { #a, (void**)&mpfn##a }
3835
3836 static const struct SymbolEntry s_aSymbols[] =
3837 {
3838 DEFSYMENTRY(VRDECreateServer)
3839 };
3840
3841 #undef DEFSYMENTRY
3842
3843 for (unsigned i = 0; i < RT_ELEMENTS(s_aSymbols); i++)
3844 {
3845 rc = RTLdrGetSymbol(mVRDPLibrary, s_aSymbols[i].name, s_aSymbols[i].ppfn);
3846
3847 if (RT_FAILURE(rc))
3848 {
3849 LogRel(("VRDE: Error resolving symbol '%s', rc %Rrc.\n", s_aSymbols[i].name, rc));
3850 break;
3851 }
3852 }
3853 }
3854 else
3855 {
3856 if (RTErrInfoIsSet(&ErrInfo.Core))
3857 LogRel(("VRDE: Error loading the library '%s': %s (%Rrc)\n", pszLibraryName, ErrInfo.Core.pszMsg, rc));
3858 else
3859 LogRel(("VRDE: Error loading the library '%s' rc = %Rrc.\n", pszLibraryName, rc));
3860
3861 mVRDPLibrary = NIL_RTLDRMOD;
3862 }
3863 }
3864
3865 if (RT_FAILURE(rc))
3866 {
3867 if (mVRDPLibrary != NIL_RTLDRMOD)
3868 {
3869 RTLdrClose(mVRDPLibrary);
3870 mVRDPLibrary = NIL_RTLDRMOD;
3871 }
3872 }
3873
3874 return rc;
3875}
3876
3877/*
3878 * IVRDEServerInfo implementation.
3879 */
3880// constructor / destructor
3881/////////////////////////////////////////////////////////////////////////////
3882
3883VRDEServerInfo::VRDEServerInfo()
3884 : mParent(NULL)
3885{
3886}
3887
3888VRDEServerInfo::~VRDEServerInfo()
3889{
3890}
3891
3892
3893HRESULT VRDEServerInfo::FinalConstruct()
3894{
3895 return BaseFinalConstruct();
3896}
3897
3898void VRDEServerInfo::FinalRelease()
3899{
3900 uninit();
3901 BaseFinalRelease();
3902}
3903
3904// public methods only for internal purposes
3905/////////////////////////////////////////////////////////////////////////////
3906
3907/**
3908 * Initializes the guest object.
3909 */
3910HRESULT VRDEServerInfo::init(Console *aParent)
3911{
3912 LogFlowThisFunc(("aParent=%p\n", aParent));
3913
3914 ComAssertRet(aParent, E_INVALIDARG);
3915
3916 /* Enclose the state transition NotReady->InInit->Ready */
3917 AutoInitSpan autoInitSpan(this);
3918 AssertReturn(autoInitSpan.isOk(), E_FAIL);
3919
3920 unconst(mParent) = aParent;
3921
3922 /* Confirm a successful initialization */
3923 autoInitSpan.setSucceeded();
3924
3925 return S_OK;
3926}
3927
3928/**
3929 * Uninitializes the instance and sets the ready flag to FALSE.
3930 * Called either from FinalRelease() or by the parent when it gets destroyed.
3931 */
3932void VRDEServerInfo::uninit()
3933{
3934 LogFlowThisFunc(("\n"));
3935
3936 /* Enclose the state transition Ready->InUninit->NotReady */
3937 AutoUninitSpan autoUninitSpan(this);
3938 if (autoUninitSpan.uninitDone())
3939 return;
3940
3941 unconst(mParent) = NULL;
3942}
3943
3944// IVRDEServerInfo properties
3945/////////////////////////////////////////////////////////////////////////////
3946
3947#define IMPL_GETTER_BOOL(_aType, _aName, _aIndex) \
3948 HRESULT VRDEServerInfo::get##_aName(_aType *a##_aName) \
3949 { \
3950 /** @todo Not sure if a AutoReadLock would be sufficient. */ \
3951 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
3952 \
3953 uint32_t value; \
3954 uint32_t cbOut = 0; \
3955 \
3956 mParent->i_consoleVRDPServer()->QueryInfo \
3957 (_aIndex, &value, sizeof(value), &cbOut); \
3958 \
3959 *a##_aName = cbOut? !!value: FALSE; \
3960 \
3961 return S_OK; \
3962 } \
3963 extern void IMPL_GETTER_BOOL_DUMMY(void)
3964
3965#define IMPL_GETTER_SCALAR(_aType, _aName, _aIndex, _aValueMask) \
3966 HRESULT VRDEServerInfo::get##_aName(_aType *a##_aName) \
3967 { \
3968 /** @todo Not sure if a AutoReadLock would be sufficient. */ \
3969 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
3970 \
3971 _aType value; \
3972 uint32_t cbOut = 0; \
3973 \
3974 mParent->i_consoleVRDPServer()->QueryInfo \
3975 (_aIndex, &value, sizeof(value), &cbOut); \
3976 \
3977 if (_aValueMask) value &= (_aValueMask); \
3978 *a##_aName = cbOut? value: 0; \
3979 \
3980 return S_OK; \
3981 } \
3982 extern void IMPL_GETTER_SCALAR_DUMMY(void)
3983
3984#define IMPL_GETTER_UTF8STR(_aType, _aName, _aIndex) \
3985 HRESULT VRDEServerInfo::get##_aName(_aType &a##_aName) \
3986 { \
3987 /** @todo Not sure if a AutoReadLock would be sufficient. */ \
3988 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
3989 \
3990 uint32_t cbOut = 0; \
3991 \
3992 mParent->i_consoleVRDPServer()->QueryInfo \
3993 (_aIndex, NULL, 0, &cbOut); \
3994 \
3995 if (cbOut == 0) \
3996 { \
3997 a##_aName = Utf8Str::Empty; \
3998 return S_OK; \
3999 } \
4000 \
4001 char *pchBuffer = (char *)RTMemTmpAlloc(cbOut); \
4002 \
4003 if (!pchBuffer) \
4004 { \
4005 Log(("VRDEServerInfo::" \
4006 #_aName \
4007 ": Failed to allocate memory %d bytes\n", cbOut)); \
4008 return E_OUTOFMEMORY; \
4009 } \
4010 \
4011 mParent->i_consoleVRDPServer()->QueryInfo \
4012 (_aIndex, pchBuffer, cbOut, &cbOut); \
4013 \
4014 a##_aName = pchBuffer; \
4015 \
4016 RTMemTmpFree(pchBuffer); \
4017 \
4018 return S_OK; \
4019 } \
4020 extern void IMPL_GETTER_BSTR_DUMMY(void)
4021
4022IMPL_GETTER_BOOL (BOOL, Active, VRDE_QI_ACTIVE);
4023IMPL_GETTER_SCALAR (LONG, Port, VRDE_QI_PORT, 0);
4024IMPL_GETTER_SCALAR (ULONG, NumberOfClients, VRDE_QI_NUMBER_OF_CLIENTS, 0);
4025IMPL_GETTER_SCALAR (LONG64, BeginTime, VRDE_QI_BEGIN_TIME, 0);
4026IMPL_GETTER_SCALAR (LONG64, EndTime, VRDE_QI_END_TIME, 0);
4027IMPL_GETTER_SCALAR (LONG64, BytesSent, VRDE_QI_BYTES_SENT, INT64_MAX);
4028IMPL_GETTER_SCALAR (LONG64, BytesSentTotal, VRDE_QI_BYTES_SENT_TOTAL, INT64_MAX);
4029IMPL_GETTER_SCALAR (LONG64, BytesReceived, VRDE_QI_BYTES_RECEIVED, INT64_MAX);
4030IMPL_GETTER_SCALAR (LONG64, BytesReceivedTotal, VRDE_QI_BYTES_RECEIVED_TOTAL, INT64_MAX);
4031IMPL_GETTER_UTF8STR(Utf8Str, User, VRDE_QI_USER);
4032IMPL_GETTER_UTF8STR(Utf8Str, Domain, VRDE_QI_DOMAIN);
4033IMPL_GETTER_UTF8STR(Utf8Str, ClientName, VRDE_QI_CLIENT_NAME);
4034IMPL_GETTER_UTF8STR(Utf8Str, ClientIP, VRDE_QI_CLIENT_IP);
4035IMPL_GETTER_SCALAR (ULONG, ClientVersion, VRDE_QI_CLIENT_VERSION, 0);
4036IMPL_GETTER_SCALAR (ULONG, EncryptionStyle, VRDE_QI_ENCRYPTION_STYLE, 0);
4037
4038#undef IMPL_GETTER_UTF8STR
4039#undef IMPL_GETTER_SCALAR
4040#undef IMPL_GETTER_BOOL
4041/* 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