VirtualBox

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

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

Multimonitor support.

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

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