VirtualBox

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

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

Clipboard RDP channel

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