VirtualBox

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

Last change on this file since 82502 was 82502, checked in by vboxsync, 4 years ago

Main/Console: Reverted VRDE clipboard breakage introduced in r131016 when using the HGCM extension feature for doing clipboard area coordination via VBoxSVC. Removed the SharedClipboardPrivate bits as they seem to have no real purpose. The clipboard area stuff will no longer get IVirtualBox/VBoxSVC, that has to be replumbed if deemed necessary (I don't think it is). bugref:9437

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

© 2023 Oracle
ContactPrivacy policyTerms of Use