VirtualBox

source: vbox/trunk/src/VBox/Main/VRDEServerImpl.cpp@ 35105

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

Main: API to list supported VRDE properties.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.9 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "VRDEServerImpl.h"
19#include "MachineImpl.h"
20#include "VirtualBoxImpl.h"
21#ifdef VBOX_WITH_EXTPACK
22# include "ExtPackManagerImpl.h"
23#endif
24
25#include <iprt/cpp/utils.h>
26#include <iprt/ctype.h>
27#include <iprt/ldr.h>
28#include <iprt/path.h>
29
30#include <VBox/err.h>
31#include <VBox/sup.h>
32
33#include <VBox/RemoteDesktop/VRDE.h>
34
35#include "AutoStateDep.h"
36#include "AutoCaller.h"
37#include "Global.h"
38#include "Logging.h"
39
40// defines
41/////////////////////////////////////////////////////////////////////////////
42#define VRDP_DEFAULT_PORT_STR "3389"
43
44// constructor / destructor
45/////////////////////////////////////////////////////////////////////////////
46
47VRDEServer::VRDEServer()
48 : mParent(NULL)
49{
50}
51
52VRDEServer::~VRDEServer()
53{
54}
55
56HRESULT VRDEServer::FinalConstruct()
57{
58 return S_OK;
59}
60
61void VRDEServer::FinalRelease()
62{
63 uninit();
64}
65
66// public initializer/uninitializer for internal purposes only
67/////////////////////////////////////////////////////////////////////////////
68
69/**
70 * Initializes the VRDP server object.
71 *
72 * @param aParent Handle of the parent object.
73 */
74HRESULT VRDEServer::init (Machine *aParent)
75{
76 LogFlowThisFunc(("aParent=%p\n", aParent));
77
78 ComAssertRet(aParent, E_INVALIDARG);
79
80 /* Enclose the state transition NotReady->InInit->Ready */
81 AutoInitSpan autoInitSpan(this);
82 AssertReturn(autoInitSpan.isOk(), E_FAIL);
83
84 unconst(mParent) = aParent;
85 /* mPeer is left null */
86
87 mData.allocate();
88
89 mData->mAuthType = AuthType_Null;
90 mData->mAuthTimeout = 0;
91 mData->mAuthLibrary.setNull();
92 mData->mEnabled = FALSE;
93 mData->mAllowMultiConnection = FALSE;
94 mData->mReuseSingleConnection = FALSE;
95 mData->mVideoChannel = FALSE;
96 mData->mVideoChannelQuality = 75;
97 mData->mVrdeExtPack.setNull();
98
99 /* Confirm a successful initialization */
100 autoInitSpan.setSucceeded();
101
102 return S_OK;
103}
104
105/**
106 * Initializes the object given another object
107 * (a kind of copy constructor). This object shares data with
108 * the object passed as an argument.
109 *
110 * @note This object must be destroyed before the original object
111 * it shares data with is destroyed.
112 *
113 * @note Locks @a aThat object for reading.
114 */
115HRESULT VRDEServer::init (Machine *aParent, VRDEServer *aThat)
116{
117 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
118
119 ComAssertRet(aParent && aThat, E_INVALIDARG);
120
121 /* Enclose the state transition NotReady->InInit->Ready */
122 AutoInitSpan autoInitSpan(this);
123 AssertReturn(autoInitSpan.isOk(), E_FAIL);
124
125 unconst(mParent) = aParent;
126 unconst(mPeer) = aThat;
127
128 AutoCaller thatCaller (aThat);
129 AssertComRCReturnRC(thatCaller.rc());
130
131 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
132 mData.share (aThat->mData);
133
134 /* Confirm a successful initialization */
135 autoInitSpan.setSucceeded();
136
137 return S_OK;
138}
139
140/**
141 * Initializes the guest object given another guest object
142 * (a kind of copy constructor). This object makes a private copy of data
143 * of the original object passed as an argument.
144 *
145 * @note Locks @a aThat object for reading.
146 */
147HRESULT VRDEServer::initCopy (Machine *aParent, VRDEServer *aThat)
148{
149 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
150
151 ComAssertRet(aParent && aThat, E_INVALIDARG);
152
153 /* Enclose the state transition NotReady->InInit->Ready */
154 AutoInitSpan autoInitSpan(this);
155 AssertReturn(autoInitSpan.isOk(), E_FAIL);
156
157 unconst(mParent) = aParent;
158 /* mPeer is left null */
159
160 AutoCaller thatCaller (aThat);
161 AssertComRCReturnRC(thatCaller.rc());
162
163 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
164 mData.attachCopy (aThat->mData);
165
166 /* Confirm a successful initialization */
167 autoInitSpan.setSucceeded();
168
169 return S_OK;
170}
171
172/**
173 * Uninitializes the instance and sets the ready flag to FALSE.
174 * Called either from FinalRelease() or by the parent when it gets destroyed.
175 */
176void VRDEServer::uninit()
177{
178 LogFlowThisFunc(("\n"));
179
180 /* Enclose the state transition Ready->InUninit->NotReady */
181 AutoUninitSpan autoUninitSpan(this);
182 if (autoUninitSpan.uninitDone())
183 return;
184
185 mData.free();
186
187 unconst(mPeer) = NULL;
188 unconst(mParent) = NULL;
189}
190
191/**
192 * Loads settings from the given machine node.
193 * May be called once right after this object creation.
194 *
195 * @param aMachineNode <Machine> node.
196 *
197 * @note Locks this object for writing.
198 */
199HRESULT VRDEServer::loadSettings(const settings::VRDESettings &data)
200{
201 using namespace settings;
202
203 AutoCaller autoCaller(this);
204 AssertComRCReturnRC(autoCaller.rc());
205
206 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
207
208 mData->mEnabled = data.fEnabled;
209 mData->mAuthType = data.authType;
210 mData->mAuthTimeout = data.ulAuthTimeout;
211 mData->mAuthLibrary = data.strAuthLibrary;
212 mData->mAllowMultiConnection = data.fAllowMultiConnection;
213 mData->mReuseSingleConnection = data.fReuseSingleConnection;
214 mData->mVideoChannel = data.fVideoChannel;
215 mData->mVideoChannelQuality = data.ulVideoChannelQuality;
216 mData->mVrdeExtPack = data.strVrdeExtPack;
217 mData->mProperties = data.mapProperties;
218
219 return S_OK;
220}
221
222/**
223 * Saves settings to the given machine node.
224 *
225 * @param aMachineNode <Machine> node.
226 *
227 * @note Locks this object for reading.
228 */
229HRESULT VRDEServer::saveSettings(settings::VRDESettings &data)
230{
231 AutoCaller autoCaller(this);
232 AssertComRCReturnRC(autoCaller.rc());
233
234 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
235
236 data.fEnabled = !!mData->mEnabled;
237 data.authType = mData->mAuthType;
238 data.strAuthLibrary = mData->mAuthLibrary;
239 data.ulAuthTimeout = mData->mAuthTimeout;
240 data.fAllowMultiConnection = !!mData->mAllowMultiConnection;
241 data.fReuseSingleConnection = !!mData->mReuseSingleConnection;
242 data.fVideoChannel = !!mData->mVideoChannel;
243 data.ulVideoChannelQuality = mData->mVideoChannelQuality;
244 data.strVrdeExtPack = mData->mVrdeExtPack;
245 data.mapProperties = mData->mProperties;
246
247 return S_OK;
248}
249
250// IVRDEServer properties
251/////////////////////////////////////////////////////////////////////////////
252
253STDMETHODIMP VRDEServer::COMGETTER(Enabled) (BOOL *aEnabled)
254{
255 CheckComArgOutPointerValid(aEnabled);
256
257 AutoCaller autoCaller(this);
258 if (FAILED(autoCaller.rc())) return autoCaller.rc();
259
260 *aEnabled = mData->mEnabled;
261
262 return S_OK;
263}
264
265STDMETHODIMP VRDEServer::COMSETTER(Enabled) (BOOL aEnabled)
266{
267 AutoCaller autoCaller(this);
268 if (FAILED(autoCaller.rc())) return autoCaller.rc();
269
270 /* the machine can also be in saved state for this property to change */
271 AutoMutableOrSavedStateDependency adep (mParent);
272 if (FAILED(adep.rc())) return adep.rc();
273
274 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
275
276 if (mData->mEnabled != aEnabled)
277 {
278 mData.backup();
279 mData->mEnabled = aEnabled;
280
281 /* leave the lock before informing callbacks */
282 alock.release();
283
284 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
285 mParent->setModified(Machine::IsModified_VRDEServer);
286 mlock.release();
287
288 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
289 adep.release();
290
291 mParent->onVRDEServerChange(/* aRestart */ TRUE);
292 }
293
294 return S_OK;
295}
296
297static int portParseNumber(uint16_t *pu16Port, const char *pszStart, const char *pszEnd)
298{
299 /* Gets a string of digits, converts to 16 bit port number.
300 * Note: pszStart <= pszEnd is expected, the string contains
301 * only digits and pszEnd points to the char after last
302 * digit.
303 */
304 int cch = pszEnd - pszStart;
305 if (cch > 0 && cch <= 5) /* Port is up to 5 decimal digits. */
306 {
307 unsigned uPort = 0;
308 while (pszStart != pszEnd)
309 {
310 uPort = uPort * 10 + *pszStart - '0';
311 pszStart++;
312 }
313
314 if (uPort != 0 && uPort < 0x10000)
315 {
316 if (pu16Port)
317 *pu16Port = (uint16_t)uPort;
318 return VINF_SUCCESS;
319 }
320 }
321
322 return VERR_INVALID_PARAMETER;
323}
324
325static int vrdpServerVerifyPortsString(Bstr ports)
326{
327 com::Utf8Str portRange = ports;
328
329 const char *pszPortRange = portRange.c_str();
330
331 if (!pszPortRange || *pszPortRange == 0) /* Reject empty string. */
332 return VERR_INVALID_PARAMETER;
333
334 /* The string should be like "1000-1010,1020,2000-2003" */
335 while (*pszPortRange)
336 {
337 const char *pszStart = pszPortRange;
338 const char *pszDash = NULL;
339 const char *pszEnd = pszStart;
340
341 while (*pszEnd && *pszEnd != ',')
342 {
343 if (*pszEnd == '-')
344 {
345 if (pszDash != NULL)
346 return VERR_INVALID_PARAMETER; /* More than one '-'. */
347
348 pszDash = pszEnd;
349 }
350 else if (!RT_C_IS_DIGIT(*pszEnd))
351 return VERR_INVALID_PARAMETER;
352
353 pszEnd++;
354 }
355
356 /* Update the next range pointer. */
357 pszPortRange = pszEnd;
358 if (*pszPortRange == ',')
359 {
360 pszPortRange++;
361 }
362
363 /* A probably valid range. Verify and parse it. */
364 int rc;
365 if (pszDash)
366 {
367 rc = portParseNumber(NULL, pszStart, pszDash);
368 if (RT_SUCCESS(rc))
369 rc = portParseNumber(NULL, pszDash + 1, pszEnd);
370 }
371 else
372 rc = portParseNumber(NULL, pszStart, pszEnd);
373
374 if (RT_FAILURE(rc))
375 return rc;
376 }
377
378 return VINF_SUCCESS;
379}
380
381STDMETHODIMP VRDEServer::SetVRDEProperty (IN_BSTR aKey, IN_BSTR aValue)
382{
383 LogFlowThisFunc(("\n"));
384
385 AutoCaller autoCaller(this);
386 if (FAILED(autoCaller.rc())) return autoCaller.rc();
387
388 /* The machine needs to be mutable. */
389 AutoMutableStateDependency adep(mParent);
390 if (FAILED(adep.rc())) return adep.rc();
391
392 Bstr key = aKey;
393
394 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
395
396 /* Special processing for some "standard" properties. */
397 if (key == Bstr("TCP/Ports"))
398 {
399 Bstr ports = aValue;
400
401 /* Verify the string. */
402 int vrc = vrdpServerVerifyPortsString(ports);
403 if (RT_FAILURE(vrc))
404 return E_INVALIDARG;
405
406 if (ports != mData->mProperties["TCP/Ports"])
407 {
408 /* Port value is not verified here because it is up to VRDP transport to
409 * use it. Specifying a wrong port number will cause a running server to
410 * stop. There is no fool proof here.
411 */
412 mData.backup();
413 if (ports == Bstr("0"))
414 mData->mProperties["TCP/Ports"] = VRDP_DEFAULT_PORT_STR;
415 else
416 mData->mProperties["TCP/Ports"] = ports;
417
418 /* leave the lock before informing callbacks */
419 alock.release();
420
421 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
422 mParent->setModified(Machine::IsModified_VRDEServer);
423 mlock.release();
424
425 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
426 adep.release();
427
428 mParent->onVRDEServerChange(/* aRestart */ TRUE);
429 }
430 }
431 else
432 {
433 /* Generic properties processing.
434 * Look up the old value first; if nothing's changed then do nothing.
435 */
436 Utf8Str strValue(aValue);
437 Utf8Str strKey(aKey);
438 Utf8Str strOldValue;
439
440 settings::StringsMap::const_iterator it = mData->mProperties.find(strKey);
441 if (it != mData->mProperties.end())
442 strOldValue = it->second;
443
444 if (strOldValue != strValue)
445 {
446 if (strValue.isEmpty())
447 mData->mProperties.erase(strKey);
448 else
449 mData->mProperties[strKey] = strValue;
450
451 /* leave the lock before informing callbacks */
452 alock.release();
453
454 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
455 mParent->setModified(Machine::IsModified_VRDEServer);
456 mlock.release();
457
458 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
459 adep.release();
460
461 mParent->onVRDEServerChange(/* aRestart */ TRUE);
462 }
463 }
464
465 return S_OK;
466}
467
468STDMETHODIMP VRDEServer::GetVRDEProperty (IN_BSTR aKey, BSTR *aValue)
469{
470 CheckComArgOutPointerValid(aValue);
471
472 AutoCaller autoCaller(this);
473 if (FAILED(autoCaller.rc())) return autoCaller.rc();
474
475 Bstr key = aKey;
476 Bstr value;
477
478 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
479
480 Utf8Str strKey(key);
481 settings::StringsMap::const_iterator it = mData->mProperties.find(strKey);
482 if (it != mData->mProperties.end())
483 {
484 value = it->second; // source is a Utf8Str
485 value.cloneTo(aValue);
486 }
487
488 return S_OK;
489}
490
491static int loadVRDELibrary(const char *pszLibraryName, RTLDRMOD *phmod, PFNVRDESUPPORTEDPROPERTIES *ppfn)
492{
493 int rc = VINF_SUCCESS;
494
495 RTLDRMOD hmod = NIL_RTLDRMOD;
496
497 char szErr[4096 + 512];
498 szErr[0] = '\0';
499 if (RTPathHavePath(pszLibraryName))
500 rc = SUPR3HardenedLdrLoadPlugIn(pszLibraryName, &hmod, szErr, sizeof(szErr));
501 else
502 rc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &hmod, szErr, sizeof(szErr));
503 if (RT_SUCCESS(rc))
504 {
505 rc = RTLdrGetSymbol(hmod, "VRDESupportedProperties", (void **)ppfn);
506
507 if (RT_FAILURE(rc) && rc != VERR_SYMBOL_NOT_FOUND)
508 LogRel(("VRDE: Error resolving symbol '%s', rc %Rrc.\n", "VRDESupportedProperties", rc));
509 }
510 else
511 {
512 if (szErr[0])
513 LogRel(("VRDE: Error loading the library '%s': %s (%Rrc)\n", pszLibraryName, szErr, rc));
514 else
515 LogRel(("VRDE: Error loading the library '%s' rc = %Rrc.\n", pszLibraryName, rc));
516
517 hmod = NIL_RTLDRMOD;
518 }
519
520 if (RT_SUCCESS(rc))
521 {
522 *phmod = hmod;
523 }
524 else
525 {
526 if (hmod != NIL_RTLDRMOD)
527 {
528 RTLdrClose(hmod);
529 hmod = NIL_RTLDRMOD;
530 }
531 }
532
533 return rc;
534}
535
536STDMETHODIMP VRDEServer::COMGETTER(VRDEProperties)(ComSafeArrayOut(BSTR, aProperties))
537{
538 if (ComSafeArrayOutIsNull(aProperties))
539 return E_POINTER;
540
541 AutoCaller autoCaller(this);
542 if (FAILED(autoCaller.rc())) return autoCaller.rc();
543
544 size_t cProperties = 0;
545
546 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
547 if (!mData->mEnabled)
548 {
549 com::SafeArray<BSTR> properties(cProperties);
550 properties.detachTo(ComSafeArrayOutArg(aProperties));
551 return S_OK;
552 }
553 alock.release();
554
555 /*
556 * Check that a VRDE extension pack name is set and resolve it into a
557 * library path.
558 */
559 Bstr bstrExtPack;
560 HRESULT hrc = COMGETTER(VRDEExtPack)(bstrExtPack.asOutParam());
561 Log(("VRDEPROP: get extpack hrc 0x%08X, isEmpty %d\n", hrc, bstrExtPack.isEmpty()));
562 if (FAILED(hrc))
563 return hrc;
564 if (bstrExtPack.isEmpty())
565 return E_FAIL;
566
567 Utf8Str strExtPack(bstrExtPack);
568 Utf8Str strVrdeLibrary;
569 int vrc = VINF_SUCCESS;
570 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
571 strVrdeLibrary = "VBoxVRDP";
572 else
573 {
574#ifdef VBOX_WITH_EXTPACK
575 VirtualBox *pVirtualBox = mParent->getVirtualBox();
576 ExtPackManager *pExtPackMgr = pVirtualBox->getExtPackManager();
577 vrc = pExtPackMgr->getVrdeLibraryPathForExtPack(&strExtPack, &strVrdeLibrary);
578#else
579 vrc = VERR_FILE_NOT_FOUND;
580#endif
581 }
582 Log(("VRDEPROP: library get rc %Rrc\n", vrc));
583
584 if (RT_SUCCESS(vrc))
585 {
586 /*
587 * Load the VRDE library and start the server, if it is enabled.
588 */
589 PFNVRDESUPPORTEDPROPERTIES pfn = NULL;
590 RTLDRMOD hmod = NIL_RTLDRMOD;
591 vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, &pfn);
592 Log(("VRDEPROP: load library [%s] rc %Rrc\n", strVrdeLibrary.c_str(), vrc));
593 if (RT_SUCCESS(vrc))
594 {
595 const char * const *papszNames = pfn();
596
597 if (papszNames)
598 {
599 size_t i;
600 for (i = 0; papszNames[i] != NULL; ++i)
601 {
602 cProperties++;
603 }
604 }
605 Log(("VRDEPROP: %d properties\n", cProperties));
606
607 com::SafeArray<BSTR> properties(cProperties);
608
609 if (cProperties > 0)
610 {
611 size_t i;
612 for (i = 0; papszNames[i] != NULL && i < cProperties; ++i)
613 {
614 Bstr tmp(papszNames[i]);
615 tmp.cloneTo(&properties[i]);
616 }
617 }
618
619 /* Do not forget to unload the library. */
620 RTLdrClose(hmod);
621 hmod = NIL_RTLDRMOD;
622
623 properties.detachTo(ComSafeArrayOutArg(aProperties));
624 }
625 }
626
627 if (RT_FAILURE(vrc))
628 {
629 return E_FAIL;
630 }
631
632 return S_OK;
633}
634
635STDMETHODIMP VRDEServer::COMGETTER(AuthType) (AuthType_T *aType)
636{
637 CheckComArgOutPointerValid(aType);
638
639 AutoCaller autoCaller(this);
640 if (FAILED(autoCaller.rc())) return autoCaller.rc();
641
642 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
643
644 *aType = mData->mAuthType;
645
646 return S_OK;
647}
648
649STDMETHODIMP VRDEServer::COMSETTER(AuthType) (AuthType_T aType)
650{
651 AutoCaller autoCaller(this);
652 if (FAILED(autoCaller.rc())) return autoCaller.rc();
653
654 /* the machine needs to be mutable */
655 AutoMutableStateDependency adep(mParent);
656 if (FAILED(adep.rc())) return adep.rc();
657
658 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
659
660 if (mData->mAuthType != aType)
661 {
662 mData.backup();
663 mData->mAuthType = aType;
664
665 /* leave the lock before informing callbacks */
666 alock.release();
667
668 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
669 mParent->setModified(Machine::IsModified_VRDEServer);
670 mlock.release();
671
672 mParent->onVRDEServerChange(/* aRestart */ TRUE);
673 }
674
675 return S_OK;
676}
677
678STDMETHODIMP VRDEServer::COMGETTER(AuthTimeout) (ULONG *aTimeout)
679{
680 CheckComArgOutPointerValid(aTimeout);
681
682 AutoCaller autoCaller(this);
683 if (FAILED(autoCaller.rc())) return autoCaller.rc();
684
685 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
686
687 *aTimeout = mData->mAuthTimeout;
688
689 return S_OK;
690}
691
692STDMETHODIMP VRDEServer::COMSETTER(AuthTimeout) (ULONG aTimeout)
693{
694 AutoCaller autoCaller(this);
695 if (FAILED(autoCaller.rc())) return autoCaller.rc();
696
697 /* the machine needs to be mutable */
698 AutoMutableStateDependency adep(mParent);
699 if (FAILED(adep.rc())) return adep.rc();
700
701 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
702
703 if (aTimeout != mData->mAuthTimeout)
704 {
705 mData.backup();
706 mData->mAuthTimeout = aTimeout;
707
708 /* leave the lock before informing callbacks */
709 alock.release();
710
711 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
712 mParent->setModified(Machine::IsModified_VRDEServer);
713 mlock.release();
714
715 /* sunlover 20060131: This setter does not require the notification
716 * really */
717#if 0
718 mParent->onVRDEServerChange();
719#endif
720 }
721
722 return S_OK;
723}
724
725STDMETHODIMP VRDEServer::COMGETTER(AuthLibrary) (BSTR *aLibrary)
726{
727 CheckComArgOutPointerValid(aLibrary);
728
729 AutoCaller autoCaller(this);
730 if (FAILED(autoCaller.rc())) return autoCaller.rc();
731
732 Bstr bstrLibrary;
733
734 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
735 bstrLibrary = mData->mAuthLibrary;
736 alock.release();
737
738 if (bstrLibrary.isEmpty())
739 {
740 /* Get the global setting. */
741 ComPtr<ISystemProperties> systemProperties;
742 HRESULT hrc = mParent->getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
743
744 if (SUCCEEDED(hrc))
745 hrc = systemProperties->COMGETTER(VRDEAuthLibrary)(bstrLibrary.asOutParam());
746
747 if (FAILED(hrc))
748 return setError(hrc, "failed to query the library setting\n");
749 }
750
751 bstrLibrary.cloneTo(aLibrary);
752
753 return S_OK;
754}
755
756STDMETHODIMP VRDEServer::COMSETTER(AuthLibrary) (IN_BSTR aLibrary)
757{
758 AutoCaller autoCaller(this);
759 if (FAILED(autoCaller.rc())) return autoCaller.rc();
760
761 /* the machine needs to be mutable */
762 AutoMutableStateDependency adep(mParent);
763 if (FAILED(adep.rc())) return adep.rc();
764
765 Bstr bstrLibrary(aLibrary);
766
767 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
768
769 if (mData->mAuthLibrary != bstrLibrary)
770 {
771 mData.backup();
772 mData->mAuthLibrary = bstrLibrary;
773
774 /* leave the lock before informing callbacks */
775 alock.release();
776
777 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
778 mParent->setModified(Machine::IsModified_VRDEServer);
779 mlock.release();
780
781 mParent->onVRDEServerChange(/* aRestart */ TRUE);
782 }
783
784 return S_OK;
785}
786
787STDMETHODIMP VRDEServer::COMGETTER(AllowMultiConnection) (
788 BOOL *aAllowMultiConnection)
789{
790 CheckComArgOutPointerValid(aAllowMultiConnection);
791
792 AutoCaller autoCaller(this);
793 if (FAILED(autoCaller.rc())) return autoCaller.rc();
794
795 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
796
797 *aAllowMultiConnection = mData->mAllowMultiConnection;
798
799 return S_OK;
800}
801
802STDMETHODIMP VRDEServer::COMSETTER(AllowMultiConnection) (
803 BOOL aAllowMultiConnection)
804{
805 AutoCaller autoCaller(this);
806 if (FAILED(autoCaller.rc())) return autoCaller.rc();
807
808 /* the machine needs to be mutable */
809 AutoMutableStateDependency adep(mParent);
810 if (FAILED(adep.rc())) return adep.rc();
811
812 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
813
814 if (mData->mAllowMultiConnection != aAllowMultiConnection)
815 {
816 mData.backup();
817 mData->mAllowMultiConnection = aAllowMultiConnection;
818
819 /* leave the lock before informing callbacks */
820 alock.release();
821
822 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
823 mParent->setModified(Machine::IsModified_VRDEServer);
824 mlock.release();
825
826 mParent->onVRDEServerChange(/* aRestart */ TRUE); // @todo does it need a restart?
827 }
828
829 return S_OK;
830}
831
832STDMETHODIMP VRDEServer::COMGETTER(ReuseSingleConnection) (
833 BOOL *aReuseSingleConnection)
834{
835 CheckComArgOutPointerValid(aReuseSingleConnection);
836
837 AutoCaller autoCaller(this);
838 if (FAILED(autoCaller.rc())) return autoCaller.rc();
839
840 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
841
842 *aReuseSingleConnection = mData->mReuseSingleConnection;
843
844 return S_OK;
845}
846
847STDMETHODIMP VRDEServer::COMSETTER(ReuseSingleConnection) (
848 BOOL aReuseSingleConnection)
849{
850 AutoCaller autoCaller(this);
851 if (FAILED(autoCaller.rc())) return autoCaller.rc();
852
853 /* the machine needs to be mutable */
854 AutoMutableStateDependency adep(mParent);
855 if (FAILED(adep.rc())) return adep.rc();
856
857 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
858
859 if (mData->mReuseSingleConnection != aReuseSingleConnection)
860 {
861 mData.backup();
862 mData->mReuseSingleConnection = aReuseSingleConnection;
863
864 /* leave the lock before informing callbacks */
865 alock.release();
866
867 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
868 mParent->setModified(Machine::IsModified_VRDEServer);
869 mlock.release();
870
871 mParent->onVRDEServerChange(/* aRestart */ TRUE); // @todo needs a restart?
872 }
873
874 return S_OK;
875}
876
877STDMETHODIMP VRDEServer::COMGETTER(VideoChannel) (
878 BOOL *aVideoChannel)
879{
880 CheckComArgOutPointerValid(aVideoChannel);
881
882 AutoCaller autoCaller(this);
883 if (FAILED(autoCaller.rc())) return autoCaller.rc();
884
885 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
886
887 *aVideoChannel = mData->mVideoChannel;
888
889 return S_OK;
890}
891
892STDMETHODIMP VRDEServer::COMSETTER(VideoChannel) (
893 BOOL aVideoChannel)
894{
895 AutoCaller autoCaller(this);
896 if (FAILED(autoCaller.rc())) return autoCaller.rc();
897
898 /* the machine needs to be mutable */
899 AutoMutableStateDependency adep(mParent);
900 if (FAILED(adep.rc())) return adep.rc();
901
902 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
903
904 if (mData->mVideoChannel != aVideoChannel)
905 {
906 mData.backup();
907 mData->mVideoChannel = aVideoChannel;
908
909 /* leave the lock before informing callbacks */
910 alock.release();
911
912 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
913 mParent->setModified(Machine::IsModified_VRDEServer);
914 mlock.release();
915
916 mParent->onVRDEServerChange(/* aRestart */ TRUE);
917 }
918
919 return S_OK;
920}
921
922STDMETHODIMP VRDEServer::COMGETTER(VideoChannelQuality) (
923 ULONG *aVideoChannelQuality)
924{
925 CheckComArgOutPointerValid(aVideoChannelQuality);
926
927 AutoCaller autoCaller(this);
928 if (FAILED(autoCaller.rc())) return autoCaller.rc();
929
930 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
931
932 *aVideoChannelQuality = mData->mVideoChannelQuality;
933
934 return S_OK;
935}
936
937STDMETHODIMP VRDEServer::COMSETTER(VideoChannelQuality) (
938 ULONG aVideoChannelQuality)
939{
940 AutoCaller autoCaller(this);
941 if (FAILED(autoCaller.rc())) return autoCaller.rc();
942
943 /* the machine needs to be mutable */
944 AutoMutableStateDependency adep(mParent);
945 if (FAILED(adep.rc())) return adep.rc();
946
947 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
948
949 aVideoChannelQuality = RT_CLAMP(aVideoChannelQuality, 10, 100);
950
951 if (mData->mVideoChannelQuality != aVideoChannelQuality)
952 {
953 mData.backup();
954 mData->mVideoChannelQuality = aVideoChannelQuality;
955
956 /* leave the lock before informing callbacks */
957 alock.release();
958
959 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
960 mParent->setModified(Machine::IsModified_VRDEServer);
961 mlock.release();
962
963 mParent->onVRDEServerChange(/* aRestart */ FALSE);
964 }
965
966 return S_OK;
967}
968
969STDMETHODIMP VRDEServer::COMGETTER(VRDEExtPack) (BSTR *aExtPack)
970{
971 CheckComArgOutPointerValid(aExtPack);
972
973 AutoCaller autoCaller(this);
974 HRESULT hrc = autoCaller.rc();
975 if (SUCCEEDED(hrc))
976 {
977 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
978 Utf8Str strExtPack = mData->mVrdeExtPack;
979 alock.release();
980
981 if (strExtPack.isNotEmpty())
982 {
983 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
984 hrc = S_OK;
985 else
986 {
987#ifdef VBOX_WITH_EXTPACK
988 ExtPackManager *pExtPackMgr = mParent->getVirtualBox()->getExtPackManager();
989 hrc = pExtPackMgr->checkVrdeExtPack(&strExtPack);
990#else
991 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), strExtPack.c_str());
992#endif
993 }
994 if (SUCCEEDED(hrc))
995 strExtPack.cloneTo(aExtPack);
996 }
997 else
998 {
999 /* Get the global setting. */
1000 ComPtr<ISystemProperties> systemProperties;
1001 hrc = mParent->getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
1002 if (SUCCEEDED(hrc))
1003 hrc = systemProperties->COMGETTER(DefaultVRDEExtPack)(aExtPack);
1004 }
1005 }
1006
1007 return hrc;
1008}
1009
1010STDMETHODIMP VRDEServer::COMSETTER(VRDEExtPack)(IN_BSTR aExtPack)
1011{
1012 CheckComArgNotNull(aExtPack);
1013 Utf8Str strExtPack(aExtPack);
1014
1015 AutoCaller autoCaller(this);
1016 HRESULT hrc = autoCaller.rc();
1017 if (SUCCEEDED(hrc))
1018 {
1019 /* the machine needs to be mutable */
1020 AutoMutableStateDependency adep(mParent);
1021 hrc = adep.rc();
1022 if (SUCCEEDED(hrc))
1023 {
1024 /*
1025 * If not empty, check the specific extension pack.
1026 */
1027 if (!strExtPack.isEmpty())
1028 {
1029 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
1030 hrc = S_OK;
1031 else
1032 {
1033#ifdef VBOX_WITH_EXTPACK
1034 ExtPackManager *pExtPackMgr = mParent->getVirtualBox()->getExtPackManager();
1035 hrc = pExtPackMgr->checkVrdeExtPack(&strExtPack);
1036#else
1037 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), strExtPack.c_str());
1038#endif
1039 }
1040 }
1041 if (SUCCEEDED(hrc))
1042 {
1043 /*
1044 * Update the setting if there is an actual change, post an
1045 * change event to trigger a VRDE server restart.
1046 */
1047 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1048 if (strExtPack != mData->mVrdeExtPack)
1049 {
1050 mData.backup();
1051 mData->mVrdeExtPack = strExtPack;
1052
1053 /* leave the lock before informing callbacks */
1054 alock.release();
1055
1056 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
1057 mParent->setModified(Machine::IsModified_VRDEServer);
1058 mlock.release();
1059
1060 mParent->onVRDEServerChange(/* aRestart */ TRUE);
1061 }
1062 }
1063 }
1064 }
1065
1066 return hrc;
1067}
1068
1069// public methods only for internal purposes
1070/////////////////////////////////////////////////////////////////////////////
1071
1072/**
1073 * @note Locks this object for writing.
1074 */
1075void VRDEServer::rollback()
1076{
1077 /* sanity */
1078 AutoCaller autoCaller(this);
1079 AssertComRCReturnVoid(autoCaller.rc());
1080
1081 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1082
1083 mData.rollback();
1084}
1085
1086/**
1087 * @note Locks this object for writing, together with the peer object (also
1088 * for writing) if there is one.
1089 */
1090void VRDEServer::commit()
1091{
1092 /* sanity */
1093 AutoCaller autoCaller(this);
1094 AssertComRCReturnVoid (autoCaller.rc());
1095
1096 /* sanity too */
1097 AutoCaller peerCaller (mPeer);
1098 AssertComRCReturnVoid (peerCaller.rc());
1099
1100 /* lock both for writing since we modify both (mPeer is "master" so locked
1101 * first) */
1102 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
1103
1104 if (mData.isBackedUp())
1105 {
1106 mData.commit();
1107 if (mPeer)
1108 {
1109 /* attach new data to the peer and reshare it */
1110 mPeer->mData.attach (mData);
1111 }
1112 }
1113}
1114
1115/**
1116 * @note Locks this object for writing, together with the peer object
1117 * represented by @a aThat (locked for reading).
1118 */
1119void VRDEServer::copyFrom (VRDEServer *aThat)
1120{
1121 AssertReturnVoid (aThat != NULL);
1122
1123 /* sanity */
1124 AutoCaller autoCaller(this);
1125 AssertComRCReturnVoid (autoCaller.rc());
1126
1127 /* sanity too */
1128 AutoCaller thatCaller (aThat);
1129 AssertComRCReturnVoid (thatCaller.rc());
1130
1131 /* peer is not modified, lock it for reading (aThat is "master" so locked
1132 * first) */
1133 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1134 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1135
1136 /* this will back up current data */
1137 mData.assignCopy (aThat->mData);
1138}
1139/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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