VirtualBox

source: vbox/trunk/src/VBox/Main/ConsoleVRDPServer.cpp@ 34079

Last change on this file since 34079 was 33963, checked in by vboxsync, 14 years ago

Main: moved listeners to location usable by fronends, rework

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 71.8 KB
Line 
1/* $Id: ConsoleVRDPServer.cpp 33963 2010-11-11 10:23:42Z vboxsync $ */
2/** @file
3 * VBox Console VRDP Helper class
4 */
5
6/*
7 * Copyright (C) 2006-2010 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
24#include "AutoCaller.h"
25#include "Logging.h"
26
27#include <iprt/asm.h>
28#include <iprt/ldr.h>
29#include <iprt/param.h>
30#include <iprt/path.h>
31#include <iprt/alloca.h>
32#include <iprt/cpp/utils.h>
33
34#include <VBox/err.h>
35#include <VBox/RemoteDesktop/VRDEOrders.h>
36#include <VBox/com/listeners.h>
37
38class VRDPConsoleListener
39{
40public:
41 VRDPConsoleListener(ConsoleVRDPServer *server)
42 : m_server(server)
43 {
44 }
45
46 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent * aEvent)
47 {
48 switch (aType)
49 {
50 case VBoxEventType_OnMousePointerShapeChanged:
51 {
52 ComPtr<IMousePointerShapeChangedEvent> mpscev = aEvent;
53 Assert(mpscev);
54 BOOL visible, alpha;
55 ULONG xHot, yHot, width, height;
56 com::SafeArray <BYTE> shape;
57
58 mpscev->COMGETTER(Visible)(&visible);
59 mpscev->COMGETTER(Alpha)(&alpha);
60 mpscev->COMGETTER(Xhot)(&xHot);
61 mpscev->COMGETTER(Yhot)(&yHot);
62 mpscev->COMGETTER(Width)(&width);
63 mpscev->COMGETTER(Height)(&height);
64 mpscev->COMGETTER(Shape)(ComSafeArrayAsOutParam(shape));
65
66 OnMousePointerShapeChange(visible, alpha, xHot, yHot, width, height, ComSafeArrayAsInParam(shape));
67 break;
68 }
69 case VBoxEventType_OnMouseCapabilityChanged:
70 {
71 ComPtr<IMouseCapabilityChangedEvent> mccev = aEvent;
72 Assert(mccev);
73 if (m_server)
74 {
75 BOOL fAbsoluteMouse;
76 mccev->COMGETTER(SupportsAbsolute)(&fAbsoluteMouse);
77 m_server->NotifyAbsoluteMouse(!!fAbsoluteMouse);
78 }
79 break;
80 }
81 case VBoxEventType_OnKeyboardLedsChanged:
82 {
83 ComPtr<IKeyboardLedsChangedEvent> klcev = aEvent;
84 Assert(klcev);
85
86 if (m_server)
87 {
88 BOOL fNumLock, fCapsLock, fScrollLock;
89 klcev->COMGETTER(NumLock)(&fNumLock);
90 klcev->COMGETTER(CapsLock)(&fCapsLock);
91 klcev->COMGETTER(ScrollLock)(&fScrollLock);
92 m_server->NotifyKeyboardLedsChange(fNumLock, fCapsLock, fScrollLock);
93 }
94 break;
95 }
96
97 default:
98 AssertFailed();
99 }
100
101 return S_OK;
102 }
103
104private:
105 STDMETHOD(OnMousePointerShapeChange)(BOOL visible, BOOL alpha, ULONG xHot, ULONG yHot,
106 ULONG width, ULONG height, ComSafeArrayIn(BYTE,shape));
107 ConsoleVRDPServer *m_server;
108};
109
110typedef ListenerImpl<VRDPConsoleListener, ConsoleVRDPServer*> VRDPConsoleListenerImpl;
111
112VBOX_LISTENER_DECLARE(VRDPConsoleListenerImpl)
113
114#ifdef DEBUG_sunlover
115#define LOGDUMPPTR Log
116void dumpPointer(const uint8_t *pu8Shape, uint32_t width, uint32_t height, bool fXorMaskRGB32)
117{
118 unsigned i;
119
120 const uint8_t *pu8And = pu8Shape;
121
122 for (i = 0; i < height; i++)
123 {
124 unsigned j;
125 LOGDUMPPTR(("%p: ", pu8And));
126 for (j = 0; j < (width + 7) / 8; j++)
127 {
128 unsigned k;
129 for (k = 0; k < 8; k++)
130 {
131 LOGDUMPPTR(("%d", ((*pu8And) & (1 << (7 - k)))? 1: 0));
132 }
133
134 pu8And++;
135 }
136 LOGDUMPPTR(("\n"));
137 }
138
139 if (fXorMaskRGB32)
140 {
141 uint32_t *pu32Xor = (uint32_t*)(pu8Shape + ((((width + 7) / 8) * height + 3) & ~3));
142
143 for (i = 0; i < height; i++)
144 {
145 unsigned j;
146 LOGDUMPPTR(("%p: ", pu32Xor));
147 for (j = 0; j < width; j++)
148 {
149 LOGDUMPPTR(("%08X", *pu32Xor++));
150 }
151 LOGDUMPPTR(("\n"));
152 }
153 }
154 else
155 {
156 /* RDP 24 bit RGB mask. */
157 uint8_t *pu8Xor = (uint8_t*)(pu8Shape + ((((width + 7) / 8) * height + 3) & ~3));
158 for (i = 0; i < height; i++)
159 {
160 unsigned j;
161 LOGDUMPPTR(("%p: ", pu8Xor));
162 for (j = 0; j < width; j++)
163 {
164 LOGDUMPPTR(("%02X%02X%02X", pu8Xor[2], pu8Xor[1], pu8Xor[0]));
165 pu8Xor += 3;
166 }
167 LOGDUMPPTR(("\n"));
168 }
169 }
170}
171#else
172#define dumpPointer(a, b, c, d) do {} while (0)
173#endif /* DEBUG_sunlover */
174
175static void findTopLeftBorder(const uint8_t *pu8AndMask, const uint8_t *pu8XorMask, uint32_t width, uint32_t height, uint32_t *pxSkip, uint32_t *pySkip)
176{
177 /*
178 * Find the top border of the AND mask. First assign to special value.
179 */
180 uint32_t ySkipAnd = ~0;
181
182 const uint8_t *pu8And = pu8AndMask;
183 const uint32_t cbAndRow = (width + 7) / 8;
184 const uint8_t maskLastByte = (uint8_t)( 0xFF << (cbAndRow * 8 - width) );
185
186 Assert(cbAndRow > 0);
187
188 unsigned y;
189 unsigned x;
190
191 for (y = 0; y < height && ySkipAnd == ~(uint32_t)0; y++, pu8And += cbAndRow)
192 {
193 /* For each complete byte in the row. */
194 for (x = 0; x < cbAndRow - 1; x++)
195 {
196 if (pu8And[x] != 0xFF)
197 {
198 ySkipAnd = y;
199 break;
200 }
201 }
202
203 if (ySkipAnd == ~(uint32_t)0)
204 {
205 /* Last byte. */
206 if ((pu8And[cbAndRow - 1] & maskLastByte) != maskLastByte)
207 {
208 ySkipAnd = y;
209 }
210 }
211 }
212
213 if (ySkipAnd == ~(uint32_t)0)
214 {
215 ySkipAnd = 0;
216 }
217
218 /*
219 * Find the left border of the AND mask.
220 */
221 uint32_t xSkipAnd = ~0;
222
223 /* For all bit columns. */
224 for (x = 0; x < width && xSkipAnd == ~(uint32_t)0; x++)
225 {
226 pu8And = pu8AndMask + x/8; /* Currently checking byte. */
227 uint8_t mask = 1 << (7 - x%8); /* Currently checking bit in the byte. */
228
229 for (y = ySkipAnd; y < height; y++, pu8And += cbAndRow)
230 {
231 if ((*pu8And & mask) == 0)
232 {
233 xSkipAnd = x;
234 break;
235 }
236 }
237 }
238
239 if (xSkipAnd == ~(uint32_t)0)
240 {
241 xSkipAnd = 0;
242 }
243
244 /*
245 * Find the XOR mask top border.
246 */
247 uint32_t ySkipXor = ~0;
248
249 uint32_t *pu32XorStart = (uint32_t *)pu8XorMask;
250
251 uint32_t *pu32Xor = pu32XorStart;
252
253 for (y = 0; y < height && ySkipXor == ~(uint32_t)0; y++, pu32Xor += width)
254 {
255 for (x = 0; x < width; x++)
256 {
257 if (pu32Xor[x] != 0)
258 {
259 ySkipXor = y;
260 break;
261 }
262 }
263 }
264
265 if (ySkipXor == ~(uint32_t)0)
266 {
267 ySkipXor = 0;
268 }
269
270 /*
271 * Find the left border of the XOR mask.
272 */
273 uint32_t xSkipXor = ~(uint32_t)0;
274
275 /* For all columns. */
276 for (x = 0; x < width && xSkipXor == ~(uint32_t)0; x++)
277 {
278 pu32Xor = pu32XorStart + x; /* Currently checking dword. */
279
280 for (y = ySkipXor; y < height; y++, pu32Xor += width)
281 {
282 if (*pu32Xor != 0)
283 {
284 xSkipXor = x;
285 break;
286 }
287 }
288 }
289
290 if (xSkipXor == ~(uint32_t)0)
291 {
292 xSkipXor = 0;
293 }
294
295 *pxSkip = RT_MIN(xSkipAnd, xSkipXor);
296 *pySkip = RT_MIN(ySkipAnd, ySkipXor);
297}
298
299/* Generate an AND mask for alpha pointers here, because
300 * guest driver does not do that correctly for Vista pointers.
301 * Similar fix, changing the alpha threshold, could be applied
302 * for the guest driver, but then additions reinstall would be
303 * necessary, which we try to avoid.
304 */
305static void mousePointerGenerateANDMask(uint8_t *pu8DstAndMask, int cbDstAndMask, const uint8_t *pu8SrcAlpha, int w, int h)
306{
307 memset(pu8DstAndMask, 0xFF, cbDstAndMask);
308
309 int y;
310 for (y = 0; y < h; y++)
311 {
312 uint8_t bitmask = 0x80;
313
314 int x;
315 for (x = 0; x < w; x++, bitmask >>= 1)
316 {
317 if (bitmask == 0)
318 {
319 bitmask = 0x80;
320 }
321
322 /* Whether alpha channel value is not transparent enough for the pixel to be seen. */
323 if (pu8SrcAlpha[x * 4 + 3] > 0x7f)
324 {
325 pu8DstAndMask[x / 8] &= ~bitmask;
326 }
327 }
328
329 /* Point to next source and dest scans. */
330 pu8SrcAlpha += w * 4;
331 pu8DstAndMask += (w + 7) / 8;
332 }
333}
334
335STDMETHODIMP VRDPConsoleListener::OnMousePointerShapeChange(BOOL visible,
336 BOOL alpha,
337 ULONG xHot,
338 ULONG yHot,
339 ULONG width,
340 ULONG height,
341 ComSafeArrayIn(BYTE,inShape))
342{
343 LogSunlover(("VRDPConsoleListener::OnMousePointerShapeChange: %d, %d, %lux%lu, @%lu,%lu\n", visible, alpha, width, height, xHot, yHot));
344
345 if (m_server)
346 {
347 com::SafeArray <BYTE> aShape(ComSafeArrayInArg(inShape));
348 if (aShape.size() == 0)
349 {
350 if (!visible)
351 {
352 m_server->MousePointerHide();
353 }
354 }
355 else if (width != 0 && height != 0)
356 {
357 /* Pointer consists of 1 bpp AND and 24 BPP XOR masks.
358 * 'shape' AND mask followed by XOR mask.
359 * XOR mask contains 32 bit (lsb)BGR0(msb) values.
360 *
361 * We convert this to RDP color format which consist of
362 * one bpp AND mask and 24 BPP (BGR) color XOR image.
363 *
364 * RDP clients expect 8 aligned width and height of
365 * pointer (preferably 32x32).
366 *
367 * They even contain bugs which do not appear for
368 * 32x32 pointers but would appear for a 41x32 one.
369 *
370 * So set pointer size to 32x32. This can be done safely
371 * because most pointers are 32x32.
372 */
373 uint8_t* shape = aShape.raw();
374
375 dumpPointer(shape, width, height, true);
376
377 int cbDstAndMask = (((width + 7) / 8) * height + 3) & ~3;
378
379 uint8_t *pu8AndMask = shape;
380 uint8_t *pu8XorMask = shape + cbDstAndMask;
381
382 if (alpha)
383 {
384 pu8AndMask = (uint8_t*)alloca(cbDstAndMask);
385
386 mousePointerGenerateANDMask(pu8AndMask, cbDstAndMask, pu8XorMask, width, height);
387 }
388
389 /* Windows guest alpha pointers are wider than 32 pixels.
390 * Try to find out the top-left border of the pointer and
391 * then copy only meaningful bits. All complete top rows
392 * and all complete left columns where (AND == 1 && XOR == 0)
393 * are skipped. Hot spot is adjusted.
394 */
395 uint32_t ySkip = 0; /* How many rows to skip at the top. */
396 uint32_t xSkip = 0; /* How many columns to skip at the left. */
397
398 findTopLeftBorder(pu8AndMask, pu8XorMask, width, height, &xSkip, &ySkip);
399
400 /* Must not skip the hot spot. */
401 xSkip = RT_MIN(xSkip, xHot);
402 ySkip = RT_MIN(ySkip, yHot);
403
404 /*
405 * Compute size and allocate memory for the pointer.
406 */
407 const uint32_t dstwidth = 32;
408 const uint32_t dstheight = 32;
409
410 VRDECOLORPOINTER *pointer = NULL;
411
412 uint32_t dstmaskwidth = (dstwidth + 7) / 8;
413
414 uint32_t rdpmaskwidth = dstmaskwidth;
415 uint32_t rdpmasklen = dstheight * rdpmaskwidth;
416
417 uint32_t rdpdatawidth = dstwidth * 3;
418 uint32_t rdpdatalen = dstheight * rdpdatawidth;
419
420 pointer = (VRDECOLORPOINTER *)RTMemTmpAlloc(sizeof(VRDECOLORPOINTER) + rdpmasklen + rdpdatalen);
421
422 if (pointer)
423 {
424 uint8_t *maskarray = (uint8_t*)pointer + sizeof(VRDECOLORPOINTER);
425 uint8_t *dataarray = maskarray + rdpmasklen;
426
427 memset(maskarray, 0xFF, rdpmasklen);
428 memset(dataarray, 0x00, rdpdatalen);
429
430 uint32_t srcmaskwidth = (width + 7) / 8;
431 uint32_t srcdatawidth = width * 4;
432
433 /* Copy AND mask. */
434 uint8_t *src = pu8AndMask + ySkip * srcmaskwidth;
435 uint8_t *dst = maskarray + (dstheight - 1) * rdpmaskwidth;
436
437 uint32_t minheight = RT_MIN(height - ySkip, dstheight);
438 uint32_t minwidth = RT_MIN(width - xSkip, dstwidth);
439
440 unsigned x, y;
441
442 for (y = 0; y < minheight; y++)
443 {
444 for (x = 0; x < minwidth; x++)
445 {
446 uint32_t byteIndex = (x + xSkip) / 8;
447 uint32_t bitIndex = (x + xSkip) % 8;
448
449 bool bit = (src[byteIndex] & (1 << (7 - bitIndex))) != 0;
450
451 if (!bit)
452 {
453 byteIndex = x / 8;
454 bitIndex = x % 8;
455
456 dst[byteIndex] &= ~(1 << (7 - bitIndex));
457 }
458 }
459
460 src += srcmaskwidth;
461 dst -= rdpmaskwidth;
462 }
463
464 /* Point src to XOR mask */
465 src = pu8XorMask + ySkip * srcdatawidth;
466 dst = dataarray + (dstheight - 1) * rdpdatawidth;
467
468 for (y = 0; y < minheight ; y++)
469 {
470 for (x = 0; x < minwidth; x++)
471 {
472 memcpy(dst + x * 3, &src[4 * (x + xSkip)], 3);
473 }
474
475 src += srcdatawidth;
476 dst -= rdpdatawidth;
477 }
478
479 pointer->u16HotX = (uint16_t)(xHot - xSkip);
480 pointer->u16HotY = (uint16_t)(yHot - ySkip);
481
482 pointer->u16Width = (uint16_t)dstwidth;
483 pointer->u16Height = (uint16_t)dstheight;
484
485 pointer->u16MaskLen = (uint16_t)rdpmasklen;
486 pointer->u16DataLen = (uint16_t)rdpdatalen;
487
488 dumpPointer((uint8_t*)pointer + sizeof(*pointer), dstwidth, dstheight, false);
489
490 m_server->MousePointerUpdate(pointer);
491
492 RTMemTmpFree(pointer);
493 }
494 }
495 }
496
497 return S_OK;
498}
499
500
501// ConsoleVRDPServer
502////////////////////////////////////////////////////////////////////////////////
503
504RTLDRMOD ConsoleVRDPServer::mVRDPLibrary;
505
506PFNVRDECREATESERVER ConsoleVRDPServer::mpfnVRDECreateServer = NULL;
507
508VRDEENTRYPOINTS_1 *ConsoleVRDPServer::mpEntryPoints = NULL;
509
510VRDECALLBACKS_1 ConsoleVRDPServer::mCallbacks =
511{
512 { VRDE_INTERFACE_VERSION_1, sizeof(VRDECALLBACKS_1) },
513 ConsoleVRDPServer::VRDPCallbackQueryProperty,
514 ConsoleVRDPServer::VRDPCallbackClientLogon,
515 ConsoleVRDPServer::VRDPCallbackClientConnect,
516 ConsoleVRDPServer::VRDPCallbackClientDisconnect,
517 ConsoleVRDPServer::VRDPCallbackIntercept,
518 ConsoleVRDPServer::VRDPCallbackUSB,
519 ConsoleVRDPServer::VRDPCallbackClipboard,
520 ConsoleVRDPServer::VRDPCallbackFramebufferQuery,
521 ConsoleVRDPServer::VRDPCallbackFramebufferLock,
522 ConsoleVRDPServer::VRDPCallbackFramebufferUnlock,
523 ConsoleVRDPServer::VRDPCallbackInput,
524 ConsoleVRDPServer::VRDPCallbackVideoModeHint
525};
526
527DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackQueryProperty(void *pvCallback, uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut)
528{
529 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
530
531 int rc = VERR_NOT_SUPPORTED;
532
533 switch (index)
534 {
535 case VRDE_QP_NETWORK_PORT:
536 {
537 /* This is obsolete, the VRDE server uses VRDE_QP_NETWORK_PORT_RANGE instead. */
538 ULONG port = 0;
539
540 if (cbBuffer >= sizeof(uint32_t))
541 {
542 *(uint32_t *)pvBuffer = (uint32_t)port;
543 rc = VINF_SUCCESS;
544 }
545 else
546 {
547 rc = VINF_BUFFER_OVERFLOW;
548 }
549
550 *pcbOut = sizeof(uint32_t);
551 } break;
552
553 case VRDE_QP_NETWORK_ADDRESS:
554 {
555 com::Bstr bstr;
556 server->mConsole->getVRDEServer()->GetVRDEProperty(Bstr("TCP/Address").raw(), bstr.asOutParam());
557
558 /* The server expects UTF8. */
559 com::Utf8Str address = bstr;
560
561 size_t cbAddress = address.length() + 1;
562
563 if (cbAddress >= 0x10000)
564 {
565 /* More than 64K seems to be an invalid address. */
566 rc = VERR_TOO_MUCH_DATA;
567 break;
568 }
569
570 if ((size_t)cbBuffer >= cbAddress)
571 {
572 memcpy(pvBuffer, address.c_str(), cbAddress);
573 rc = VINF_SUCCESS;
574 }
575 else
576 {
577 rc = VINF_BUFFER_OVERFLOW;
578 }
579
580 *pcbOut = (uint32_t)cbAddress;
581 } break;
582
583 case VRDE_QP_NUMBER_MONITORS:
584 {
585 ULONG cMonitors = 1;
586
587 server->mConsole->machine()->COMGETTER(MonitorCount)(&cMonitors);
588
589 if (cbBuffer >= sizeof(uint32_t))
590 {
591 *(uint32_t *)pvBuffer = (uint32_t)cMonitors;
592 rc = VINF_SUCCESS;
593 }
594 else
595 {
596 rc = VINF_BUFFER_OVERFLOW;
597 }
598
599 *pcbOut = sizeof(uint32_t);
600 } break;
601
602 case VRDE_QP_NETWORK_PORT_RANGE:
603 {
604 com::Bstr bstr;
605 HRESULT hrc = server->mConsole->getVRDEServer()->GetVRDEProperty(Bstr("TCP/Ports").raw(), bstr.asOutParam());
606
607 if (hrc != S_OK)
608 {
609 bstr = "";
610 }
611
612 if (bstr == "0")
613 {
614 bstr = "3389";
615 }
616
617 /* The server expects UTF8. */
618 com::Utf8Str portRange = bstr;
619
620 size_t cbPortRange = portRange.length() + 1;
621
622 if (cbPortRange >= 0x10000)
623 {
624 /* More than 64K seems to be an invalid port range string. */
625 rc = VERR_TOO_MUCH_DATA;
626 break;
627 }
628
629 if ((size_t)cbBuffer >= cbPortRange)
630 {
631 memcpy(pvBuffer, portRange.c_str(), cbPortRange);
632 rc = VINF_SUCCESS;
633 }
634 else
635 {
636 rc = VINF_BUFFER_OVERFLOW;
637 }
638
639 *pcbOut = (uint32_t)cbPortRange;
640 } break;
641
642#ifdef VBOX_WITH_VRDP_VIDEO_CHANNEL
643 case VRDE_QP_VIDEO_CHANNEL:
644 {
645 BOOL fVideoEnabled = FALSE;
646
647 server->mConsole->getVRDEServer()->COMGETTER(VideoChannel)(&fVideoEnabled);
648
649 if (cbBuffer >= sizeof(uint32_t))
650 {
651 *(uint32_t *)pvBuffer = (uint32_t)fVideoEnabled;
652 rc = VINF_SUCCESS;
653 }
654 else
655 {
656 rc = VINF_BUFFER_OVERFLOW;
657 }
658
659 *pcbOut = sizeof(uint32_t);
660 } break;
661
662 case VRDE_QP_VIDEO_CHANNEL_QUALITY:
663 {
664 ULONG ulQuality = 0;
665
666 server->mConsole->getVRDEServer()->COMGETTER(VideoChannelQuality)(&ulQuality);
667
668 if (cbBuffer >= sizeof(uint32_t))
669 {
670 *(uint32_t *)pvBuffer = (uint32_t)ulQuality;
671 rc = VINF_SUCCESS;
672 }
673 else
674 {
675 rc = VINF_BUFFER_OVERFLOW;
676 }
677
678 *pcbOut = sizeof(uint32_t);
679 } break;
680
681 case VRDE_QP_VIDEO_CHANNEL_SUNFLSH:
682 {
683 ULONG ulSunFlsh = 1;
684
685 com::Bstr bstr;
686 HRESULT hrc = server->mConsole->machine()->GetExtraData(Bstr("VRDP/SunFlsh").raw(),
687 bstr.asOutParam());
688 if (hrc == S_OK && !bstr.isEmpty())
689 {
690 com::Utf8Str sunFlsh = bstr;
691 if (!sunFlsh.isEmpty())
692 {
693 ulSunFlsh = sunFlsh.toUInt32();
694 }
695 }
696
697 if (cbBuffer >= sizeof(uint32_t))
698 {
699 *(uint32_t *)pvBuffer = (uint32_t)ulSunFlsh;
700 rc = VINF_SUCCESS;
701 }
702 else
703 {
704 rc = VINF_BUFFER_OVERFLOW;
705 }
706
707 *pcbOut = sizeof(uint32_t);
708 } break;
709#endif /* VBOX_WITH_VRDP_VIDEO_CHANNEL */
710
711 case VRDE_QP_FEATURE:
712 {
713 if (cbBuffer < sizeof(VRDEFEATURE))
714 {
715 rc = VERR_INVALID_PARAMETER;
716 break;
717 }
718
719 size_t cbInfo = cbBuffer - RT_OFFSETOF(VRDEFEATURE, achInfo);
720
721 VRDEFEATURE *pFeature = (VRDEFEATURE *)pvBuffer;
722
723 size_t cchInfo = 0;
724 rc = RTStrNLenEx(pFeature->achInfo, cbInfo, &cchInfo);
725
726 if (RT_FAILURE(rc))
727 {
728 rc = VERR_INVALID_PARAMETER;
729 break;
730 }
731
732 Log(("VRDE_QP_FEATURE [%s]\n", pFeature->achInfo));
733
734 com::Bstr bstrValue;
735
736 if ( RTStrICmp(pFeature->achInfo, "Client/DisableDisplay") == 0
737 || RTStrICmp(pFeature->achInfo, "Client/DisableInput") == 0
738 || RTStrICmp(pFeature->achInfo, "Client/DisableAudio") == 0
739 || RTStrICmp(pFeature->achInfo, "Client/DisableUSB") == 0
740 || RTStrICmp(pFeature->achInfo, "Client/DisableClipboard") == 0
741 )
742 {
743 /* @todo these features should be per client. */
744 NOREF(pFeature->u32ClientId);
745
746 /* These features are mapped to "VRDE/Feature/NAME" extra data. */
747 com::Utf8Str extraData("VRDE/Feature/");
748 extraData += pFeature->achInfo;
749
750 HRESULT hrc = server->mConsole->machine()->GetExtraData(com::Bstr(extraData).raw(),
751 bstrValue.asOutParam());
752 if (FAILED(hrc) || bstrValue.isEmpty())
753 {
754 /* Also try the old "VRDP/Feature/NAME" */
755 extraData = "VRDP/Feature/";
756 extraData += pFeature->achInfo;
757
758 hrc = server->mConsole->machine()->GetExtraData(com::Bstr(extraData).raw(),
759 bstrValue.asOutParam());
760 if (FAILED(hrc) || bstrValue.isEmpty())
761 {
762 rc = VERR_NOT_SUPPORTED;
763 }
764 }
765 }
766 else if (RTStrNCmp(pFeature->achInfo, "Property/", 9) == 0)
767 {
768 /* Generic properties. */
769 const char *pszPropertyName = &pFeature->achInfo[9];
770 HRESULT hrc = server->mConsole->getVRDEServer()->GetVRDEProperty(Bstr(pszPropertyName).raw(), bstrValue.asOutParam());
771 if (FAILED(hrc))
772 {
773 rc = VERR_NOT_SUPPORTED;
774 }
775 }
776 else
777 {
778 rc = VERR_NOT_SUPPORTED;
779 }
780
781 /* Copy the value string to the callers buffer. */
782 if (rc == VINF_SUCCESS)
783 {
784 com::Utf8Str value = bstrValue;
785
786 size_t cb = value.length() + 1;
787
788 if ((size_t)cbInfo >= cb)
789 {
790 memcpy(pFeature->achInfo, value.c_str(), cb);
791 }
792 else
793 {
794 rc = VINF_BUFFER_OVERFLOW;
795 }
796
797 *pcbOut = (uint32_t)cb;
798 }
799 } break;
800
801 case VRDE_SP_NETWORK_BIND_PORT:
802 {
803 if (cbBuffer != sizeof(uint32_t))
804 {
805 rc = VERR_INVALID_PARAMETER;
806 break;
807 }
808
809 ULONG port = *(uint32_t *)pvBuffer;
810
811 server->mVRDPBindPort = port;
812
813 rc = VINF_SUCCESS;
814
815 if (pcbOut)
816 {
817 *pcbOut = sizeof(uint32_t);
818 }
819
820 server->mConsole->onVRDEServerInfoChange();
821 } break;
822
823 default:
824 break;
825 }
826
827 return rc;
828}
829
830DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClientLogon(void *pvCallback, uint32_t u32ClientId, const char *pszUser, const char *pszPassword, const char *pszDomain)
831{
832 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
833
834 return server->mConsole->VRDPClientLogon(u32ClientId, pszUser, pszPassword, pszDomain);
835}
836
837DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientConnect(void *pvCallback, uint32_t u32ClientId)
838{
839 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
840
841 server->mConsole->VRDPClientConnect(u32ClientId);
842}
843
844DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientDisconnect(void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercepted)
845{
846 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
847
848 server->mConsole->VRDPClientDisconnect(u32ClientId, fu32Intercepted);
849}
850
851DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackIntercept(void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercept, void **ppvIntercept)
852{
853 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
854
855 LogFlowFunc(("%x\n", fu32Intercept));
856
857 int rc = VERR_NOT_SUPPORTED;
858
859 switch (fu32Intercept)
860 {
861 case VRDE_CLIENT_INTERCEPT_AUDIO:
862 {
863 server->mConsole->VRDPInterceptAudio(u32ClientId);
864 if (ppvIntercept)
865 {
866 *ppvIntercept = server;
867 }
868 rc = VINF_SUCCESS;
869 } break;
870
871 case VRDE_CLIENT_INTERCEPT_USB:
872 {
873 server->mConsole->VRDPInterceptUSB(u32ClientId, ppvIntercept);
874 rc = VINF_SUCCESS;
875 } break;
876
877 case VRDE_CLIENT_INTERCEPT_CLIPBOARD:
878 {
879 server->mConsole->VRDPInterceptClipboard(u32ClientId);
880 if (ppvIntercept)
881 {
882 *ppvIntercept = server;
883 }
884 rc = VINF_SUCCESS;
885 } break;
886
887 default:
888 break;
889 }
890
891 return rc;
892}
893
894DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackUSB(void *pvCallback, void *pvIntercept, uint32_t u32ClientId, uint8_t u8Code, const void *pvRet, uint32_t cbRet)
895{
896#ifdef VBOX_WITH_USB
897 return USBClientResponseCallback(pvIntercept, u32ClientId, u8Code, pvRet, cbRet);
898#else
899 return VERR_NOT_SUPPORTED;
900#endif
901}
902
903DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClipboard(void *pvCallback, void *pvIntercept, uint32_t u32ClientId, uint32_t u32Function, uint32_t u32Format, const void *pvData, uint32_t cbData)
904{
905 return ClipboardCallback(pvIntercept, u32ClientId, u32Function, u32Format, pvData, cbData);
906}
907
908DECLCALLBACK(bool) ConsoleVRDPServer::VRDPCallbackFramebufferQuery(void *pvCallback, unsigned uScreenId, VRDEFRAMEBUFFERINFO *pInfo)
909{
910 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
911
912 bool fAvailable = false;
913
914 IFramebuffer *pfb = NULL;
915 LONG xOrigin = 0;
916 LONG yOrigin = 0;
917
918 server->mConsole->getDisplay()->GetFramebuffer(uScreenId, &pfb, &xOrigin, &yOrigin);
919
920 if (pfb)
921 {
922 pfb->Lock ();
923
924 /* Query framebuffer parameters. */
925 ULONG lineSize = 0;
926 pfb->COMGETTER(BytesPerLine)(&lineSize);
927
928 ULONG bitsPerPixel = 0;
929 pfb->COMGETTER(BitsPerPixel)(&bitsPerPixel);
930
931 BYTE *address = NULL;
932 pfb->COMGETTER(Address)(&address);
933
934 ULONG height = 0;
935 pfb->COMGETTER(Height)(&height);
936
937 ULONG width = 0;
938 pfb->COMGETTER(Width)(&width);
939
940 /* Now fill the information as requested by the caller. */
941 pInfo->pu8Bits = address;
942 pInfo->xOrigin = xOrigin;
943 pInfo->yOrigin = yOrigin;
944 pInfo->cWidth = width;
945 pInfo->cHeight = height;
946 pInfo->cBitsPerPixel = bitsPerPixel;
947 pInfo->cbLine = lineSize;
948
949 pfb->Unlock();
950
951 fAvailable = true;
952 }
953
954 if (server->maFramebuffers[uScreenId])
955 {
956 server->maFramebuffers[uScreenId]->Release();
957 }
958 server->maFramebuffers[uScreenId] = pfb;
959
960 return fAvailable;
961}
962
963DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferLock(void *pvCallback, unsigned uScreenId)
964{
965 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
966
967 if (server->maFramebuffers[uScreenId])
968 {
969 server->maFramebuffers[uScreenId]->Lock();
970 }
971}
972
973DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferUnlock(void *pvCallback, unsigned uScreenId)
974{
975 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
976
977 if (server->maFramebuffers[uScreenId])
978 {
979 server->maFramebuffers[uScreenId]->Unlock();
980 }
981}
982
983static void fixKbdLockStatus(VRDPInputSynch *pInputSynch, IKeyboard *pKeyboard)
984{
985 if ( pInputSynch->cGuestNumLockAdaptions
986 && (pInputSynch->fGuestNumLock != pInputSynch->fClientNumLock))
987 {
988 pInputSynch->cGuestNumLockAdaptions--;
989 pKeyboard->PutScancode(0x45);
990 pKeyboard->PutScancode(0x45 | 0x80);
991 }
992 if ( pInputSynch->cGuestCapsLockAdaptions
993 && (pInputSynch->fGuestCapsLock != pInputSynch->fClientCapsLock))
994 {
995 pInputSynch->cGuestCapsLockAdaptions--;
996 pKeyboard->PutScancode(0x3a);
997 pKeyboard->PutScancode(0x3a | 0x80);
998 }
999}
1000
1001DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackInput(void *pvCallback, int type, const void *pvInput, unsigned cbInput)
1002{
1003 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1004 Console *pConsole = server->mConsole;
1005
1006 switch (type)
1007 {
1008 case VRDE_INPUT_SCANCODE:
1009 {
1010 if (cbInput == sizeof(VRDEINPUTSCANCODE))
1011 {
1012 IKeyboard *pKeyboard = pConsole->getKeyboard();
1013
1014 const VRDEINPUTSCANCODE *pInputScancode = (VRDEINPUTSCANCODE *)pvInput;
1015
1016 /* Track lock keys. */
1017 if (pInputScancode->uScancode == 0x45)
1018 {
1019 server->m_InputSynch.fClientNumLock = !server->m_InputSynch.fClientNumLock;
1020 }
1021 else if (pInputScancode->uScancode == 0x3a)
1022 {
1023 server->m_InputSynch.fClientCapsLock = !server->m_InputSynch.fClientCapsLock;
1024 }
1025 else if (pInputScancode->uScancode == 0x46)
1026 {
1027 server->m_InputSynch.fClientScrollLock = !server->m_InputSynch.fClientScrollLock;
1028 }
1029 else if ((pInputScancode->uScancode & 0x80) == 0)
1030 {
1031 /* Key pressed. */
1032 fixKbdLockStatus(&server->m_InputSynch, pKeyboard);
1033 }
1034
1035 pKeyboard->PutScancode((LONG)pInputScancode->uScancode);
1036 }
1037 } break;
1038
1039 case VRDE_INPUT_POINT:
1040 {
1041 if (cbInput == sizeof(VRDEINPUTPOINT))
1042 {
1043 const VRDEINPUTPOINT *pInputPoint = (VRDEINPUTPOINT *)pvInput;
1044
1045 int mouseButtons = 0;
1046 int iWheel = 0;
1047
1048 if (pInputPoint->uButtons & VRDE_INPUT_POINT_BUTTON1)
1049 {
1050 mouseButtons |= MouseButtonState_LeftButton;
1051 }
1052 if (pInputPoint->uButtons & VRDE_INPUT_POINT_BUTTON2)
1053 {
1054 mouseButtons |= MouseButtonState_RightButton;
1055 }
1056 if (pInputPoint->uButtons & VRDE_INPUT_POINT_BUTTON3)
1057 {
1058 mouseButtons |= MouseButtonState_MiddleButton;
1059 }
1060 if (pInputPoint->uButtons & VRDE_INPUT_POINT_WHEEL_UP)
1061 {
1062 mouseButtons |= MouseButtonState_WheelUp;
1063 iWheel = -1;
1064 }
1065 if (pInputPoint->uButtons & VRDE_INPUT_POINT_WHEEL_DOWN)
1066 {
1067 mouseButtons |= MouseButtonState_WheelDown;
1068 iWheel = 1;
1069 }
1070
1071 if (server->m_fGuestWantsAbsolute)
1072 {
1073 pConsole->getMouse()->PutMouseEventAbsolute(pInputPoint->x + 1, pInputPoint->y + 1, iWheel, 0 /* Horizontal wheel */, mouseButtons);
1074 } else
1075 {
1076 pConsole->getMouse()->PutMouseEvent(pInputPoint->x - server->m_mousex,
1077 pInputPoint->y - server->m_mousey,
1078 iWheel, 0 /* Horizontal wheel */, mouseButtons);
1079 server->m_mousex = pInputPoint->x;
1080 server->m_mousey = pInputPoint->y;
1081 }
1082 }
1083 } break;
1084
1085 case VRDE_INPUT_CAD:
1086 {
1087 pConsole->getKeyboard()->PutCAD();
1088 } break;
1089
1090 case VRDE_INPUT_RESET:
1091 {
1092 pConsole->Reset();
1093 } break;
1094
1095 case VRDE_INPUT_SYNCH:
1096 {
1097 if (cbInput == sizeof(VRDEINPUTSYNCH))
1098 {
1099 IKeyboard *pKeyboard = pConsole->getKeyboard();
1100
1101 const VRDEINPUTSYNCH *pInputSynch = (VRDEINPUTSYNCH *)pvInput;
1102
1103 server->m_InputSynch.fClientNumLock = (pInputSynch->uLockStatus & VRDE_INPUT_SYNCH_NUMLOCK) != 0;
1104 server->m_InputSynch.fClientCapsLock = (pInputSynch->uLockStatus & VRDE_INPUT_SYNCH_CAPITAL) != 0;
1105 server->m_InputSynch.fClientScrollLock = (pInputSynch->uLockStatus & VRDE_INPUT_SYNCH_SCROLL) != 0;
1106
1107 /* The client initiated synchronization. Always make the guest to reflect the client state.
1108 * Than means, when the guest changes the state itself, it is forced to return to the client
1109 * state.
1110 */
1111 if (server->m_InputSynch.fClientNumLock != server->m_InputSynch.fGuestNumLock)
1112 {
1113 server->m_InputSynch.cGuestNumLockAdaptions = 2;
1114 }
1115
1116 if (server->m_InputSynch.fClientCapsLock != server->m_InputSynch.fGuestCapsLock)
1117 {
1118 server->m_InputSynch.cGuestCapsLockAdaptions = 2;
1119 }
1120
1121 fixKbdLockStatus(&server->m_InputSynch, pKeyboard);
1122 }
1123 } break;
1124
1125 default:
1126 break;
1127 }
1128}
1129
1130DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackVideoModeHint(void *pvCallback, unsigned cWidth, unsigned cHeight, unsigned cBitsPerPixel, unsigned uScreenId)
1131{
1132 ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
1133
1134 server->mConsole->getDisplay()->SetVideoModeHint(cWidth, cHeight, cBitsPerPixel, uScreenId);
1135}
1136
1137ConsoleVRDPServer::ConsoleVRDPServer(Console *console)
1138{
1139 mConsole = console;
1140
1141 int rc = RTCritSectInit(&mCritSect);
1142 AssertRC(rc);
1143
1144 mcClipboardRefs = 0;
1145 mpfnClipboardCallback = NULL;
1146
1147#ifdef VBOX_WITH_USB
1148 mUSBBackends.pHead = NULL;
1149 mUSBBackends.pTail = NULL;
1150
1151 mUSBBackends.thread = NIL_RTTHREAD;
1152 mUSBBackends.fThreadRunning = false;
1153 mUSBBackends.event = 0;
1154#endif
1155
1156 mhServer = 0;
1157
1158 m_fGuestWantsAbsolute = false;
1159 m_mousex = 0;
1160 m_mousey = 0;
1161
1162 m_InputSynch.cGuestNumLockAdaptions = 2;
1163 m_InputSynch.cGuestCapsLockAdaptions = 2;
1164
1165 m_InputSynch.fGuestNumLock = false;
1166 m_InputSynch.fGuestCapsLock = false;
1167 m_InputSynch.fGuestScrollLock = false;
1168
1169 m_InputSynch.fClientNumLock = false;
1170 m_InputSynch.fClientCapsLock = false;
1171 m_InputSynch.fClientScrollLock = false;
1172
1173 memset(maFramebuffers, 0, sizeof(maFramebuffers));
1174
1175 {
1176 ComPtr<IEventSource> es;
1177 console->COMGETTER(EventSource)(es.asOutParam());
1178 mConsoleListener = new VRDPConsoleListenerImpl(this);
1179 com::SafeArray <VBoxEventType_T> eventTypes;
1180 eventTypes.push_back(VBoxEventType_OnMousePointerShapeChanged);
1181 eventTypes.push_back(VBoxEventType_OnMouseCapabilityChanged);
1182 eventTypes.push_back(VBoxEventType_OnKeyboardLedsChanged);
1183 es->RegisterListener(mConsoleListener, ComSafeArrayAsInParam(eventTypes), true);
1184 }
1185
1186 mVRDPBindPort = -1;
1187
1188 mAuthLibrary = 0;
1189}
1190
1191ConsoleVRDPServer::~ConsoleVRDPServer()
1192{
1193 Stop();
1194
1195 if (mConsoleListener)
1196 {
1197 ComPtr<IEventSource> es;
1198 mConsole->COMGETTER(EventSource)(es.asOutParam());
1199 es->UnregisterListener(mConsoleListener);
1200 mConsoleListener->Release();
1201 mConsoleListener = NULL;
1202 }
1203
1204 unsigned i;
1205 for (i = 0; i < RT_ELEMENTS(maFramebuffers); i++)
1206 {
1207 if (maFramebuffers[i])
1208 {
1209 maFramebuffers[i]->Release();
1210 maFramebuffers[i] = NULL;
1211 }
1212 }
1213
1214 if (RTCritSectIsInitialized(&mCritSect))
1215 {
1216 RTCritSectDelete(&mCritSect);
1217 memset(&mCritSect, 0, sizeof(mCritSect));
1218 }
1219}
1220
1221int ConsoleVRDPServer::Launch(void)
1222{
1223 LogFlowThisFunc(("\n"));
1224
1225 int rc = VINF_SUCCESS;
1226
1227 /*
1228 * Check that a VRDE library name is set.
1229 */
1230 Bstr library;
1231 Utf8Str filename;
1232
1233 IVRDEServer *server = mConsole->getVRDEServer();
1234 Assert(server);
1235
1236 HRESULT hrc = server->COMGETTER(VRDELibrary)(library.asOutParam());
1237 if (SUCCEEDED(hrc))
1238 {
1239 filename = library;
1240 }
1241
1242 if (filename.isEmpty())
1243 {
1244 return VINF_NOT_SUPPORTED;
1245 }
1246
1247 /*
1248 * Load the VRDE library and start the server, if it is enabled.
1249 */
1250 BOOL fEnabled = FALSE;
1251
1252 hrc = server->COMGETTER(Enabled)(&fEnabled);
1253 AssertComRC(hrc);
1254
1255 if (SUCCEEDED(hrc) && fEnabled)
1256 {
1257 rc = loadVRDPLibrary(filename.c_str());
1258
1259 if (RT_SUCCESS(rc))
1260 {
1261 rc = mpfnVRDECreateServer(&mCallbacks.header, this, (VRDEINTERFACEHDR **)&mpEntryPoints, &mhServer);
1262
1263 if (RT_SUCCESS(rc))
1264 {
1265#ifdef VBOX_WITH_USB
1266 remoteUSBThreadStart();
1267#endif /* VBOX_WITH_USB */
1268 }
1269 else if (rc != VERR_NET_ADDRESS_IN_USE)
1270 {
1271 LogRel(("VRDE: Could not start VRDP server rc = %Rrc\n", rc));
1272 }
1273 }
1274 }
1275
1276 return rc;
1277}
1278
1279void ConsoleVRDPServer::EnableConnections(void)
1280{
1281 if (mpEntryPoints && mhServer)
1282 {
1283 mpEntryPoints->VRDEEnableConnections(mhServer, true);
1284 }
1285}
1286
1287void ConsoleVRDPServer::DisconnectClient(uint32_t u32ClientId, bool fReconnect)
1288{
1289 if (mpEntryPoints && mhServer)
1290 {
1291 mpEntryPoints->VRDEDisconnect(mhServer, u32ClientId, fReconnect);
1292 }
1293}
1294
1295void ConsoleVRDPServer::MousePointerUpdate(const VRDECOLORPOINTER *pPointer)
1296{
1297 if (mpEntryPoints && mhServer)
1298 {
1299 mpEntryPoints->VRDEColorPointer(mhServer, pPointer);
1300 }
1301}
1302
1303void ConsoleVRDPServer::MousePointerHide(void)
1304{
1305 if (mpEntryPoints && mhServer)
1306 {
1307 mpEntryPoints->VRDEHidePointer(mhServer);
1308 }
1309}
1310
1311void ConsoleVRDPServer::Stop(void)
1312{
1313 Assert(VALID_PTR(this)); /** @todo r=bird: there are(/was) some odd cases where this buster was invalid on
1314 * linux. Just remove this when it's 100% sure that problem has been fixed. */
1315 if (mhServer)
1316 {
1317 HVRDESERVER hServer = mhServer;
1318
1319 /* Reset the handle to avoid further calls to the server. */
1320 mhServer = 0;
1321
1322 if (mpEntryPoints && hServer)
1323 {
1324 mpEntryPoints->VRDEDestroy(hServer);
1325 }
1326 }
1327
1328#ifdef VBOX_WITH_USB
1329 remoteUSBThreadStop();
1330#endif /* VBOX_WITH_USB */
1331
1332 mpfnAuthEntry = NULL;
1333 mpfnAuthEntry2 = NULL;
1334
1335 if (mAuthLibrary)
1336 {
1337 RTLdrClose(mAuthLibrary);
1338 mAuthLibrary = 0;
1339 }
1340}
1341
1342/* Worker thread for Remote USB. The thread polls the clients for
1343 * the list of attached USB devices.
1344 * The thread is also responsible for attaching/detaching devices
1345 * to/from the VM.
1346 *
1347 * It is expected that attaching/detaching is not a frequent operation.
1348 *
1349 * The thread is always running when the VRDP server is active.
1350 *
1351 * The thread scans backends and requests the device list every 2 seconds.
1352 *
1353 * When device list is available, the thread calls the Console to process it.
1354 *
1355 */
1356#define VRDP_DEVICE_LIST_PERIOD_MS (2000)
1357
1358#ifdef VBOX_WITH_USB
1359static DECLCALLBACK(int) threadRemoteUSB(RTTHREAD self, void *pvUser)
1360{
1361 ConsoleVRDPServer *pOwner = (ConsoleVRDPServer *)pvUser;
1362
1363 LogFlow(("Console::threadRemoteUSB: start. owner = %p.\n", pOwner));
1364
1365 pOwner->notifyRemoteUSBThreadRunning(self);
1366
1367 while (pOwner->isRemoteUSBThreadRunning())
1368 {
1369 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1370
1371 while ((pRemoteUSBBackend = pOwner->usbBackendGetNext(pRemoteUSBBackend)) != NULL)
1372 {
1373 pRemoteUSBBackend->PollRemoteDevices();
1374 }
1375
1376 pOwner->waitRemoteUSBThreadEvent(VRDP_DEVICE_LIST_PERIOD_MS);
1377
1378 LogFlow(("Console::threadRemoteUSB: iteration. owner = %p.\n", pOwner));
1379 }
1380
1381 return VINF_SUCCESS;
1382}
1383
1384void ConsoleVRDPServer::notifyRemoteUSBThreadRunning(RTTHREAD thread)
1385{
1386 mUSBBackends.thread = thread;
1387 mUSBBackends.fThreadRunning = true;
1388 int rc = RTThreadUserSignal(thread);
1389 AssertRC(rc);
1390}
1391
1392bool ConsoleVRDPServer::isRemoteUSBThreadRunning(void)
1393{
1394 return mUSBBackends.fThreadRunning;
1395}
1396
1397void ConsoleVRDPServer::waitRemoteUSBThreadEvent(RTMSINTERVAL cMillies)
1398{
1399 int rc = RTSemEventWait(mUSBBackends.event, cMillies);
1400 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1401 NOREF(rc);
1402}
1403
1404void ConsoleVRDPServer::remoteUSBThreadStart(void)
1405{
1406 int rc = RTSemEventCreate(&mUSBBackends.event);
1407
1408 if (RT_FAILURE(rc))
1409 {
1410 AssertFailed();
1411 mUSBBackends.event = 0;
1412 }
1413
1414 if (RT_SUCCESS(rc))
1415 {
1416 rc = RTThreadCreate(&mUSBBackends.thread, threadRemoteUSB, this, 65536,
1417 RTTHREADTYPE_VRDP_IO, RTTHREADFLAGS_WAITABLE, "remote usb");
1418 }
1419
1420 if (RT_FAILURE(rc))
1421 {
1422 LogRel(("Warning: could not start the remote USB thread, rc = %Rrc!!!\n", rc));
1423 mUSBBackends.thread = NIL_RTTHREAD;
1424 }
1425 else
1426 {
1427 /* Wait until the thread is ready. */
1428 rc = RTThreadUserWait(mUSBBackends.thread, 60000);
1429 AssertRC(rc);
1430 Assert (mUSBBackends.fThreadRunning || RT_FAILURE(rc));
1431 }
1432}
1433
1434void ConsoleVRDPServer::remoteUSBThreadStop(void)
1435{
1436 mUSBBackends.fThreadRunning = false;
1437
1438 if (mUSBBackends.thread != NIL_RTTHREAD)
1439 {
1440 Assert (mUSBBackends.event != 0);
1441
1442 RTSemEventSignal(mUSBBackends.event);
1443
1444 int rc = RTThreadWait(mUSBBackends.thread, 60000, NULL);
1445 AssertRC(rc);
1446
1447 mUSBBackends.thread = NIL_RTTHREAD;
1448 }
1449
1450 if (mUSBBackends.event)
1451 {
1452 RTSemEventDestroy(mUSBBackends.event);
1453 mUSBBackends.event = 0;
1454 }
1455}
1456#endif /* VBOX_WITH_USB */
1457
1458VRDPAuthResult ConsoleVRDPServer::Authenticate(const Guid &uuid, VRDPAuthGuestJudgement guestJudgement,
1459 const char *pszUser, const char *pszPassword, const char *pszDomain,
1460 uint32_t u32ClientId)
1461{
1462 VRDPAUTHUUID rawuuid;
1463
1464 memcpy(rawuuid, uuid.raw(), sizeof(rawuuid));
1465
1466 LogFlow(("ConsoleVRDPServer::Authenticate: uuid = %RTuuid, guestJudgement = %d, pszUser = %s, pszPassword = %s, pszDomain = %s, u32ClientId = %d\n",
1467 rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, u32ClientId));
1468
1469 /*
1470 * Called only from VRDP input thread. So thread safety is not required.
1471 */
1472
1473 if (!mAuthLibrary)
1474 {
1475 /* Load the external authentication library. */
1476
1477 ComPtr<IMachine> machine;
1478 mConsole->COMGETTER(Machine)(machine.asOutParam());
1479
1480 ComPtr<IVirtualBox> virtualBox;
1481 machine->COMGETTER(Parent)(virtualBox.asOutParam());
1482
1483 ComPtr<ISystemProperties> systemProperties;
1484 virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
1485
1486 Bstr authLibrary;
1487 systemProperties->COMGETTER(VRDEAuthLibrary)(authLibrary.asOutParam());
1488
1489 Utf8Str filename = authLibrary;
1490
1491 LogRel(("VRDPAUTH: ConsoleVRDPServer::Authenticate: loading external authentication library '%ls'\n", authLibrary.raw()));
1492
1493 int rc;
1494 if (RTPathHavePath(filename.c_str()))
1495 rc = RTLdrLoad(filename.c_str(), &mAuthLibrary);
1496 else
1497 rc = RTLdrLoadAppPriv(filename.c_str(), &mAuthLibrary);
1498
1499 if (RT_FAILURE(rc))
1500 LogRel(("VRDPAUTH: Failed to load external authentication library. Error code: %Rrc\n", rc));
1501
1502 if (RT_SUCCESS(rc))
1503 {
1504 /* Get the entry point. */
1505 mpfnAuthEntry2 = NULL;
1506 int rc2 = RTLdrGetSymbol(mAuthLibrary, "VRDPAuth2", (void**)&mpfnAuthEntry2);
1507 if (RT_FAILURE(rc2))
1508 {
1509 if (rc2 != VERR_SYMBOL_NOT_FOUND)
1510 {
1511 LogRel(("VRDPAUTH: Could not resolve import '%s'. Error code: %Rrc\n", "VRDPAuth2", rc2));
1512 }
1513 rc = rc2;
1514 }
1515
1516 /* Get the entry point. */
1517 mpfnAuthEntry = NULL;
1518 rc2 = RTLdrGetSymbol(mAuthLibrary, "VRDPAuth", (void**)&mpfnAuthEntry);
1519 if (RT_FAILURE(rc2))
1520 {
1521 if (rc2 != VERR_SYMBOL_NOT_FOUND)
1522 {
1523 LogRel(("VRDPAUTH: Could not resolve import '%s'. Error code: %Rrc\n", "VRDPAuth", rc2));
1524 }
1525 rc = rc2;
1526 }
1527
1528 if (mpfnAuthEntry2 || mpfnAuthEntry)
1529 {
1530 LogRel(("VRDPAUTH: Using entry point '%s'.\n", mpfnAuthEntry2? "VRDPAuth2": "VRDPAuth"));
1531 rc = VINF_SUCCESS;
1532 }
1533 }
1534
1535 if (RT_FAILURE(rc))
1536 {
1537 mConsole->setError(E_FAIL,
1538 mConsole->tr("Could not load the external authentication library '%s' (%Rrc)"),
1539 filename.c_str(),
1540 rc);
1541
1542 mpfnAuthEntry = NULL;
1543 mpfnAuthEntry2 = NULL;
1544
1545 if (mAuthLibrary)
1546 {
1547 RTLdrClose(mAuthLibrary);
1548 mAuthLibrary = 0;
1549 }
1550
1551 return VRDPAuthAccessDenied;
1552 }
1553 }
1554
1555 Assert(mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2));
1556
1557 VRDPAuthResult result = mpfnAuthEntry2?
1558 mpfnAuthEntry2(&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, true, u32ClientId):
1559 mpfnAuthEntry(&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain);
1560
1561 switch (result)
1562 {
1563 case VRDPAuthAccessDenied:
1564 LogRel(("VRDPAUTH: external authentication module returned 'access denied'\n"));
1565 break;
1566 case VRDPAuthAccessGranted:
1567 LogRel(("VRDPAUTH: external authentication module returned 'access granted'\n"));
1568 break;
1569 case VRDPAuthDelegateToGuest:
1570 LogRel(("VRDPAUTH: external authentication module returned 'delegate request to guest'\n"));
1571 break;
1572 default:
1573 LogRel(("VRDPAUTH: external authentication module returned incorrect return code %d\n", result));
1574 result = VRDPAuthAccessDenied;
1575 }
1576
1577 LogFlow(("ConsoleVRDPServer::Authenticate: result = %d\n", result));
1578
1579 return result;
1580}
1581
1582void ConsoleVRDPServer::AuthDisconnect(const Guid &uuid, uint32_t u32ClientId)
1583{
1584 VRDPAUTHUUID rawuuid;
1585
1586 memcpy(rawuuid, uuid.raw(), sizeof(rawuuid));
1587
1588 LogFlow(("ConsoleVRDPServer::AuthDisconnect: uuid = %RTuuid, u32ClientId = %d\n",
1589 rawuuid, u32ClientId));
1590
1591 Assert(mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2));
1592
1593 if (mpfnAuthEntry2)
1594 mpfnAuthEntry2(&rawuuid, VRDPAuthGuestNotAsked, NULL, NULL, NULL, false, u32ClientId);
1595}
1596
1597int ConsoleVRDPServer::lockConsoleVRDPServer(void)
1598{
1599 int rc = RTCritSectEnter(&mCritSect);
1600 AssertRC(rc);
1601 return rc;
1602}
1603
1604void ConsoleVRDPServer::unlockConsoleVRDPServer(void)
1605{
1606 RTCritSectLeave(&mCritSect);
1607}
1608
1609DECLCALLBACK(int) ConsoleVRDPServer::ClipboardCallback(void *pvCallback,
1610 uint32_t u32ClientId,
1611 uint32_t u32Function,
1612 uint32_t u32Format,
1613 const void *pvData,
1614 uint32_t cbData)
1615{
1616 LogFlowFunc(("pvCallback = %p, u32ClientId = %d, u32Function = %d, u32Format = 0x%08X, pvData = %p, cbData = %d\n",
1617 pvCallback, u32ClientId, u32Function, u32Format, pvData, cbData));
1618
1619 int rc = VINF_SUCCESS;
1620
1621 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvCallback);
1622
1623 NOREF(u32ClientId);
1624
1625 switch (u32Function)
1626 {
1627 case VRDE_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE:
1628 {
1629 if (pServer->mpfnClipboardCallback)
1630 {
1631 pServer->mpfnClipboardCallback(VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE,
1632 u32Format,
1633 (void *)pvData,
1634 cbData);
1635 }
1636 } break;
1637
1638 case VRDE_CLIPBOARD_FUNCTION_DATA_READ:
1639 {
1640 if (pServer->mpfnClipboardCallback)
1641 {
1642 pServer->mpfnClipboardCallback(VBOX_CLIPBOARD_EXT_FN_DATA_READ,
1643 u32Format,
1644 (void *)pvData,
1645 cbData);
1646 }
1647 } break;
1648
1649 default:
1650 rc = VERR_NOT_SUPPORTED;
1651 }
1652
1653 return rc;
1654}
1655
1656DECLCALLBACK(int) ConsoleVRDPServer::ClipboardServiceExtension(void *pvExtension,
1657 uint32_t u32Function,
1658 void *pvParms,
1659 uint32_t cbParms)
1660{
1661 LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
1662 pvExtension, u32Function, pvParms, cbParms));
1663
1664 int rc = VINF_SUCCESS;
1665
1666 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvExtension);
1667
1668 VBOXCLIPBOARDEXTPARMS *pParms = (VBOXCLIPBOARDEXTPARMS *)pvParms;
1669
1670 switch (u32Function)
1671 {
1672 case VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK:
1673 {
1674 pServer->mpfnClipboardCallback = pParms->u.pfnCallback;
1675 } break;
1676
1677 case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
1678 {
1679 /* The guest announces clipboard formats. This must be delivered to all clients. */
1680 if (mpEntryPoints && pServer->mhServer)
1681 {
1682 mpEntryPoints->VRDEClipboard(pServer->mhServer,
1683 VRDE_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE,
1684 pParms->u32Format,
1685 NULL,
1686 0,
1687 NULL);
1688 }
1689 } break;
1690
1691 case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
1692 {
1693 /* The clipboard service expects that the pvData buffer will be filled
1694 * with clipboard data. The server returns the data from the client that
1695 * announced the requested format most recently.
1696 */
1697 if (mpEntryPoints && pServer->mhServer)
1698 {
1699 mpEntryPoints->VRDEClipboard(pServer->mhServer,
1700 VRDE_CLIPBOARD_FUNCTION_DATA_READ,
1701 pParms->u32Format,
1702 pParms->u.pvData,
1703 pParms->cbData,
1704 &pParms->cbData);
1705 }
1706 } break;
1707
1708 case VBOX_CLIPBOARD_EXT_FN_DATA_WRITE:
1709 {
1710 if (mpEntryPoints && pServer->mhServer)
1711 {
1712 mpEntryPoints->VRDEClipboard(pServer->mhServer,
1713 VRDE_CLIPBOARD_FUNCTION_DATA_WRITE,
1714 pParms->u32Format,
1715 pParms->u.pvData,
1716 pParms->cbData,
1717 NULL);
1718 }
1719 } break;
1720
1721 default:
1722 rc = VERR_NOT_SUPPORTED;
1723 }
1724
1725 return rc;
1726}
1727
1728void ConsoleVRDPServer::ClipboardCreate(uint32_t u32ClientId)
1729{
1730 int rc = lockConsoleVRDPServer();
1731
1732 if (RT_SUCCESS(rc))
1733 {
1734 if (mcClipboardRefs == 0)
1735 {
1736 rc = HGCMHostRegisterServiceExtension(&mhClipboard, "VBoxSharedClipboard", ClipboardServiceExtension, this);
1737
1738 if (RT_SUCCESS(rc))
1739 {
1740 mcClipboardRefs++;
1741 }
1742 }
1743
1744 unlockConsoleVRDPServer();
1745 }
1746}
1747
1748void ConsoleVRDPServer::ClipboardDelete(uint32_t u32ClientId)
1749{
1750 int rc = lockConsoleVRDPServer();
1751
1752 if (RT_SUCCESS(rc))
1753 {
1754 mcClipboardRefs--;
1755
1756 if (mcClipboardRefs == 0)
1757 {
1758 HGCMHostUnregisterServiceExtension(mhClipboard);
1759 }
1760
1761 unlockConsoleVRDPServer();
1762 }
1763}
1764
1765/* That is called on INPUT thread of the VRDP server.
1766 * The ConsoleVRDPServer keeps a list of created backend instances.
1767 */
1768void ConsoleVRDPServer::USBBackendCreate(uint32_t u32ClientId, void **ppvIntercept)
1769{
1770#ifdef VBOX_WITH_USB
1771 LogFlow(("ConsoleVRDPServer::USBBackendCreate: u32ClientId = %d\n", u32ClientId));
1772
1773 /* Create a new instance of the USB backend for the new client. */
1774 RemoteUSBBackend *pRemoteUSBBackend = new RemoteUSBBackend(mConsole, this, u32ClientId);
1775
1776 if (pRemoteUSBBackend)
1777 {
1778 pRemoteUSBBackend->AddRef(); /* 'Release' called in USBBackendDelete. */
1779
1780 /* Append the new instance in the list. */
1781 int rc = lockConsoleVRDPServer();
1782
1783 if (RT_SUCCESS(rc))
1784 {
1785 pRemoteUSBBackend->pNext = mUSBBackends.pHead;
1786 if (mUSBBackends.pHead)
1787 {
1788 mUSBBackends.pHead->pPrev = pRemoteUSBBackend;
1789 }
1790 else
1791 {
1792 mUSBBackends.pTail = pRemoteUSBBackend;
1793 }
1794
1795 mUSBBackends.pHead = pRemoteUSBBackend;
1796
1797 unlockConsoleVRDPServer();
1798
1799 if (ppvIntercept)
1800 {
1801 *ppvIntercept = pRemoteUSBBackend;
1802 }
1803 }
1804
1805 if (RT_FAILURE(rc))
1806 {
1807 pRemoteUSBBackend->Release();
1808 }
1809 }
1810#endif /* VBOX_WITH_USB */
1811}
1812
1813void ConsoleVRDPServer::USBBackendDelete(uint32_t u32ClientId)
1814{
1815#ifdef VBOX_WITH_USB
1816 LogFlow(("ConsoleVRDPServer::USBBackendDelete: u32ClientId = %d\n", u32ClientId));
1817
1818 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1819
1820 /* Find the instance. */
1821 int rc = lockConsoleVRDPServer();
1822
1823 if (RT_SUCCESS(rc))
1824 {
1825 pRemoteUSBBackend = usbBackendFind(u32ClientId);
1826
1827 if (pRemoteUSBBackend)
1828 {
1829 /* Notify that it will be deleted. */
1830 pRemoteUSBBackend->NotifyDelete();
1831 }
1832
1833 unlockConsoleVRDPServer();
1834 }
1835
1836 if (pRemoteUSBBackend)
1837 {
1838 /* Here the instance has been excluded from the list and can be dereferenced. */
1839 pRemoteUSBBackend->Release();
1840 }
1841#endif
1842}
1843
1844void *ConsoleVRDPServer::USBBackendRequestPointer(uint32_t u32ClientId, const Guid *pGuid)
1845{
1846#ifdef VBOX_WITH_USB
1847 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1848
1849 /* Find the instance. */
1850 int rc = lockConsoleVRDPServer();
1851
1852 if (RT_SUCCESS(rc))
1853 {
1854 pRemoteUSBBackend = usbBackendFind(u32ClientId);
1855
1856 if (pRemoteUSBBackend)
1857 {
1858 /* Inform the backend instance that it is referenced by the Guid. */
1859 bool fAdded = pRemoteUSBBackend->addUUID(pGuid);
1860
1861 if (fAdded)
1862 {
1863 /* Reference the instance because its pointer is being taken. */
1864 pRemoteUSBBackend->AddRef(); /* 'Release' is called in USBBackendReleasePointer. */
1865 }
1866 else
1867 {
1868 pRemoteUSBBackend = NULL;
1869 }
1870 }
1871
1872 unlockConsoleVRDPServer();
1873 }
1874
1875 if (pRemoteUSBBackend)
1876 {
1877 return pRemoteUSBBackend->GetBackendCallbackPointer();
1878 }
1879
1880#endif
1881 return NULL;
1882}
1883
1884void ConsoleVRDPServer::USBBackendReleasePointer(const Guid *pGuid)
1885{
1886#ifdef VBOX_WITH_USB
1887 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1888
1889 /* Find the instance. */
1890 int rc = lockConsoleVRDPServer();
1891
1892 if (RT_SUCCESS(rc))
1893 {
1894 pRemoteUSBBackend = usbBackendFindByUUID(pGuid);
1895
1896 if (pRemoteUSBBackend)
1897 {
1898 pRemoteUSBBackend->removeUUID(pGuid);
1899 }
1900
1901 unlockConsoleVRDPServer();
1902
1903 if (pRemoteUSBBackend)
1904 {
1905 pRemoteUSBBackend->Release();
1906 }
1907 }
1908#endif
1909}
1910
1911RemoteUSBBackend *ConsoleVRDPServer::usbBackendGetNext(RemoteUSBBackend *pRemoteUSBBackend)
1912{
1913 LogFlow(("ConsoleVRDPServer::usbBackendGetNext: pBackend = %p\n", pRemoteUSBBackend));
1914
1915 RemoteUSBBackend *pNextRemoteUSBBackend = NULL;
1916#ifdef VBOX_WITH_USB
1917
1918 int rc = lockConsoleVRDPServer();
1919
1920 if (RT_SUCCESS(rc))
1921 {
1922 if (pRemoteUSBBackend == NULL)
1923 {
1924 /* The first backend in the list is requested. */
1925 pNextRemoteUSBBackend = mUSBBackends.pHead;
1926 }
1927 else
1928 {
1929 /* Get pointer to the next backend. */
1930 pNextRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1931 }
1932
1933 if (pNextRemoteUSBBackend)
1934 {
1935 pNextRemoteUSBBackend->AddRef();
1936 }
1937
1938 unlockConsoleVRDPServer();
1939
1940 if (pRemoteUSBBackend)
1941 {
1942 pRemoteUSBBackend->Release();
1943 }
1944 }
1945#endif
1946
1947 return pNextRemoteUSBBackend;
1948}
1949
1950#ifdef VBOX_WITH_USB
1951/* Internal method. Called under the ConsoleVRDPServerLock. */
1952RemoteUSBBackend *ConsoleVRDPServer::usbBackendFind(uint32_t u32ClientId)
1953{
1954 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
1955
1956 while (pRemoteUSBBackend)
1957 {
1958 if (pRemoteUSBBackend->ClientId() == u32ClientId)
1959 {
1960 break;
1961 }
1962
1963 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1964 }
1965
1966 return pRemoteUSBBackend;
1967}
1968
1969/* Internal method. Called under the ConsoleVRDPServerLock. */
1970RemoteUSBBackend *ConsoleVRDPServer::usbBackendFindByUUID(const Guid *pGuid)
1971{
1972 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
1973
1974 while (pRemoteUSBBackend)
1975 {
1976 if (pRemoteUSBBackend->findUUID(pGuid))
1977 {
1978 break;
1979 }
1980
1981 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1982 }
1983
1984 return pRemoteUSBBackend;
1985}
1986#endif
1987
1988/* Internal method. Called by the backend destructor. */
1989void ConsoleVRDPServer::usbBackendRemoveFromList(RemoteUSBBackend *pRemoteUSBBackend)
1990{
1991#ifdef VBOX_WITH_USB
1992 int rc = lockConsoleVRDPServer();
1993 AssertRC(rc);
1994
1995 /* Exclude the found instance from the list. */
1996 if (pRemoteUSBBackend->pNext)
1997 {
1998 pRemoteUSBBackend->pNext->pPrev = pRemoteUSBBackend->pPrev;
1999 }
2000 else
2001 {
2002 mUSBBackends.pTail = (RemoteUSBBackend *)pRemoteUSBBackend->pPrev;
2003 }
2004
2005 if (pRemoteUSBBackend->pPrev)
2006 {
2007 pRemoteUSBBackend->pPrev->pNext = pRemoteUSBBackend->pNext;
2008 }
2009 else
2010 {
2011 mUSBBackends.pHead = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
2012 }
2013
2014 pRemoteUSBBackend->pNext = pRemoteUSBBackend->pPrev = NULL;
2015
2016 unlockConsoleVRDPServer();
2017#endif
2018}
2019
2020
2021void ConsoleVRDPServer::SendUpdate(unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate) const
2022{
2023 if (mpEntryPoints && mhServer)
2024 {
2025 mpEntryPoints->VRDEUpdate(mhServer, uScreenId, pvUpdate, cbUpdate);
2026 }
2027}
2028
2029void ConsoleVRDPServer::SendResize(void) const
2030{
2031 if (mpEntryPoints && mhServer)
2032 {
2033 mpEntryPoints->VRDEResize(mhServer);
2034 }
2035}
2036
2037void ConsoleVRDPServer::SendUpdateBitmap(unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h) const
2038{
2039 VRDEORDERHDR update;
2040 update.x = x;
2041 update.y = y;
2042 update.w = w;
2043 update.h = h;
2044 if (mpEntryPoints && mhServer)
2045 {
2046 mpEntryPoints->VRDEUpdate(mhServer, uScreenId, &update, sizeof(update));
2047 }
2048}
2049
2050void ConsoleVRDPServer::SendAudioSamples(void *pvSamples, uint32_t cSamples, VRDEAUDIOFORMAT format) const
2051{
2052 if (mpEntryPoints && mhServer)
2053 {
2054 mpEntryPoints->VRDEAudioSamples(mhServer, pvSamples, cSamples, format);
2055 }
2056}
2057
2058void ConsoleVRDPServer::SendAudioVolume(uint16_t left, uint16_t right) const
2059{
2060 if (mpEntryPoints && mhServer)
2061 {
2062 mpEntryPoints->VRDEAudioVolume(mhServer, left, right);
2063 }
2064}
2065
2066void ConsoleVRDPServer::SendUSBRequest(uint32_t u32ClientId, void *pvParms, uint32_t cbParms) const
2067{
2068 if (mpEntryPoints && mhServer)
2069 {
2070 mpEntryPoints->VRDEUSBRequest(mhServer, u32ClientId, pvParms, cbParms);
2071 }
2072}
2073
2074void ConsoleVRDPServer::QueryInfo(uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const
2075{
2076 if (index == VRDE_QI_PORT)
2077 {
2078 uint32_t cbOut = sizeof(int32_t);
2079
2080 if (cbBuffer >= cbOut)
2081 {
2082 *pcbOut = cbOut;
2083 *(int32_t *)pvBuffer = (int32_t)mVRDPBindPort;
2084 }
2085 }
2086 else if (mpEntryPoints && mhServer)
2087 {
2088 mpEntryPoints->VRDEQueryInfo(mhServer, index, pvBuffer, cbBuffer, pcbOut);
2089 }
2090}
2091
2092/* static */ int ConsoleVRDPServer::loadVRDPLibrary(const char *pszLibraryName)
2093{
2094 int rc = VINF_SUCCESS;
2095
2096 if (!mVRDPLibrary)
2097 {
2098 rc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &mVRDPLibrary);
2099
2100 if (RT_SUCCESS(rc))
2101 {
2102 struct SymbolEntry
2103 {
2104 const char *name;
2105 void **ppfn;
2106 };
2107
2108 #define DEFSYMENTRY(a) { #a, (void**)&mpfn##a }
2109
2110 static const struct SymbolEntry symbols[] =
2111 {
2112 DEFSYMENTRY(VRDECreateServer)
2113 };
2114
2115 #undef DEFSYMENTRY
2116
2117 for (unsigned i = 0; i < RT_ELEMENTS(symbols); i++)
2118 {
2119 rc = RTLdrGetSymbol(mVRDPLibrary, symbols[i].name, symbols[i].ppfn);
2120
2121 if (RT_FAILURE(rc))
2122 {
2123 LogRel(("VRDE: Error resolving symbol '%s', rc %Rrc.\n", symbols[i].name, rc));
2124 break;
2125 }
2126 }
2127 }
2128 else
2129 {
2130 if (rc != VERR_FILE_NOT_FOUND)
2131 {
2132 LogRel(("VRDE: Error loading the library '%s' rc = %Rrc.\n", pszLibraryName, rc));
2133 }
2134
2135 mVRDPLibrary = NULL;
2136 }
2137 }
2138
2139 if (RT_FAILURE(rc))
2140 {
2141 if (mVRDPLibrary)
2142 {
2143 RTLdrClose(mVRDPLibrary);
2144 mVRDPLibrary = NULL;
2145 }
2146 }
2147
2148 return rc;
2149}
2150
2151/*
2152 * IVRDEServerInfo implementation.
2153 */
2154// constructor / destructor
2155/////////////////////////////////////////////////////////////////////////////
2156
2157VRDEServerInfo::VRDEServerInfo()
2158 : mParent(NULL)
2159{
2160}
2161
2162VRDEServerInfo::~VRDEServerInfo()
2163{
2164}
2165
2166
2167HRESULT VRDEServerInfo::FinalConstruct()
2168{
2169 return S_OK;
2170}
2171
2172void VRDEServerInfo::FinalRelease()
2173{
2174 uninit();
2175}
2176
2177// public methods only for internal purposes
2178/////////////////////////////////////////////////////////////////////////////
2179
2180/**
2181 * Initializes the guest object.
2182 */
2183HRESULT VRDEServerInfo::init(Console *aParent)
2184{
2185 LogFlowThisFunc(("aParent=%p\n", aParent));
2186
2187 ComAssertRet(aParent, E_INVALIDARG);
2188
2189 /* Enclose the state transition NotReady->InInit->Ready */
2190 AutoInitSpan autoInitSpan(this);
2191 AssertReturn(autoInitSpan.isOk(), E_FAIL);
2192
2193 unconst(mParent) = aParent;
2194
2195 /* Confirm a successful initialization */
2196 autoInitSpan.setSucceeded();
2197
2198 return S_OK;
2199}
2200
2201/**
2202 * Uninitializes the instance and sets the ready flag to FALSE.
2203 * Called either from FinalRelease() or by the parent when it gets destroyed.
2204 */
2205void VRDEServerInfo::uninit()
2206{
2207 LogFlowThisFunc(("\n"));
2208
2209 /* Enclose the state transition Ready->InUninit->NotReady */
2210 AutoUninitSpan autoUninitSpan(this);
2211 if (autoUninitSpan.uninitDone())
2212 return;
2213
2214 unconst(mParent) = NULL;
2215}
2216
2217// IVRDEServerInfo properties
2218/////////////////////////////////////////////////////////////////////////////
2219
2220#define IMPL_GETTER_BOOL(_aType, _aName, _aIndex) \
2221 STDMETHODIMP VRDEServerInfo::COMGETTER(_aName)(_aType *a##_aName) \
2222 { \
2223 if (!a##_aName) \
2224 return E_POINTER; \
2225 \
2226 AutoCaller autoCaller(this); \
2227 if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2228 \
2229 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
2230 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2231 \
2232 uint32_t value; \
2233 uint32_t cbOut = 0; \
2234 \
2235 mParent->consoleVRDPServer()->QueryInfo \
2236 (_aIndex, &value, sizeof(value), &cbOut); \
2237 \
2238 *a##_aName = cbOut? !!value: FALSE; \
2239 \
2240 return S_OK; \
2241 } \
2242 extern void IMPL_GETTER_BOOL_DUMMY(void)
2243
2244#define IMPL_GETTER_SCALAR(_aType, _aName, _aIndex, _aValueMask) \
2245 STDMETHODIMP VRDEServerInfo::COMGETTER(_aName)(_aType *a##_aName) \
2246 { \
2247 if (!a##_aName) \
2248 return E_POINTER; \
2249 \
2250 AutoCaller autoCaller(this); \
2251 if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2252 \
2253 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
2254 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2255 \
2256 _aType value; \
2257 uint32_t cbOut = 0; \
2258 \
2259 mParent->consoleVRDPServer()->QueryInfo \
2260 (_aIndex, &value, sizeof(value), &cbOut); \
2261 \
2262 if (_aValueMask) value &= (_aValueMask); \
2263 *a##_aName = cbOut? value: 0; \
2264 \
2265 return S_OK; \
2266 } \
2267 extern void IMPL_GETTER_SCALAR_DUMMY(void)
2268
2269#define IMPL_GETTER_BSTR(_aType, _aName, _aIndex) \
2270 STDMETHODIMP VRDEServerInfo::COMGETTER(_aName)(_aType *a##_aName) \
2271 { \
2272 if (!a##_aName) \
2273 return E_POINTER; \
2274 \
2275 AutoCaller autoCaller(this); \
2276 if (FAILED(autoCaller.rc())) return autoCaller.rc(); \
2277 \
2278 /* todo: Not sure if a AutoReadLock would be sufficient. */ \
2279 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); \
2280 \
2281 uint32_t cbOut = 0; \
2282 \
2283 mParent->consoleVRDPServer()->QueryInfo \
2284 (_aIndex, NULL, 0, &cbOut); \
2285 \
2286 if (cbOut == 0) \
2287 { \
2288 Bstr str(""); \
2289 str.cloneTo(a##_aName); \
2290 return S_OK; \
2291 } \
2292 \
2293 char *pchBuffer = (char *)RTMemTmpAlloc(cbOut); \
2294 \
2295 if (!pchBuffer) \
2296 { \
2297 Log(("VRDEServerInfo::" \
2298 #_aName \
2299 ": Failed to allocate memory %d bytes\n", cbOut)); \
2300 return E_OUTOFMEMORY; \
2301 } \
2302 \
2303 mParent->consoleVRDPServer()->QueryInfo \
2304 (_aIndex, pchBuffer, cbOut, &cbOut); \
2305 \
2306 Bstr str(pchBuffer); \
2307 \
2308 str.cloneTo(a##_aName); \
2309 \
2310 RTMemTmpFree(pchBuffer); \
2311 \
2312 return S_OK; \
2313 } \
2314 extern void IMPL_GETTER_BSTR_DUMMY(void)
2315
2316IMPL_GETTER_BOOL (BOOL, Active, VRDE_QI_ACTIVE);
2317IMPL_GETTER_SCALAR (LONG, Port, VRDE_QI_PORT, 0);
2318IMPL_GETTER_SCALAR (ULONG, NumberOfClients, VRDE_QI_NUMBER_OF_CLIENTS, 0);
2319IMPL_GETTER_SCALAR (LONG64, BeginTime, VRDE_QI_BEGIN_TIME, 0);
2320IMPL_GETTER_SCALAR (LONG64, EndTime, VRDE_QI_END_TIME, 0);
2321IMPL_GETTER_SCALAR (LONG64, BytesSent, VRDE_QI_BYTES_SENT, INT64_MAX);
2322IMPL_GETTER_SCALAR (LONG64, BytesSentTotal, VRDE_QI_BYTES_SENT_TOTAL, INT64_MAX);
2323IMPL_GETTER_SCALAR (LONG64, BytesReceived, VRDE_QI_BYTES_RECEIVED, INT64_MAX);
2324IMPL_GETTER_SCALAR (LONG64, BytesReceivedTotal, VRDE_QI_BYTES_RECEIVED_TOTAL, INT64_MAX);
2325IMPL_GETTER_BSTR (BSTR, User, VRDE_QI_USER);
2326IMPL_GETTER_BSTR (BSTR, Domain, VRDE_QI_DOMAIN);
2327IMPL_GETTER_BSTR (BSTR, ClientName, VRDE_QI_CLIENT_NAME);
2328IMPL_GETTER_BSTR (BSTR, ClientIP, VRDE_QI_CLIENT_IP);
2329IMPL_GETTER_SCALAR (ULONG, ClientVersion, VRDE_QI_CLIENT_VERSION, 0);
2330IMPL_GETTER_SCALAR (ULONG, EncryptionStyle, VRDE_QI_ENCRYPTION_STYLE, 0);
2331
2332#undef IMPL_GETTER_BSTR
2333#undef IMPL_GETTER_SCALAR
2334#undef IMPL_GETTER_BOOL
2335/* 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