VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/VRDEServerImpl.cpp@ 37989

Last change on this file since 37989 was 37700, checked in by vboxsync, 13 years ago

Main/VRDEServer: fix GetVRDEProperty method, for unknown values it might return garbage

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