VirtualBox

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

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

VBOX_VRDP ifdefs for OSE

  • 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#ifdef VBOX_VRDP
528 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvExtension);
529
530 VBOXCLIPBOARDEXTPARMS *pParms = (VBOXCLIPBOARDEXTPARMS *)pvParms;
531
532 switch (u32Function)
533 {
534 case VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK:
535 {
536 pServer->mpfnClipboardCallback = (PFNVRDPCLIPBOARDEXTCALLBACK)pParms->pvData;
537 } break;
538
539 case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
540 {
541 if (mpfnVRDPClipboard)
542 {
543 mpfnVRDPClipboard (pServer->mhServer,
544 VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE,
545 pParms->u32Format,
546 NULL,
547 0);
548 }
549 } break;
550
551 case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
552 {
553 if (mpfnVRDPClipboard)
554 {
555 if (ASMAtomicCmpXchgU32(&pServer->mfu32ClipboardWaitData, VBOX_CLIPBOARD_DATA_WAITING, VBOX_CLIPBOARD_NO_DATA))
556 {
557 LogFlowFunc(("Wait for clipboard data\n"));
558 RTSemEventMultiReset(pServer->mEventClipboardData);
559
560 mpfnVRDPClipboard (pServer->mhServer,
561 VRDP_CLIPBOARD_FUNCTION_DATA_READ,
562 pParms->u32Format,
563 NULL,
564 0);
565
566 /* Wait for the client. 10 seconds should be enough. */
567 int rc = RTSemEventMultiWait(pServer->mEventClipboardData, 10*1000);
568 LogFlowFunc (("Wait completed rc = %d.\n", rc)); NOREF(rc);
569 }
570
571 if (pServer->mfu32ClipboardWaitData == VBOX_CLIPBOARD_DATA_ARRIVED)
572 {
573 LogFlowFunc(("Return clipboard data: pParms->cbData = %d, mcbClipboardData = %d\n", pParms->cbData, pServer->mcbClipboardData));
574 if (pParms->cbData >= pServer->mcbClipboardData)
575 {
576 if (pServer->mcbClipboardData)
577 {
578 memcpy (pParms->pvData, pServer->mpvClipboardData, pServer->mcbClipboardData);
579 }
580
581 RTMemFree (pServer->mpvClipboardData);
582 pServer->mpvClipboardData = NULL;
583
584 pServer->mfu32ClipboardWaitData = VBOX_CLIPBOARD_NO_DATA;
585 }
586
587 pParms->cbData = pServer->mcbClipboardData;
588 }
589 else
590 {
591 pParms->pvData = NULL;
592 pParms->cbData = 0;
593 }
594 }
595 } break;
596
597 case VBOX_CLIPBOARD_EXT_FN_DATA_WRITE:
598 {
599 if (mpfnVRDPClipboard)
600 {
601 mpfnVRDPClipboard (pServer->mhServer,
602 VRDP_CLIPBOARD_FUNCTION_DATA_WRITE,
603 pParms->u32Format,
604 pParms->pvData,
605 pParms->cbData);
606 }
607 } break;
608
609 default:
610 rc = VERR_NOT_SUPPORTED;
611 }
612#endif /* VBOX_VRDP */
613
614 return rc;
615}
616
617void ConsoleVRDPServer::ClipboardCreate (uint32_t u32ClientId, PFNVRDPCLIPBOARDCALLBACK *ppfn, void **ppv)
618{
619 int rc = lockConsoleVRDPServer ();
620
621 if (VBOX_SUCCESS (rc))
622 {
623 if (mcClipboardRefs == 0)
624 {
625 rc = HGCMHostRegisterServiceExtension (&mhClipboard, "VBoxSharedClipboard", ClipboardServiceExtension, this);
626
627 if (VBOX_SUCCESS (rc))
628 {
629 mcClipboardRefs++;
630 }
631 }
632
633 if (VBOX_SUCCESS (rc))
634 {
635 *ppfn = ClipboardCallback;
636 *ppv = this;
637 }
638
639 unlockConsoleVRDPServer ();
640 }
641}
642
643void ConsoleVRDPServer::ClipboardDelete (uint32_t u32ClientId)
644{
645 int rc = lockConsoleVRDPServer ();
646
647 if (VBOX_SUCCESS (rc))
648 {
649 mcClipboardRefs--;
650
651 if (mcClipboardRefs == 0)
652 {
653 HGCMHostUnregisterServiceExtension (mhClipboard);
654 }
655
656 unlockConsoleVRDPServer ();
657 }
658}
659
660/* That is called on INPUT thread of the VRDP server.
661 * The ConsoleVRDPServer keeps a list of created backend instances.
662 */
663void ConsoleVRDPServer::USBBackendCreate (uint32_t u32ClientId, PFNVRDPUSBCALLBACK *ppfn, void **ppv)
664{
665#ifdef VBOX_WITH_USB
666 LogFlow(("ConsoleVRDPServer::USBBackendCreate: u32ClientId = %d\n", u32ClientId));
667
668 /* Create a new instance of the USB backend for the new client. */
669 RemoteUSBBackend *pRemoteUSBBackend = new RemoteUSBBackend (mConsole, this, u32ClientId);
670
671 if (pRemoteUSBBackend)
672 {
673 pRemoteUSBBackend->AddRef (); /* 'Release' called in USBBackendDelete. */
674
675 /* Append the new instance in the list. */
676 int rc = lockConsoleVRDPServer ();
677
678 if (VBOX_SUCCESS (rc))
679 {
680 pRemoteUSBBackend->pNext = mUSBBackends.pHead;
681 if (mUSBBackends.pHead)
682 {
683 mUSBBackends.pHead->pPrev = pRemoteUSBBackend;
684 }
685 else
686 {
687 mUSBBackends.pTail = pRemoteUSBBackend;
688 }
689
690 mUSBBackends.pHead = pRemoteUSBBackend;
691
692 unlockConsoleVRDPServer ();
693
694 pRemoteUSBBackend->QueryVRDPCallbackPointer (ppfn, ppv);
695 }
696
697 if (VBOX_FAILURE (rc))
698 {
699 pRemoteUSBBackend->Release ();
700 }
701 }
702#endif
703}
704
705void ConsoleVRDPServer::USBBackendDelete (uint32_t u32ClientId)
706{
707#ifdef VBOX_WITH_USB
708 LogFlow(("ConsoleVRDPServer::USBBackendDelete: u32ClientId = %d\n", u32ClientId));
709
710 RemoteUSBBackend *pRemoteUSBBackend = NULL;
711
712 /* Find the instance. */
713 int rc = lockConsoleVRDPServer ();
714
715 if (VBOX_SUCCESS (rc))
716 {
717 pRemoteUSBBackend = usbBackendFind (u32ClientId);
718
719 if (pRemoteUSBBackend)
720 {
721 /* Notify that it will be deleted. */
722 pRemoteUSBBackend->NotifyDelete ();
723 }
724
725 unlockConsoleVRDPServer ();
726 }
727
728 if (pRemoteUSBBackend)
729 {
730 /* Here the instance has been excluded from the list and can be dereferenced. */
731 pRemoteUSBBackend->Release ();
732 }
733#endif
734}
735
736void *ConsoleVRDPServer::USBBackendRequestPointer (uint32_t u32ClientId, const Guid *pGuid)
737{
738#ifdef VBOX_WITH_USB
739 RemoteUSBBackend *pRemoteUSBBackend = NULL;
740
741 /* Find the instance. */
742 int rc = lockConsoleVRDPServer ();
743
744 if (VBOX_SUCCESS (rc))
745 {
746 pRemoteUSBBackend = usbBackendFind (u32ClientId);
747
748 if (pRemoteUSBBackend)
749 {
750 /* Inform the backend instance that it is referenced by the Guid. */
751 bool fAdded = pRemoteUSBBackend->addUUID (pGuid);
752
753 if (fAdded)
754 {
755 /* Reference the instance because its pointer is being taken. */
756 pRemoteUSBBackend->AddRef (); /* 'Release' is called in USBBackendReleasePointer. */
757 }
758 else
759 {
760 pRemoteUSBBackend = NULL;
761 }
762 }
763
764 unlockConsoleVRDPServer ();
765 }
766
767 if (pRemoteUSBBackend)
768 {
769 return pRemoteUSBBackend->GetBackendCallbackPointer ();
770 }
771
772#endif
773 return NULL;
774}
775
776void ConsoleVRDPServer::USBBackendReleasePointer (const Guid *pGuid)
777{
778#ifdef VBOX_WITH_USB
779 RemoteUSBBackend *pRemoteUSBBackend = NULL;
780
781 /* Find the instance. */
782 int rc = lockConsoleVRDPServer ();
783
784 if (VBOX_SUCCESS (rc))
785 {
786 pRemoteUSBBackend = usbBackendFindByUUID (pGuid);
787
788 if (pRemoteUSBBackend)
789 {
790 pRemoteUSBBackend->removeUUID (pGuid);
791 }
792
793 unlockConsoleVRDPServer ();
794
795 if (pRemoteUSBBackend)
796 {
797 pRemoteUSBBackend->Release ();
798 }
799 }
800#endif
801}
802
803RemoteUSBBackend *ConsoleVRDPServer::usbBackendGetNext (RemoteUSBBackend *pRemoteUSBBackend)
804{
805 LogFlow(("ConsoleVRDPServer::usbBackendGetNext: pBackend = %p\n", pRemoteUSBBackend));
806
807 RemoteUSBBackend *pNextRemoteUSBBackend = NULL;
808#ifdef VBOX_WITH_USB
809
810 int rc = lockConsoleVRDPServer ();
811
812 if (VBOX_SUCCESS (rc))
813 {
814 if (pRemoteUSBBackend == NULL)
815 {
816 /* The first backend in the list is requested. */
817 pNextRemoteUSBBackend = mUSBBackends.pHead;
818 }
819 else
820 {
821 /* Get pointer to the next backend. */
822 pNextRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
823 }
824
825 if (pNextRemoteUSBBackend)
826 {
827 pNextRemoteUSBBackend->AddRef ();
828 }
829
830 unlockConsoleVRDPServer ();
831
832 if (pRemoteUSBBackend)
833 {
834 pRemoteUSBBackend->Release ();
835 }
836 }
837#endif
838
839 return pNextRemoteUSBBackend;
840}
841
842#ifdef VBOX_WITH_USB
843/* Internal method. Called under the ConsoleVRDPServerLock. */
844RemoteUSBBackend *ConsoleVRDPServer::usbBackendFind (uint32_t u32ClientId)
845{
846 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
847
848 while (pRemoteUSBBackend)
849 {
850 if (pRemoteUSBBackend->ClientId () == u32ClientId)
851 {
852 break;
853 }
854
855 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
856 }
857
858 return pRemoteUSBBackend;
859}
860
861/* Internal method. Called under the ConsoleVRDPServerLock. */
862RemoteUSBBackend *ConsoleVRDPServer::usbBackendFindByUUID (const Guid *pGuid)
863{
864 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
865
866 while (pRemoteUSBBackend)
867 {
868 if (pRemoteUSBBackend->findUUID (pGuid))
869 {
870 break;
871 }
872
873 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
874 }
875
876 return pRemoteUSBBackend;
877}
878#endif
879
880/* Internal method. Called by the backend destructor. */
881void ConsoleVRDPServer::usbBackendRemoveFromList (RemoteUSBBackend *pRemoteUSBBackend)
882{
883#ifdef VBOX_WITH_USB
884 int rc = lockConsoleVRDPServer ();
885 AssertRC (rc);
886
887 /* Exclude the found instance from the list. */
888 if (pRemoteUSBBackend->pNext)
889 {
890 pRemoteUSBBackend->pNext->pPrev = pRemoteUSBBackend->pPrev;
891 }
892 else
893 {
894 mUSBBackends.pTail = (RemoteUSBBackend *)pRemoteUSBBackend->pPrev;
895 }
896
897 if (pRemoteUSBBackend->pPrev)
898 {
899 pRemoteUSBBackend->pPrev->pNext = pRemoteUSBBackend->pNext;
900 }
901 else
902 {
903 mUSBBackends.pHead = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
904 }
905
906 pRemoteUSBBackend->pNext = pRemoteUSBBackend->pPrev = NULL;
907
908 unlockConsoleVRDPServer ();
909#endif
910}
911#else // VRDP_MC
912void ConsoleVRDPServer::CreateUSBBackend (PFNVRDPUSBCALLBACK *ppfn, void **ppv)
913{
914#ifdef VBOX_WITH_USB
915 Assert(mRemoteUSBBackend == NULL);
916
917 mRemoteUSBBackend = new RemoteUSBBackend (mConsole, this);
918
919 if (mRemoteUSBBackend)
920 {
921 int rc = mRemoteUSBBackend->InterceptUSB (ppfn, ppv);
922
923 if (VBOX_FAILURE (rc))
924 {
925 delete mRemoteUSBBackend;
926 mRemoteUSBBackend = NULL;
927 }
928 }
929#endif /* VBOX_WITH_USB */
930}
931
932void ConsoleVRDPServer::DeleteUSBBackend (void)
933{
934#ifdef VBOX_WITH_USB
935 LogFlow(("ConsoleVRDPServer::DeleteUSBBackend: %p\n", mRemoteUSBBackend));
936
937 if (mRemoteUSBBackend)
938 {
939 mRemoteUSBBackend->ReleaseUSB ();
940 delete mRemoteUSBBackend;
941 mRemoteUSBBackend = NULL;
942 }
943#endif /* VBOX_WITH_USB */
944}
945
946void *ConsoleVRDPServer::GetUSBBackendPointer (void)
947{
948#ifdef VBOX_WITH_USB
949 Assert (mRemoteUSBBackend); /* Must be called only if the object exists. */
950 return mRemoteUSBBackend->GetRemoteBackendCallback ();
951#else
952 return NULL;
953#endif
954}
955#endif /* VRDP_MC */
956
957
958
959void ConsoleVRDPServer::SendUpdate (void *pvUpdate, uint32_t cbUpdate) const
960{
961#ifdef VBOX_VRDP
962 if (mpfnVRDPSendUpdate)
963 mpfnVRDPSendUpdate (mhServer, pvUpdate, cbUpdate);
964#endif
965}
966
967void ConsoleVRDPServer::SendResize (void) const
968{
969#ifdef VBOX_VRDP
970 if (mpfnVRDPSendResize)
971 mpfnVRDPSendResize (mhServer);
972#endif
973}
974
975void ConsoleVRDPServer::SendUpdateBitmap (uint32_t x, uint32_t y, uint32_t w, uint32_t h) const
976{
977#ifdef VBOX_VRDP
978 if (mpfnVRDPSendUpdateBitmap)
979 mpfnVRDPSendUpdateBitmap (mhServer, x, y, w, h);
980#endif
981}
982
983void ConsoleVRDPServer::SetFramebuffer (IFramebuffer *framebuffer, uint32_t fFlags) const
984{
985#ifdef VBOX_VRDP
986 if (mpfnVRDPSetFramebuffer)
987 mpfnVRDPSetFramebuffer (mhServer, framebuffer, fFlags);
988#endif
989}
990
991void ConsoleVRDPServer::SendAudioSamples (void *pvSamples, uint32_t cSamples, VRDPAUDIOFORMAT format) const
992{
993#ifdef VBOX_VRDP
994 if (mpfnVRDPSendAudioSamples)
995 mpfnVRDPSendAudioSamples (mhServer, pvSamples, cSamples, format);
996#endif
997}
998
999void ConsoleVRDPServer::SendAudioVolume (uint16_t left, uint16_t right) const
1000{
1001#ifdef VBOX_VRDP
1002 if (mpfnVRDPSendAudioVolume)
1003 mpfnVRDPSendAudioVolume (mhServer, left, right);
1004#endif
1005}
1006
1007#ifdef VRDP_MC
1008void ConsoleVRDPServer::SendUSBRequest (uint32_t u32ClientId, void *pvParms, uint32_t cbParms) const
1009{
1010#ifdef VBOX_VRDP
1011 if (mpfnVRDPSendUSBRequest)
1012 mpfnVRDPSendUSBRequest (mhServer, u32ClientId, pvParms, cbParms);
1013#endif
1014}
1015#else
1016void ConsoleVRDPServer::SendUSBRequest (void *pvParms, uint32_t cbParms) const
1017{
1018#ifdef VBOX_VRDP
1019 if (mpfnVRDPSendUSBRequest)
1020 mpfnVRDPSendUSBRequest (mhServer, pvParms, cbParms);
1021#endif
1022}
1023#endif /* VRDP_MC */
1024
1025void ConsoleVRDPServer::QueryInfo (uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const
1026{
1027#ifdef VBOX_VRDP
1028 if (mpfnVRDPQueryInfo)
1029 mpfnVRDPQueryInfo (mhServer, index, pvBuffer, cbBuffer, pcbOut);
1030#endif
1031}
1032
1033#ifdef VBOX_VRDP
1034/* note: static function now! */
1035bool ConsoleVRDPServer::loadVRDPLibrary (void)
1036{
1037 int rc = VINF_SUCCESS;
1038
1039 if (!mVRDPLibrary)
1040 {
1041 rc = RTLdrLoad("VBoxVRDP", &mVRDPLibrary);
1042
1043 if (VBOX_SUCCESS(rc))
1044 {
1045 LogFlow(("VRDPServer::loadLibrary(): successfully loaded VRDP library.\n"));
1046
1047 struct SymbolEntry
1048 {
1049 const char *name;
1050 void **ppfn;
1051 };
1052
1053 #define DEFSYMENTRY(a) { #a, (void**)&mpfn##a }
1054
1055 static const struct SymbolEntry symbols[] =
1056 {
1057 DEFSYMENTRY(VRDPStartServer),
1058 DEFSYMENTRY(VRDPSetFramebuffer),
1059 DEFSYMENTRY(VRDPSetCallback),
1060 DEFSYMENTRY(VRDPShutdownServer),
1061 DEFSYMENTRY(VRDPSendUpdate),
1062 DEFSYMENTRY(VRDPSendUpdateBitmap),
1063 DEFSYMENTRY(VRDPSendResize),
1064 DEFSYMENTRY(VRDPSendAudioSamples),
1065 DEFSYMENTRY(VRDPSendAudioVolume),
1066 DEFSYMENTRY(VRDPSendUSBRequest),
1067 DEFSYMENTRY(VRDPQueryInfo),
1068 DEFSYMENTRY(VRDPClipboard)
1069 };
1070
1071 #undef DEFSYMENTRY
1072
1073 for (unsigned i = 0; i < ELEMENTS(symbols); i++)
1074 {
1075 rc = RTLdrGetSymbol(mVRDPLibrary, symbols[i].name, symbols[i].ppfn);
1076
1077 AssertMsgRC(rc, ("Error resolving VRDP symbol %s\n", symbols[i].name));
1078
1079 if (VBOX_FAILURE(rc))
1080 {
1081 break;
1082 }
1083 }
1084 }
1085 else
1086 {
1087 LogFlow(("VRDPServer::loadLibrary(): failed to load VRDP library! VRDP not available.\n"));
1088 mVRDPLibrary = NULL;
1089 }
1090 }
1091
1092 // just to be safe
1093 if (VBOX_FAILURE(rc))
1094 {
1095 if (mVRDPLibrary)
1096 {
1097 RTLdrClose (mVRDPLibrary);
1098 mVRDPLibrary = NULL;
1099 }
1100 }
1101
1102 return (mVRDPLibrary != NULL);
1103}
1104#endif /* VBOX_VRDP */
1105
1106/*
1107 * IRemoteDisplayInfo implementation.
1108 */
1109// constructor / destructor
1110/////////////////////////////////////////////////////////////////////////////
1111
1112HRESULT RemoteDisplayInfo::FinalConstruct()
1113{
1114 return S_OK;
1115}
1116
1117void RemoteDisplayInfo::FinalRelease()
1118{
1119 if (isReady())
1120 uninit ();
1121}
1122
1123// public methods only for internal purposes
1124/////////////////////////////////////////////////////////////////////////////
1125
1126/**
1127 * Initializes the guest object.
1128 */
1129HRESULT RemoteDisplayInfo::init (Console *aParent)
1130{
1131 LogFlowMember (("RemoteDisplayInfo::init (%p)\n", aParent));
1132
1133 ComAssertRet (aParent, E_INVALIDARG);
1134
1135 AutoLock alock (this);
1136 ComAssertRet (!isReady(), E_UNEXPECTED);
1137
1138 mParent = aParent;
1139
1140 setReady (true);
1141 return S_OK;
1142}
1143
1144/**
1145 * Uninitializes the instance and sets the ready flag to FALSE.
1146 * Called either from FinalRelease() or by the parent when it gets destroyed.
1147 */
1148void RemoteDisplayInfo::uninit()
1149{
1150 LogFlowMember (("RemoteDisplayInfo::uninit()\n"));
1151
1152 AutoLock alock (this);
1153 AssertReturn (isReady(), (void) 0);
1154
1155 mParent.setNull();
1156
1157 setReady (false);
1158}
1159
1160// IRemoteDisplayInfo properties
1161/////////////////////////////////////////////////////////////////////////////
1162
1163#define IMPL_GETTER_BOOL(_aType, _aName, _aIndex) \
1164 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
1165 { \
1166 if (!a##_aName) \
1167 return E_POINTER; \
1168 \
1169 AutoLock alock (this); \
1170 CHECK_READY(); \
1171 \
1172 uint32_t value; \
1173 uint32_t cbOut = 0; \
1174 \
1175 mParent->consoleVRDPServer ()->QueryInfo \
1176 (_aIndex, &value, sizeof (value), &cbOut); \
1177 \
1178 *a##_aName = cbOut? !!value: FALSE; \
1179 \
1180 return S_OK; \
1181 }
1182
1183#define IMPL_GETTER_SCALAR(_aType, _aName, _aIndex) \
1184 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
1185 { \
1186 if (!a##_aName) \
1187 return E_POINTER; \
1188 \
1189 AutoLock alock (this); \
1190 CHECK_READY(); \
1191 \
1192 _aType value; \
1193 uint32_t cbOut = 0; \
1194 \
1195 mParent->consoleVRDPServer ()->QueryInfo \
1196 (_aIndex, &value, sizeof (value), &cbOut); \
1197 \
1198 *a##_aName = cbOut? value: 0; \
1199 \
1200 return S_OK; \
1201 }
1202
1203#define IMPL_GETTER_BSTR(_aType, _aName, _aIndex) \
1204 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
1205 { \
1206 if (!a##_aName) \
1207 return E_POINTER; \
1208 \
1209 AutoLock alock (this); \
1210 CHECK_READY(); \
1211 \
1212 uint32_t cbOut = 0; \
1213 \
1214 mParent->consoleVRDPServer ()->QueryInfo \
1215 (_aIndex, NULL, 0, &cbOut); \
1216 \
1217 if (cbOut == 0) \
1218 { \
1219 Bstr str(""); \
1220 str.cloneTo (a##_aName); \
1221 return S_OK; \
1222 } \
1223 \
1224 char *pchBuffer = (char *)RTMemTmpAlloc (cbOut); \
1225 \
1226 if (!pchBuffer) \
1227 { \
1228 Log(("RemoteDisplayInfo::" \
1229 #_aName \
1230 ": Failed to allocate memory %d bytes\n", cbOut)); \
1231 return E_OUTOFMEMORY; \
1232 } \
1233 \
1234 mParent->consoleVRDPServer ()->QueryInfo \
1235 (_aIndex, pchBuffer, cbOut, &cbOut); \
1236 \
1237 Bstr str(pchBuffer); \
1238 \
1239 str.cloneTo (a##_aName); \
1240 \
1241 RTMemTmpFree (pchBuffer); \
1242 \
1243 return S_OK; \
1244 }
1245
1246IMPL_GETTER_BOOL (BOOL, Active, VRDP_QI_ACTIVE);
1247IMPL_GETTER_SCALAR (ULONG, NumberOfClients, VRDP_QI_NUMBER_OF_CLIENTS);
1248IMPL_GETTER_SCALAR (LONG64, BeginTime, VRDP_QI_BEGIN_TIME);
1249IMPL_GETTER_SCALAR (LONG64, EndTime, VRDP_QI_END_TIME);
1250IMPL_GETTER_SCALAR (ULONG64, BytesSent, VRDP_QI_BYTES_SENT);
1251IMPL_GETTER_SCALAR (ULONG64, BytesSentTotal, VRDP_QI_BYTES_SENT_TOTAL);
1252IMPL_GETTER_SCALAR (ULONG64, BytesReceived, VRDP_QI_BYTES_RECEIVED);
1253IMPL_GETTER_SCALAR (ULONG64, BytesReceivedTotal, VRDP_QI_BYTES_RECEIVED_TOTAL);
1254IMPL_GETTER_BSTR (BSTR, User, VRDP_QI_USER);
1255IMPL_GETTER_BSTR (BSTR, Domain, VRDP_QI_DOMAIN);
1256IMPL_GETTER_BSTR (BSTR, ClientName, VRDP_QI_CLIENT_NAME);
1257IMPL_GETTER_BSTR (BSTR, ClientIP, VRDP_QI_CLIENT_IP);
1258IMPL_GETTER_SCALAR (ULONG, ClientVersion, VRDP_QI_CLIENT_VERSION);
1259IMPL_GETTER_SCALAR (ULONG, EncryptionStyle, VRDP_QI_ENCRYPTION_STYLE);
1260
1261#undef IMPL_GETTER_BSTR
1262#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