VirtualBox

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

Last change on this file since 2522 was 2522, checked in by vboxsync, 18 years ago

VRDP multiconnection clipboard. The VRDP server always works in multiconnection mode.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.3 KB
Line 
1/** @file
2 *
3 * VBox Console VRDP Helper class
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22#include "ConsoleVRDPServer.h"
23#include "ConsoleImpl.h"
24#include "DisplayImpl.h"
25
26#include "Logging.h"
27
28#include <iprt/asm.h>
29#include <iprt/ldr.h>
30
31#include <VBox/err.h>
32
33
34// ConsoleVRDPServer
35////////////////////////////////////////////////////////////////////////////////
36
37#ifdef VBOX_VRDP
38RTLDRMOD ConsoleVRDPServer::mVRDPLibrary;
39int (VBOXCALL *ConsoleVRDPServer::mpfnVRDPStartServer) (IConsole *pConsole, IVRDPServer *pVRDPServer, HVRDPSERVER *phServer);
40int (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSetFramebuffer) (HVRDPSERVER hServer, IFramebuffer *pFramebuffer, uint32_t fFlags);
41void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSetCallback) (HVRDPSERVER hServer, VRDPSERVERCALLBACK *pcallback, void *pvUser);
42void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPShutdownServer) (HVRDPSERVER hServer);
43void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendUpdateBitmap)(HVRDPSERVER hServer, unsigned x, unsigned y, unsigned w, unsigned h);
44void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendResize) (HVRDPSERVER hServer);
45void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendAudioSamples)(HVRDPSERVER hserver, void *pvSamples, uint32_t cSamples, VRDPAUDIOFORMAT format);
46void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendAudioVolume) (HVRDPSERVER hserver, uint16_t left, uint16_t right);
47#ifdef VRDP_MC
48void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendUSBRequest) (HVRDPSERVER hserver, uint32_t u32ClientId, void *pvParms, uint32_t cbParms);
49#else
50void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendUSBRequest) (HVRDPSERVER hserver, void *pvParms, uint32_t cbParms);
51#endif /* VRDP_MC */
52void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendUpdate) (HVRDPSERVER hServer, void *pvUpdate, uint32_t cbUpdate);
53void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPQueryInfo) (HVRDPSERVER hserver, uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut);
54void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPClipboard) (HVRDPSERVER hserver, uint32_t u32Function, uint32_t u32Format, const void *pvData, uint32_t cbData, uint32_t *pcbActualRead);
55#endif /* VBOX_VRDP */
56
57ConsoleVRDPServer::ConsoleVRDPServer (Console *console)
58{
59 mConsole = console;
60
61#ifdef VRDP_MC
62 int rc = RTCritSectInit (&mCritSect);
63 AssertRC (rc);
64
65 mcClipboardRefs = 0;
66 mpfnClipboardCallback = NULL;
67
68#ifdef VBOX_WITH_USB
69 mUSBBackends.pHead = NULL;
70 mUSBBackends.pTail = NULL;
71
72 mUSBBackends.thread = NIL_RTTHREAD;
73 mUSBBackends.fThreadRunning = false;
74 mUSBBackends.event = 0;
75#endif
76#else
77#ifdef VBOX_WITH_USB
78 mRemoteUSBBackend = NULL;
79#endif
80#endif /* VRDP_MC */
81
82#ifdef VBOX_VRDP
83 mhServer = 0;
84#endif
85
86 mAuthLibrary = 0;
87}
88
89ConsoleVRDPServer::~ConsoleVRDPServer ()
90{
91#ifdef VRDP_MC
92 Stop ();
93
94 if (RTCritSectIsInitialized (&mCritSect))
95 {
96 RTCritSectDelete (&mCritSect);
97 memset (&mCritSect, 0, sizeof (mCritSect));
98 }
99#else
100#ifdef VBOX_VRDP
101 Stop ();
102 /* No unloading of anything because we might still have live object around. */
103#endif
104#endif /* VRDP_MC */
105}
106
107int ConsoleVRDPServer::Launch (void)
108{
109 LogFlowMember(("ConsoleVRDPServer::Launch\n"));
110#ifdef VBOX_VRDP
111 int rc = VINF_SUCCESS;
112 IVRDPServer *vrdpserver = mConsole->getVRDPServer ();
113 Assert(vrdpserver);
114 BOOL vrdpEnabled = FALSE;
115
116 HRESULT rc2 = vrdpserver->COMGETTER(Enabled) (&vrdpEnabled);
117 AssertComRC(rc2);
118
119 if (SUCCEEDED (rc2)
120 && vrdpEnabled
121 && loadVRDPLibrary ())
122 {
123 rc = mpfnVRDPStartServer(mConsole, vrdpserver, &mhServer);
124
125 if (VBOX_SUCCESS(rc))
126 {
127 LogFlow(("VRDP server created: %p, will set mFramebuffer\n", mhServer));
128
129 IFramebuffer *framebuffer = mConsole->getDisplay()->getFramebuffer();
130
131 mpfnVRDPSetFramebuffer (mhServer, framebuffer,
132 framebuffer? VRDP_EXTERNAL_FRAMEBUFFER: VRDP_INTERNAL_FRAMEBUFFER);
133
134 LogFlow(("Framebuffer %p set for the VRDP server\n", framebuffer));
135
136#ifdef VBOX_WITH_USB
137#ifdef VRDP_MC
138 remoteUSBThreadStart ();
139#endif /* VRDP_MC */
140#endif /* VBOX_WITH_USB */
141 }
142 else
143 AssertMsgFailed(("Could not start VRDP server: rc = %Vrc\n", rc));
144 }
145#else
146 int rc = VERR_NOT_SUPPORTED;
147#endif
148 return rc;
149}
150
151void ConsoleVRDPServer::SetCallback (void)
152{
153#ifdef VBOX_VRDP
154 /* This is called after VM is created and allows the server to accept client connection. */
155 if (mhServer && mpfnVRDPSetCallback)
156 {
157 mpfnVRDPSetCallback (mhServer, mConsole->getVrdpServerCallback (), mConsole);
158 }
159#endif
160}
161
162void ConsoleVRDPServer::Stop (void)
163{
164 Assert(VALID_PTR(this)); /** @todo r=bird: there are(/was) some odd cases where this buster was invalid on
165 * linux. Just remove this when it's 100% sure that problem has been fixed. */
166#ifdef VBOX_VRDP
167 if (mhServer)
168 {
169 HVRDPSERVER hServer = mhServer;
170
171 /* Reset the handle to avoid further calls to the server. */
172 mhServer = 0;
173
174 mpfnVRDPShutdownServer (hServer);
175 }
176#endif
177
178#ifdef VBOX_WITH_USB
179#ifdef VRDP_MC
180 remoteUSBThreadStop ();
181#else
182 /* Delete the USB backend object if it was not deleted properly. */
183 if (mRemoteUSBBackend)
184 {
185 Log(("ConsoleVRDPServer::Stop: deleting USB backend\n"));
186
187 mRemoteUSBBackend->ReleaseUSB ();
188 delete mRemoteUSBBackend;
189 mRemoteUSBBackend = NULL;
190 }
191#endif /* VRDP_MC */
192#endif /* VBOX_WITH_USB */
193
194 mpfnAuthEntry = NULL;
195
196 if (mAuthLibrary)
197 {
198 RTLdrClose(mAuthLibrary);
199 mAuthLibrary = 0;
200 }
201}
202
203#ifdef VRDP_MC
204/* Worker thread for Remote USB. The thread polls the clients for
205 * the list of attached USB devices.
206 * The thread is also responsible for attaching/detaching devices
207 * to/from the VM.
208 *
209 * It is expected that attaching/detaching is not a frequent operation.
210 *
211 * The thread is always running when the VRDP server is active.
212 *
213 * The thread scans backends and requests the device list every 2 seconds.
214 *
215 * When device list is available, the thread calls the Console to process it.
216 *
217 */
218#define VRDP_DEVICE_LIST_PERIOD_MS (2000)
219
220#ifdef VBOX_WITH_USB
221static DECLCALLBACK(int) threadRemoteUSB (RTTHREAD self, void *pvUser)
222{
223 ConsoleVRDPServer *pOwner = (ConsoleVRDPServer *)pvUser;
224
225 LogFlow(("Console::threadRemoteUSB: start. owner = %p.\n", pOwner));
226
227 pOwner->notifyRemoteUSBThreadRunning (self);
228
229 while (pOwner->isRemoteUSBThreadRunning ())
230 {
231 RemoteUSBBackend *pRemoteUSBBackend = NULL;
232
233 while ((pRemoteUSBBackend = pOwner->usbBackendGetNext (pRemoteUSBBackend)) != NULL)
234 {
235 pRemoteUSBBackend->PollRemoteDevices ();
236 }
237
238 pOwner->waitRemoteUSBThreadEvent (VRDP_DEVICE_LIST_PERIOD_MS);
239
240 LogFlow(("Console::threadRemoteUSB: iteration. owner = %p.\n", pOwner));
241 }
242
243 return VINF_SUCCESS;
244}
245
246void ConsoleVRDPServer::notifyRemoteUSBThreadRunning (RTTHREAD thread)
247{
248#ifdef VBOX_WITH_USB
249 mUSBBackends.thread = thread;
250 mUSBBackends.fThreadRunning = true;
251 int rc = RTThreadUserSignal (thread);
252 AssertRC (rc);
253#endif
254}
255
256bool ConsoleVRDPServer::isRemoteUSBThreadRunning (void)
257{
258 return mUSBBackends.fThreadRunning;
259}
260
261void ConsoleVRDPServer::waitRemoteUSBThreadEvent (unsigned cMillies)
262{
263 int rc = RTSemEventWait (mUSBBackends.event, cMillies);
264 Assert (VBOX_SUCCESS(rc) || rc == VERR_TIMEOUT);
265 NOREF(rc);
266}
267
268void ConsoleVRDPServer::remoteUSBThreadStart (void)
269{
270 int rc = RTSemEventCreate (&mUSBBackends.event);
271
272 if (VBOX_FAILURE (rc))
273 {
274 AssertFailed ();
275 mUSBBackends.event = 0;
276 }
277
278 if (VBOX_SUCCESS (rc))
279 {
280 rc = RTThreadCreate (&mUSBBackends.thread, threadRemoteUSB, this, 65536,
281 RTTHREADTYPE_VRDP_IO, RTTHREADFLAGS_WAITABLE, "remote usb");
282 }
283
284 if (VBOX_FAILURE (rc))
285 {
286 LogRel(("Warning: could not start the remote USB thread, rc = %Vrc!!!\n", rc));
287 mUSBBackends.thread = NIL_RTTHREAD;
288 }
289 else
290 {
291 /* Wait until the thread is ready. */
292 rc = RTThreadUserWait (mUSBBackends.thread, 60000);
293 AssertRC (rc);
294 Assert (mUSBBackends.fThreadRunning || VBOX_FAILURE (rc));
295 }
296}
297
298void ConsoleVRDPServer::remoteUSBThreadStop (void)
299{
300 mUSBBackends.fThreadRunning = false;
301
302 if (mUSBBackends.thread != NIL_RTTHREAD)
303 {
304 Assert (mUSBBackends.event != 0);
305
306 RTSemEventSignal (mUSBBackends.event);
307
308 int rc = RTThreadWait (mUSBBackends.thread, 60000, NULL);
309 AssertRC (rc);
310
311 mUSBBackends.thread = NIL_RTTHREAD;
312 }
313
314 if (mUSBBackends.event)
315 {
316 RTSemEventDestroy (mUSBBackends.event);
317 mUSBBackends.event = 0;
318 }
319}
320#endif /* VBOX_WITH_USB */
321#endif /* VRDP_MC */
322
323VRDPAuthResult ConsoleVRDPServer::Authenticate (const Guid &uuid, VRDPAuthGuestJudgement guestJudgement,
324 const char *pszUser, const char *pszPassword, const char *pszDomain)
325{
326 VRDPAUTHUUID rawuuid;
327
328 memcpy (rawuuid, ((Guid &)uuid).ptr (), sizeof (rawuuid));
329
330 LogFlow(("ConsoleVRDPServer::Authenticate: uuid = %Vuuid, guestJudgement = %d, pszUser = %s, pszPassword = %s, pszDomain = %s\n",
331 rawuuid, guestJudgement, pszUser, pszPassword, pszDomain));
332
333 /*
334 * Called only from VRDP input thread. So thread safety is not required.
335 */
336
337 if (!mAuthLibrary)
338 {
339 /* Load the external authentication library. */
340
341 ComPtr<IMachine> machine;
342 mConsole->COMGETTER(Machine)(machine.asOutParam());
343
344 ComPtr<IVirtualBox> virtualBox;
345 machine->COMGETTER(Parent)(virtualBox.asOutParam());
346
347 ComPtr<ISystemProperties> systemProperties;
348 virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
349
350 Bstr authLibrary;
351 systemProperties->COMGETTER(RemoteDisplayAuthLibrary)(authLibrary.asOutParam());
352
353 Utf8Str filename = authLibrary;
354
355 LogRel(("VRDPAUTH: ConsoleVRDPServer::Authenticate: loading external authentication library '%ls'\n", authLibrary.raw()));
356
357 int rc = RTLdrLoad (filename.raw(), &mAuthLibrary);
358 if (VBOX_FAILURE (rc))
359 LogRel(("VRDPAUTH: Failed to load external authentication library. Error code: %Vrc\n", rc));
360
361 if (VBOX_SUCCESS (rc))
362 {
363 /* Get the entry point. */
364 rc = RTLdrGetSymbol(mAuthLibrary, "VRDPAuth", (void**)&mpfnAuthEntry);
365 if (VBOX_FAILURE (rc))
366 LogRel(("VRDPAUTH: Failed to resolve import 'VRDPAuth'. Error code: %Vrc\n", rc));
367 }
368
369 if (VBOX_FAILURE (rc))
370 {
371 mConsole->reportAuthLibraryError (filename.raw(), rc);
372
373 mpfnAuthEntry = NULL;
374
375 if (mAuthLibrary)
376 {
377 RTLdrClose(mAuthLibrary);
378 mAuthLibrary = 0;
379 }
380
381 return VRDPAuthAccessDenied;
382 }
383 }
384
385 Assert (mAuthLibrary && mpfnAuthEntry);
386
387 VRDPAuthResult result = mpfnAuthEntry (&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain);
388
389 switch (result)
390 {
391 case VRDPAuthAccessDenied:
392 LogRel(("VRDPAUTH: external authentication module returned 'access denied'\n"));
393 break;
394 case VRDPAuthAccessGranted:
395 LogRel(("VRDPAUTH: external authentication module returned 'access granted'\n"));
396 break;
397 case VRDPAuthDelegateToGuest:
398 LogRel(("VRDPAUTH: external authentication module returned 'delegate request to guest'\n"));
399 break;
400 default:
401 LogRel(("VRDPAUTH: external authentication module returned incorrect return code %d\n", result));
402 result = VRDPAuthAccessDenied;
403 }
404
405 LogFlow(("ConsoleVRDPServer::Authenticate: result = %d\n", result));
406
407 return result;
408}
409
410
411#ifdef VRDP_MC
412int ConsoleVRDPServer::lockConsoleVRDPServer (void)
413{
414 int rc = RTCritSectEnter (&mCritSect);
415 AssertRC (rc);
416 return rc;
417}
418
419void ConsoleVRDPServer::unlockConsoleVRDPServer (void)
420{
421 RTCritSectLeave (&mCritSect);
422}
423
424DECLCALLBACK(int) ConsoleVRDPServer::ClipboardCallback (void *pvCallback,
425 uint32_t u32ClientId,
426 uint32_t u32Function,
427 uint32_t u32Format,
428 const void *pvData,
429 uint32_t cbData)
430{
431 LogFlowFunc(("pvCallback = %p, u32ClientId = %d, u32Function = %d, u32Format = 0x%08X, pvData = %p, cbData = %d\n",
432 pvCallback, u32ClientId, u32Function, u32Format, pvData, cbData));
433
434 int rc = VINF_SUCCESS;
435
436 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvCallback);
437
438 NOREF(u32ClientId);
439
440 switch (u32Function)
441 {
442 case VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE:
443 {
444 if (pServer->mpfnClipboardCallback)
445 {
446 pServer->mpfnClipboardCallback (VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE,
447 u32Format,
448 (void *)pvData,
449 cbData);
450 }
451 } break;
452
453 case VRDP_CLIPBOARD_FUNCTION_DATA_READ:
454 {
455 if (pServer->mpfnClipboardCallback)
456 {
457 pServer->mpfnClipboardCallback (VBOX_CLIPBOARD_EXT_FN_DATA_READ,
458 u32Format,
459 (void *)pvData,
460 cbData);
461 }
462 } break;
463
464 default:
465 rc = VERR_NOT_SUPPORTED;
466 }
467
468 return rc;
469}
470
471DECLCALLBACK(int) ConsoleVRDPServer::ClipboardServiceExtension (void *pvExtension,
472 uint32_t u32Function,
473 void *pvParms,
474 uint32_t cbParms)
475{
476 LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
477 pvExtension, u32Function, pvParms, cbParms));
478
479 int rc = VINF_SUCCESS;
480
481#ifdef VBOX_VRDP
482 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvExtension);
483
484 VBOXCLIPBOARDEXTPARMS *pParms = (VBOXCLIPBOARDEXTPARMS *)pvParms;
485
486 switch (u32Function)
487 {
488 case VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK:
489 {
490 pServer->mpfnClipboardCallback = (PFNVRDPCLIPBOARDEXTCALLBACK)pParms->pvData;
491 } break;
492
493 case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
494 {
495 /* The guest announces clipboard formats. This must be delivered to all clients. */
496 if (mpfnVRDPClipboard)
497 {
498 mpfnVRDPClipboard (pServer->mhServer,
499 VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE,
500 pParms->u32Format,
501 NULL,
502 0,
503 NULL);
504 }
505 } break;
506
507 case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
508 {
509 /* The clipboard service expects that the pvData buffer will be filled
510 * with clipboard data. The server returns the data from the client that
511 * announced the requested format most recently.
512 */
513 if (mpfnVRDPClipboard)
514 {
515 mpfnVRDPClipboard (pServer->mhServer,
516 VRDP_CLIPBOARD_FUNCTION_DATA_READ,
517 pParms->u32Format,
518 pParms->pvData,
519 pParms->cbData,
520 &pParms->cbData);
521 }
522 } break;
523
524 case VBOX_CLIPBOARD_EXT_FN_DATA_WRITE:
525 {
526 if (mpfnVRDPClipboard)
527 {
528 mpfnVRDPClipboard (pServer->mhServer,
529 VRDP_CLIPBOARD_FUNCTION_DATA_WRITE,
530 pParms->u32Format,
531 pParms->pvData,
532 pParms->cbData,
533 NULL);
534 }
535 } break;
536
537 default:
538 rc = VERR_NOT_SUPPORTED;
539 }
540#endif /* VBOX_VRDP */
541
542 return rc;
543}
544
545void ConsoleVRDPServer::ClipboardCreate (uint32_t u32ClientId, PFNVRDPCLIPBOARDCALLBACK *ppfn, void **ppv)
546{
547 int rc = lockConsoleVRDPServer ();
548
549 if (VBOX_SUCCESS (rc))
550 {
551 if (mcClipboardRefs == 0)
552 {
553 rc = HGCMHostRegisterServiceExtension (&mhClipboard, "VBoxSharedClipboard", ClipboardServiceExtension, this);
554
555 if (VBOX_SUCCESS (rc))
556 {
557 mcClipboardRefs++;
558 }
559 }
560
561 if (VBOX_SUCCESS (rc))
562 {
563 *ppfn = ClipboardCallback;
564 *ppv = this;
565 }
566
567 unlockConsoleVRDPServer ();
568 }
569}
570
571void ConsoleVRDPServer::ClipboardDelete (uint32_t u32ClientId)
572{
573 int rc = lockConsoleVRDPServer ();
574
575 if (VBOX_SUCCESS (rc))
576 {
577 mcClipboardRefs--;
578
579 if (mcClipboardRefs == 0)
580 {
581 HGCMHostUnregisterServiceExtension (mhClipboard);
582 }
583
584 unlockConsoleVRDPServer ();
585 }
586}
587
588/* That is called on INPUT thread of the VRDP server.
589 * The ConsoleVRDPServer keeps a list of created backend instances.
590 */
591void ConsoleVRDPServer::USBBackendCreate (uint32_t u32ClientId, PFNVRDPUSBCALLBACK *ppfn, void **ppv)
592{
593#ifdef VBOX_WITH_USB
594 LogFlow(("ConsoleVRDPServer::USBBackendCreate: u32ClientId = %d\n", u32ClientId));
595
596 /* Create a new instance of the USB backend for the new client. */
597 RemoteUSBBackend *pRemoteUSBBackend = new RemoteUSBBackend (mConsole, this, u32ClientId);
598
599 if (pRemoteUSBBackend)
600 {
601 pRemoteUSBBackend->AddRef (); /* 'Release' called in USBBackendDelete. */
602
603 /* Append the new instance in the list. */
604 int rc = lockConsoleVRDPServer ();
605
606 if (VBOX_SUCCESS (rc))
607 {
608 pRemoteUSBBackend->pNext = mUSBBackends.pHead;
609 if (mUSBBackends.pHead)
610 {
611 mUSBBackends.pHead->pPrev = pRemoteUSBBackend;
612 }
613 else
614 {
615 mUSBBackends.pTail = pRemoteUSBBackend;
616 }
617
618 mUSBBackends.pHead = pRemoteUSBBackend;
619
620 unlockConsoleVRDPServer ();
621
622 pRemoteUSBBackend->QueryVRDPCallbackPointer (ppfn, ppv);
623 }
624
625 if (VBOX_FAILURE (rc))
626 {
627 pRemoteUSBBackend->Release ();
628 }
629 }
630#endif
631}
632
633void ConsoleVRDPServer::USBBackendDelete (uint32_t u32ClientId)
634{
635#ifdef VBOX_WITH_USB
636 LogFlow(("ConsoleVRDPServer::USBBackendDelete: u32ClientId = %d\n", u32ClientId));
637
638 RemoteUSBBackend *pRemoteUSBBackend = NULL;
639
640 /* Find the instance. */
641 int rc = lockConsoleVRDPServer ();
642
643 if (VBOX_SUCCESS (rc))
644 {
645 pRemoteUSBBackend = usbBackendFind (u32ClientId);
646
647 if (pRemoteUSBBackend)
648 {
649 /* Notify that it will be deleted. */
650 pRemoteUSBBackend->NotifyDelete ();
651 }
652
653 unlockConsoleVRDPServer ();
654 }
655
656 if (pRemoteUSBBackend)
657 {
658 /* Here the instance has been excluded from the list and can be dereferenced. */
659 pRemoteUSBBackend->Release ();
660 }
661#endif
662}
663
664void *ConsoleVRDPServer::USBBackendRequestPointer (uint32_t u32ClientId, const Guid *pGuid)
665{
666#ifdef VBOX_WITH_USB
667 RemoteUSBBackend *pRemoteUSBBackend = NULL;
668
669 /* Find the instance. */
670 int rc = lockConsoleVRDPServer ();
671
672 if (VBOX_SUCCESS (rc))
673 {
674 pRemoteUSBBackend = usbBackendFind (u32ClientId);
675
676 if (pRemoteUSBBackend)
677 {
678 /* Inform the backend instance that it is referenced by the Guid. */
679 bool fAdded = pRemoteUSBBackend->addUUID (pGuid);
680
681 if (fAdded)
682 {
683 /* Reference the instance because its pointer is being taken. */
684 pRemoteUSBBackend->AddRef (); /* 'Release' is called in USBBackendReleasePointer. */
685 }
686 else
687 {
688 pRemoteUSBBackend = NULL;
689 }
690 }
691
692 unlockConsoleVRDPServer ();
693 }
694
695 if (pRemoteUSBBackend)
696 {
697 return pRemoteUSBBackend->GetBackendCallbackPointer ();
698 }
699
700#endif
701 return NULL;
702}
703
704void ConsoleVRDPServer::USBBackendReleasePointer (const Guid *pGuid)
705{
706#ifdef VBOX_WITH_USB
707 RemoteUSBBackend *pRemoteUSBBackend = NULL;
708
709 /* Find the instance. */
710 int rc = lockConsoleVRDPServer ();
711
712 if (VBOX_SUCCESS (rc))
713 {
714 pRemoteUSBBackend = usbBackendFindByUUID (pGuid);
715
716 if (pRemoteUSBBackend)
717 {
718 pRemoteUSBBackend->removeUUID (pGuid);
719 }
720
721 unlockConsoleVRDPServer ();
722
723 if (pRemoteUSBBackend)
724 {
725 pRemoteUSBBackend->Release ();
726 }
727 }
728#endif
729}
730
731RemoteUSBBackend *ConsoleVRDPServer::usbBackendGetNext (RemoteUSBBackend *pRemoteUSBBackend)
732{
733 LogFlow(("ConsoleVRDPServer::usbBackendGetNext: pBackend = %p\n", pRemoteUSBBackend));
734
735 RemoteUSBBackend *pNextRemoteUSBBackend = NULL;
736#ifdef VBOX_WITH_USB
737
738 int rc = lockConsoleVRDPServer ();
739
740 if (VBOX_SUCCESS (rc))
741 {
742 if (pRemoteUSBBackend == NULL)
743 {
744 /* The first backend in the list is requested. */
745 pNextRemoteUSBBackend = mUSBBackends.pHead;
746 }
747 else
748 {
749 /* Get pointer to the next backend. */
750 pNextRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
751 }
752
753 if (pNextRemoteUSBBackend)
754 {
755 pNextRemoteUSBBackend->AddRef ();
756 }
757
758 unlockConsoleVRDPServer ();
759
760 if (pRemoteUSBBackend)
761 {
762 pRemoteUSBBackend->Release ();
763 }
764 }
765#endif
766
767 return pNextRemoteUSBBackend;
768}
769
770#ifdef VBOX_WITH_USB
771/* Internal method. Called under the ConsoleVRDPServerLock. */
772RemoteUSBBackend *ConsoleVRDPServer::usbBackendFind (uint32_t u32ClientId)
773{
774 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
775
776 while (pRemoteUSBBackend)
777 {
778 if (pRemoteUSBBackend->ClientId () == u32ClientId)
779 {
780 break;
781 }
782
783 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
784 }
785
786 return pRemoteUSBBackend;
787}
788
789/* Internal method. Called under the ConsoleVRDPServerLock. */
790RemoteUSBBackend *ConsoleVRDPServer::usbBackendFindByUUID (const Guid *pGuid)
791{
792 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
793
794 while (pRemoteUSBBackend)
795 {
796 if (pRemoteUSBBackend->findUUID (pGuid))
797 {
798 break;
799 }
800
801 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
802 }
803
804 return pRemoteUSBBackend;
805}
806#endif
807
808/* Internal method. Called by the backend destructor. */
809void ConsoleVRDPServer::usbBackendRemoveFromList (RemoteUSBBackend *pRemoteUSBBackend)
810{
811#ifdef VBOX_WITH_USB
812 int rc = lockConsoleVRDPServer ();
813 AssertRC (rc);
814
815 /* Exclude the found instance from the list. */
816 if (pRemoteUSBBackend->pNext)
817 {
818 pRemoteUSBBackend->pNext->pPrev = pRemoteUSBBackend->pPrev;
819 }
820 else
821 {
822 mUSBBackends.pTail = (RemoteUSBBackend *)pRemoteUSBBackend->pPrev;
823 }
824
825 if (pRemoteUSBBackend->pPrev)
826 {
827 pRemoteUSBBackend->pPrev->pNext = pRemoteUSBBackend->pNext;
828 }
829 else
830 {
831 mUSBBackends.pHead = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
832 }
833
834 pRemoteUSBBackend->pNext = pRemoteUSBBackend->pPrev = NULL;
835
836 unlockConsoleVRDPServer ();
837#endif
838}
839#else // VRDP_MC
840void ConsoleVRDPServer::CreateUSBBackend (PFNVRDPUSBCALLBACK *ppfn, void **ppv)
841{
842#ifdef VBOX_WITH_USB
843 Assert(mRemoteUSBBackend == NULL);
844
845 mRemoteUSBBackend = new RemoteUSBBackend (mConsole, this);
846
847 if (mRemoteUSBBackend)
848 {
849 int rc = mRemoteUSBBackend->InterceptUSB (ppfn, ppv);
850
851 if (VBOX_FAILURE (rc))
852 {
853 delete mRemoteUSBBackend;
854 mRemoteUSBBackend = NULL;
855 }
856 }
857#endif /* VBOX_WITH_USB */
858}
859
860void ConsoleVRDPServer::DeleteUSBBackend (void)
861{
862#ifdef VBOX_WITH_USB
863 LogFlow(("ConsoleVRDPServer::DeleteUSBBackend: %p\n", mRemoteUSBBackend));
864
865 if (mRemoteUSBBackend)
866 {
867 mRemoteUSBBackend->ReleaseUSB ();
868 delete mRemoteUSBBackend;
869 mRemoteUSBBackend = NULL;
870 }
871#endif /* VBOX_WITH_USB */
872}
873
874void *ConsoleVRDPServer::GetUSBBackendPointer (void)
875{
876#ifdef VBOX_WITH_USB
877 Assert (mRemoteUSBBackend); /* Must be called only if the object exists. */
878 return mRemoteUSBBackend->GetRemoteBackendCallback ();
879#else
880 return NULL;
881#endif
882}
883#endif /* VRDP_MC */
884
885
886
887void ConsoleVRDPServer::SendUpdate (void *pvUpdate, uint32_t cbUpdate) const
888{
889#ifdef VBOX_VRDP
890 if (mpfnVRDPSendUpdate)
891 mpfnVRDPSendUpdate (mhServer, pvUpdate, cbUpdate);
892#endif
893}
894
895void ConsoleVRDPServer::SendResize (void) const
896{
897#ifdef VBOX_VRDP
898 if (mpfnVRDPSendResize)
899 mpfnVRDPSendResize (mhServer);
900#endif
901}
902
903void ConsoleVRDPServer::SendUpdateBitmap (uint32_t x, uint32_t y, uint32_t w, uint32_t h) const
904{
905#ifdef VBOX_VRDP
906 if (mpfnVRDPSendUpdateBitmap)
907 mpfnVRDPSendUpdateBitmap (mhServer, x, y, w, h);
908#endif
909}
910
911void ConsoleVRDPServer::SetFramebuffer (IFramebuffer *framebuffer, uint32_t fFlags) const
912{
913#ifdef VBOX_VRDP
914 if (mpfnVRDPSetFramebuffer)
915 mpfnVRDPSetFramebuffer (mhServer, framebuffer, fFlags);
916#endif
917}
918
919void ConsoleVRDPServer::SendAudioSamples (void *pvSamples, uint32_t cSamples, VRDPAUDIOFORMAT format) const
920{
921#ifdef VBOX_VRDP
922 if (mpfnVRDPSendAudioSamples)
923 mpfnVRDPSendAudioSamples (mhServer, pvSamples, cSamples, format);
924#endif
925}
926
927void ConsoleVRDPServer::SendAudioVolume (uint16_t left, uint16_t right) const
928{
929#ifdef VBOX_VRDP
930 if (mpfnVRDPSendAudioVolume)
931 mpfnVRDPSendAudioVolume (mhServer, left, right);
932#endif
933}
934
935#ifdef VRDP_MC
936void ConsoleVRDPServer::SendUSBRequest (uint32_t u32ClientId, void *pvParms, uint32_t cbParms) const
937{
938#ifdef VBOX_VRDP
939 if (mpfnVRDPSendUSBRequest)
940 mpfnVRDPSendUSBRequest (mhServer, u32ClientId, pvParms, cbParms);
941#endif
942}
943#else
944void ConsoleVRDPServer::SendUSBRequest (void *pvParms, uint32_t cbParms) const
945{
946#ifdef VBOX_VRDP
947 if (mpfnVRDPSendUSBRequest)
948 mpfnVRDPSendUSBRequest (mhServer, pvParms, cbParms);
949#endif
950}
951#endif /* VRDP_MC */
952
953void ConsoleVRDPServer::QueryInfo (uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const
954{
955#ifdef VBOX_VRDP
956 if (mpfnVRDPQueryInfo)
957 mpfnVRDPQueryInfo (mhServer, index, pvBuffer, cbBuffer, pcbOut);
958#endif
959}
960
961#ifdef VBOX_VRDP
962/* note: static function now! */
963bool ConsoleVRDPServer::loadVRDPLibrary (void)
964{
965 int rc = VINF_SUCCESS;
966
967 if (!mVRDPLibrary)
968 {
969 rc = RTLdrLoad("VBoxVRDP", &mVRDPLibrary);
970
971 if (VBOX_SUCCESS(rc))
972 {
973 LogFlow(("VRDPServer::loadLibrary(): successfully loaded VRDP library.\n"));
974
975 struct SymbolEntry
976 {
977 const char *name;
978 void **ppfn;
979 };
980
981 #define DEFSYMENTRY(a) { #a, (void**)&mpfn##a }
982
983 static const struct SymbolEntry symbols[] =
984 {
985 DEFSYMENTRY(VRDPStartServer),
986 DEFSYMENTRY(VRDPSetFramebuffer),
987 DEFSYMENTRY(VRDPSetCallback),
988 DEFSYMENTRY(VRDPShutdownServer),
989 DEFSYMENTRY(VRDPSendUpdate),
990 DEFSYMENTRY(VRDPSendUpdateBitmap),
991 DEFSYMENTRY(VRDPSendResize),
992 DEFSYMENTRY(VRDPSendAudioSamples),
993 DEFSYMENTRY(VRDPSendAudioVolume),
994 DEFSYMENTRY(VRDPSendUSBRequest),
995 DEFSYMENTRY(VRDPQueryInfo),
996 DEFSYMENTRY(VRDPClipboard)
997 };
998
999 #undef DEFSYMENTRY
1000
1001 for (unsigned i = 0; i < ELEMENTS(symbols); i++)
1002 {
1003 rc = RTLdrGetSymbol(mVRDPLibrary, symbols[i].name, symbols[i].ppfn);
1004
1005 AssertMsgRC(rc, ("Error resolving VRDP symbol %s\n", symbols[i].name));
1006
1007 if (VBOX_FAILURE(rc))
1008 {
1009 break;
1010 }
1011 }
1012 }
1013 else
1014 {
1015 LogFlow(("VRDPServer::loadLibrary(): failed to load VRDP library! VRDP not available.\n"));
1016 mVRDPLibrary = NULL;
1017 }
1018 }
1019
1020 // just to be safe
1021 if (VBOX_FAILURE(rc))
1022 {
1023 if (mVRDPLibrary)
1024 {
1025 RTLdrClose (mVRDPLibrary);
1026 mVRDPLibrary = NULL;
1027 }
1028 }
1029
1030 return (mVRDPLibrary != NULL);
1031}
1032#endif /* VBOX_VRDP */
1033
1034/*
1035 * IRemoteDisplayInfo implementation.
1036 */
1037// constructor / destructor
1038/////////////////////////////////////////////////////////////////////////////
1039
1040HRESULT RemoteDisplayInfo::FinalConstruct()
1041{
1042 return S_OK;
1043}
1044
1045void RemoteDisplayInfo::FinalRelease()
1046{
1047 if (isReady())
1048 uninit ();
1049}
1050
1051// public methods only for internal purposes
1052/////////////////////////////////////////////////////////////////////////////
1053
1054/**
1055 * Initializes the guest object.
1056 */
1057HRESULT RemoteDisplayInfo::init (Console *aParent)
1058{
1059 LogFlowMember (("RemoteDisplayInfo::init (%p)\n", aParent));
1060
1061 ComAssertRet (aParent, E_INVALIDARG);
1062
1063 AutoLock alock (this);
1064 ComAssertRet (!isReady(), E_UNEXPECTED);
1065
1066 mParent = aParent;
1067
1068 setReady (true);
1069 return S_OK;
1070}
1071
1072/**
1073 * Uninitializes the instance and sets the ready flag to FALSE.
1074 * Called either from FinalRelease() or by the parent when it gets destroyed.
1075 */
1076void RemoteDisplayInfo::uninit()
1077{
1078 LogFlowMember (("RemoteDisplayInfo::uninit()\n"));
1079
1080 AutoLock alock (this);
1081 AssertReturn (isReady(), (void) 0);
1082
1083 mParent.setNull();
1084
1085 setReady (false);
1086}
1087
1088// IRemoteDisplayInfo properties
1089/////////////////////////////////////////////////////////////////////////////
1090
1091#define IMPL_GETTER_BOOL(_aType, _aName, _aIndex) \
1092 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
1093 { \
1094 if (!a##_aName) \
1095 return E_POINTER; \
1096 \
1097 AutoLock alock (this); \
1098 CHECK_READY(); \
1099 \
1100 uint32_t value; \
1101 uint32_t cbOut = 0; \
1102 \
1103 mParent->consoleVRDPServer ()->QueryInfo \
1104 (_aIndex, &value, sizeof (value), &cbOut); \
1105 \
1106 *a##_aName = cbOut? !!value: FALSE; \
1107 \
1108 return S_OK; \
1109 }
1110
1111#define IMPL_GETTER_SCALAR(_aType, _aName, _aIndex) \
1112 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
1113 { \
1114 if (!a##_aName) \
1115 return E_POINTER; \
1116 \
1117 AutoLock alock (this); \
1118 CHECK_READY(); \
1119 \
1120 _aType value; \
1121 uint32_t cbOut = 0; \
1122 \
1123 mParent->consoleVRDPServer ()->QueryInfo \
1124 (_aIndex, &value, sizeof (value), &cbOut); \
1125 \
1126 *a##_aName = cbOut? value: 0; \
1127 \
1128 return S_OK; \
1129 }
1130
1131#define IMPL_GETTER_BSTR(_aType, _aName, _aIndex) \
1132 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
1133 { \
1134 if (!a##_aName) \
1135 return E_POINTER; \
1136 \
1137 AutoLock alock (this); \
1138 CHECK_READY(); \
1139 \
1140 uint32_t cbOut = 0; \
1141 \
1142 mParent->consoleVRDPServer ()->QueryInfo \
1143 (_aIndex, NULL, 0, &cbOut); \
1144 \
1145 if (cbOut == 0) \
1146 { \
1147 Bstr str(""); \
1148 str.cloneTo (a##_aName); \
1149 return S_OK; \
1150 } \
1151 \
1152 char *pchBuffer = (char *)RTMemTmpAlloc (cbOut); \
1153 \
1154 if (!pchBuffer) \
1155 { \
1156 Log(("RemoteDisplayInfo::" \
1157 #_aName \
1158 ": Failed to allocate memory %d bytes\n", cbOut)); \
1159 return E_OUTOFMEMORY; \
1160 } \
1161 \
1162 mParent->consoleVRDPServer ()->QueryInfo \
1163 (_aIndex, pchBuffer, cbOut, &cbOut); \
1164 \
1165 Bstr str(pchBuffer); \
1166 \
1167 str.cloneTo (a##_aName); \
1168 \
1169 RTMemTmpFree (pchBuffer); \
1170 \
1171 return S_OK; \
1172 }
1173
1174IMPL_GETTER_BOOL (BOOL, Active, VRDP_QI_ACTIVE);
1175IMPL_GETTER_SCALAR (ULONG, NumberOfClients, VRDP_QI_NUMBER_OF_CLIENTS);
1176IMPL_GETTER_SCALAR (LONG64, BeginTime, VRDP_QI_BEGIN_TIME);
1177IMPL_GETTER_SCALAR (LONG64, EndTime, VRDP_QI_END_TIME);
1178IMPL_GETTER_SCALAR (ULONG64, BytesSent, VRDP_QI_BYTES_SENT);
1179IMPL_GETTER_SCALAR (ULONG64, BytesSentTotal, VRDP_QI_BYTES_SENT_TOTAL);
1180IMPL_GETTER_SCALAR (ULONG64, BytesReceived, VRDP_QI_BYTES_RECEIVED);
1181IMPL_GETTER_SCALAR (ULONG64, BytesReceivedTotal, VRDP_QI_BYTES_RECEIVED_TOTAL);
1182IMPL_GETTER_BSTR (BSTR, User, VRDP_QI_USER);
1183IMPL_GETTER_BSTR (BSTR, Domain, VRDP_QI_DOMAIN);
1184IMPL_GETTER_BSTR (BSTR, ClientName, VRDP_QI_CLIENT_NAME);
1185IMPL_GETTER_BSTR (BSTR, ClientIP, VRDP_QI_CLIENT_IP);
1186IMPL_GETTER_SCALAR (ULONG, ClientVersion, VRDP_QI_CLIENT_VERSION);
1187IMPL_GETTER_SCALAR (ULONG, EncryptionStyle, VRDP_QI_ENCRYPTION_STYLE);
1188
1189#undef IMPL_GETTER_BSTR
1190#undef IMPL_GETTER_SCALAR
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