VirtualBox

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

Last change on this file since 62370 was 62370, checked in by vboxsync, 8 years ago

Main: a few fixes for -Wunused -Wconversion

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

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