VirtualBox

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

Last change on this file since 50403 was 50355, checked in by vboxsync, 11 years ago

6813 stage 7 VirtualBoxImpl.cpp etc

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.1 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2013 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#include <VBox/com/array.h>
33
34#include <VBox/RemoteDesktop/VRDE.h>
35
36#include "AutoStateDep.h"
37#include "AutoCaller.h"
38#include "Global.h"
39#include "Logging.h"
40
41// defines
42/////////////////////////////////////////////////////////////////////////////
43#define VRDP_DEFAULT_PORT_STR "3389"
44
45// constructor / destructor
46/////////////////////////////////////////////////////////////////////////////
47
48VRDEServer::VRDEServer()
49 : mParent(NULL)
50{
51}
52
53VRDEServer::~VRDEServer()
54{
55}
56
57HRESULT VRDEServer::FinalConstruct()
58{
59 return BaseFinalConstruct();
60}
61
62void VRDEServer::FinalRelease()
63{
64 uninit();
65 BaseFinalRelease();
66}
67
68// public initializer/uninitializer for internal purposes only
69/////////////////////////////////////////////////////////////////////////////
70
71/**
72 * Initializes the VRDP server object.
73 *
74 * @param aParent Handle of the parent object.
75 */
76HRESULT VRDEServer::init(Machine *aParent)
77{
78 LogFlowThisFunc(("aParent=%p\n", aParent));
79
80 ComAssertRet(aParent, E_INVALIDARG);
81
82 /* Enclose the state transition NotReady->InInit->Ready */
83 AutoInitSpan autoInitSpan(this);
84 AssertReturn(autoInitSpan.isOk(), E_FAIL);
85
86 unconst(mParent) = aParent;
87 /* mPeer is left null */
88
89 mData.allocate();
90
91 mData->mAuthType = AuthType_Null;
92 mData->mAuthTimeout = 0;
93 mData->mAuthLibrary.setNull();
94 mData->mEnabled = FALSE;
95 mData->mAllowMultiConnection = FALSE;
96 mData->mReuseSingleConnection = FALSE;
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::i_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 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::i_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
248HRESULT VRDEServer::getEnabled(BOOL *aEnabled)
249{
250 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
251
252 *aEnabled = mData->mEnabled;
253
254 return S_OK;
255}
256
257HRESULT VRDEServer::setEnabled(BOOL aEnabled)
258{
259 /* the machine can also be in saved state for this property to change */
260 AutoMutableOrSavedStateDependency adep(mParent);
261 if (FAILED(adep.rc())) return adep.rc();
262
263 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
264
265 HRESULT rc = S_OK;
266
267 if (mData->mEnabled != aEnabled)
268 {
269 mData.backup();
270 mData->mEnabled = aEnabled;
271
272 /* leave the lock before informing callbacks */
273 alock.release();
274
275 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
276 mParent->setModified(Machine::IsModified_VRDEServer);
277 mlock.release();
278
279 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
280 adep.release();
281
282 rc = mParent->onVRDEServerChange(/* aRestart */ TRUE);
283 }
284
285 return rc;
286}
287
288static int i_portParseNumber(uint16_t *pu16Port, const char *pszStart, const char *pszEnd)
289{
290 /* Gets a string of digits, converts to 16 bit port number.
291 * Note: pszStart <= pszEnd is expected, the string contains
292 * only digits and pszEnd points to the char after last
293 * digit.
294 */
295 int cch = pszEnd - pszStart;
296 if (cch > 0 && cch <= 5) /* Port is up to 5 decimal digits. */
297 {
298 unsigned uPort = 0;
299 while (pszStart != pszEnd)
300 {
301 uPort = uPort * 10 + *pszStart - '0';
302 pszStart++;
303 }
304
305 if (uPort != 0 && uPort < 0x10000)
306 {
307 if (pu16Port)
308 *pu16Port = (uint16_t)uPort;
309 return VINF_SUCCESS;
310 }
311 }
312
313 return VERR_INVALID_PARAMETER;
314}
315
316static int i_vrdpServerVerifyPortsString(com::Utf8Str portRange)
317{
318 const char *pszPortRange = portRange.c_str();
319
320 if (!pszPortRange || *pszPortRange == 0) /* Reject empty string. */
321 return VERR_INVALID_PARAMETER;
322
323 /* The string should be like "1000-1010,1020,2000-2003" */
324 while (*pszPortRange)
325 {
326 const char *pszStart = pszPortRange;
327 const char *pszDash = NULL;
328 const char *pszEnd = pszStart;
329
330 while (*pszEnd && *pszEnd != ',')
331 {
332 if (*pszEnd == '-')
333 {
334 if (pszDash != NULL)
335 return VERR_INVALID_PARAMETER; /* More than one '-'. */
336
337 pszDash = pszEnd;
338 }
339 else if (!RT_C_IS_DIGIT(*pszEnd))
340 return VERR_INVALID_PARAMETER;
341
342 pszEnd++;
343 }
344
345 /* Update the next range pointer. */
346 pszPortRange = pszEnd;
347 if (*pszPortRange == ',')
348 {
349 pszPortRange++;
350 }
351
352 /* A probably valid range. Verify and parse it. */
353 int rc;
354 if (pszDash)
355 {
356 rc = i_portParseNumber(NULL, pszStart, pszDash);
357 if (RT_SUCCESS(rc))
358 rc = i_portParseNumber(NULL, pszDash + 1, pszEnd);
359 }
360 else
361 rc = i_portParseNumber(NULL, pszStart, pszEnd);
362
363 if (RT_FAILURE(rc))
364 return rc;
365 }
366
367 return VINF_SUCCESS;
368}
369
370HRESULT VRDEServer::setVRDEProperty(const com::Utf8Str &aKey, const com::Utf8Str &aValue)
371{
372 LogFlowThisFunc(("\n"));
373
374 /* the machine can also be in saved state for this property to change */
375 AutoMutableOrSavedStateDependency adep(mParent);
376 if (FAILED(adep.rc())) return adep.rc();
377
378 Bstr key = aKey;
379
380 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
381
382 /* Special processing for some "standard" properties. */
383 if (key == Bstr("TCP/Ports"))
384 {
385 /* Verify the string. */
386 int vrc = i_vrdpServerVerifyPortsString(aValue);
387 if (RT_FAILURE(vrc))
388 return E_INVALIDARG;
389
390 if (aValue != mData->mProperties["TCP/Ports"])
391 {
392 /* Port value is not verified here because it is up to VRDP transport to
393 * use it. Specifying a wrong port number will cause a running server to
394 * stop. There is no fool proof here.
395 */
396 mData.backup();
397 if (aValue == Utf8Str("0"))
398 mData->mProperties["TCP/Ports"] = VRDP_DEFAULT_PORT_STR;
399 else
400 mData->mProperties["TCP/Ports"] = aValue;
401
402 /* leave the lock before informing callbacks */
403 alock.release();
404
405 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
406 mParent->setModified(Machine::IsModified_VRDEServer);
407 mlock.release();
408
409 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
410 adep.release();
411
412 mParent->onVRDEServerChange(/* aRestart */ TRUE);
413 }
414 }
415 else
416 {
417 /* Generic properties processing.
418 * Look up the old value first; if nothing's changed then do nothing.
419 */
420 Utf8Str strOldValue;
421
422 settings::StringsMap::const_iterator it = mData->mProperties.find(aKey);
423 if (it != mData->mProperties.end())
424 strOldValue = it->second;
425
426 if (strOldValue != aValue)
427 {
428 if (aValue.isEmpty())
429 mData->mProperties.erase(aKey);
430 else
431 mData->mProperties[aKey] = aValue;
432
433 /* leave the lock before informing callbacks */
434 alock.release();
435
436 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
437 mParent->setModified(Machine::IsModified_VRDEServer);
438 mlock.release();
439
440 /* Avoid deadlock when onVRDEServerChange eventually calls SetExtraData. */
441 adep.release();
442
443 mParent->onVRDEServerChange(/* aRestart */ TRUE);
444 }
445 }
446
447 return S_OK;
448}
449
450HRESULT VRDEServer::getVRDEProperty(const com::Utf8Str &aKey, com::Utf8Str &aValue)
451{
452 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
453 settings::StringsMap::const_iterator it = mData->mProperties.find(aKey);
454 if (it != mData->mProperties.end())
455 aValue = it->second; // source is a Utf8Str
456 else if (aKey == "TCP/Ports")
457 aValue = VRDP_DEFAULT_PORT_STR;
458
459 return S_OK;
460}
461
462static int loadVRDELibrary(const char *pszLibraryName, RTLDRMOD *phmod, PFNVRDESUPPORTEDPROPERTIES *ppfn)
463{
464 int rc = VINF_SUCCESS;
465
466 RTLDRMOD hmod = NIL_RTLDRMOD;
467
468 RTERRINFOSTATIC ErrInfo;
469 RTErrInfoInitStatic(&ErrInfo);
470 if (RTPathHavePath(pszLibraryName))
471 rc = SUPR3HardenedLdrLoadPlugIn(pszLibraryName, &hmod, &ErrInfo.Core);
472 else
473 rc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &hmod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
474 if (RT_SUCCESS(rc))
475 {
476 rc = RTLdrGetSymbol(hmod, "VRDESupportedProperties", (void **)ppfn);
477
478 if (RT_FAILURE(rc) && rc != VERR_SYMBOL_NOT_FOUND)
479 LogRel(("VRDE: Error resolving symbol '%s', rc %Rrc.\n", "VRDESupportedProperties", rc));
480 }
481 else
482 {
483 if (RTErrInfoIsSet(&ErrInfo.Core))
484 LogRel(("VRDE: Error loading the library '%s': %s (%Rrc)\n", pszLibraryName, ErrInfo.Core.pszMsg, rc));
485 else
486 LogRel(("VRDE: Error loading the library '%s' rc = %Rrc.\n", pszLibraryName, rc));
487
488 hmod = NIL_RTLDRMOD;
489 }
490
491 if (RT_SUCCESS(rc))
492 {
493 *phmod = hmod;
494 }
495 else
496 {
497 if (hmod != NIL_RTLDRMOD)
498 {
499 RTLdrClose(hmod);
500 hmod = NIL_RTLDRMOD;
501 }
502 }
503
504 return rc;
505}
506
507HRESULT VRDEServer::getVRDEProperties(std::vector<com::Utf8Str> &aProperties)
508{
509 size_t cProperties = 0;
510 aProperties.resize(0);
511 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
512 if (!mData->mEnabled)
513 {
514 return S_OK;
515 }
516 alock.release();
517
518 /*
519 * Check that a VRDE extension pack name is set and resolve it into a
520 * library path.
521 */
522 Bstr bstrExtPack;
523 HRESULT hrc = COMGETTER(VRDEExtPack)(bstrExtPack.asOutParam());
524 Log(("VRDEPROP: get extpack hrc 0x%08X, isEmpty %d\n", hrc, bstrExtPack.isEmpty()));
525 if (FAILED(hrc))
526 return hrc;
527 if (bstrExtPack.isEmpty())
528 return E_FAIL;
529
530 Utf8Str strExtPack(bstrExtPack);
531 Utf8Str strVrdeLibrary;
532 int vrc = VINF_SUCCESS;
533 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
534 strVrdeLibrary = "VBoxVRDP";
535 else
536 {
537#ifdef VBOX_WITH_EXTPACK
538 VirtualBox *pVirtualBox = mParent->getVirtualBox();
539 ExtPackManager *pExtPackMgr = pVirtualBox->i_getExtPackManager();
540 vrc = pExtPackMgr->getVrdeLibraryPathForExtPack(&strExtPack, &strVrdeLibrary);
541#else
542 vrc = VERR_FILE_NOT_FOUND;
543#endif
544 }
545 Log(("VRDEPROP: library get rc %Rrc\n", vrc));
546
547 if (RT_SUCCESS(vrc))
548 {
549 /*
550 * Load the VRDE library and start the server, if it is enabled.
551 */
552 PFNVRDESUPPORTEDPROPERTIES pfn = NULL;
553 RTLDRMOD hmod = NIL_RTLDRMOD;
554 vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, &pfn);
555 Log(("VRDEPROP: load library [%s] rc %Rrc\n", strVrdeLibrary.c_str(), vrc));
556 if (RT_SUCCESS(vrc))
557 {
558 const char * const *papszNames = pfn();
559
560 if (papszNames)
561 {
562 size_t i;
563 for (i = 0; papszNames[i] != NULL; ++i)
564 {
565 cProperties++;
566 }
567 }
568 Log(("VRDEPROP: %d properties\n", cProperties));
569
570 if (cProperties > 0)
571 {
572 aProperties.resize(cProperties);
573 for (size_t i = 0; papszNames[i] != NULL && i < cProperties; ++i)
574 {
575 aProperties[i] = papszNames[i];
576 }
577 }
578
579 /* Do not forget to unload the library. */
580 RTLdrClose(hmod);
581 hmod = NIL_RTLDRMOD;
582 }
583 }
584
585 if (RT_FAILURE(vrc))
586 {
587 return E_FAIL;
588 }
589
590 return S_OK;
591}
592
593
594HRESULT VRDEServer::getAuthType(AuthType_T *aType)
595{
596 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
597
598 *aType = mData->mAuthType;
599
600 return S_OK;
601}
602
603HRESULT VRDEServer::setAuthType(AuthType_T aType)
604{
605 /* the machine can also be in saved state for this property to change */
606 AutoMutableOrSavedStateDependency adep(mParent);
607 if (FAILED(adep.rc())) return adep.rc();
608
609 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
610
611 if (mData->mAuthType != aType)
612 {
613 mData.backup();
614 mData->mAuthType = aType;
615
616 /* leave the lock before informing callbacks */
617 alock.release();
618
619 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
620 mParent->setModified(Machine::IsModified_VRDEServer);
621 mlock.release();
622
623 mParent->onVRDEServerChange(/* aRestart */ TRUE);
624 }
625
626 return S_OK;
627}
628
629HRESULT VRDEServer::getAuthTimeout(ULONG *aTimeout)
630{
631 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
632
633 *aTimeout = mData->mAuthTimeout;
634
635 return S_OK;
636}
637
638
639HRESULT VRDEServer::setAuthTimeout(ULONG aTimeout)
640{
641 /* the machine can also be in saved state for this property to change */
642 AutoMutableOrSavedStateDependency adep(mParent);
643 if (FAILED(adep.rc())) return adep.rc();
644
645 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
646
647 if (aTimeout != mData->mAuthTimeout)
648 {
649 mData.backup();
650 mData->mAuthTimeout = aTimeout;
651
652 /* leave the lock before informing callbacks */
653 alock.release();
654
655 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
656 mParent->setModified(Machine::IsModified_VRDEServer);
657 mlock.release();
658
659 /* sunlover 20060131: This setter does not require the notification
660 * really */
661#if 0
662 mParent->onVRDEServerChange();
663#endif
664 }
665
666 return S_OK;
667}
668
669HRESULT VRDEServer::getAuthLibrary(com::Utf8Str &aLibrary)
670{
671 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
672 aLibrary = mData->mAuthLibrary;
673 alock.release();
674
675 if (aLibrary.isEmpty())
676 {
677 /* Get the global setting. */
678 ComPtr<ISystemProperties> systemProperties;
679 HRESULT hrc = mParent->getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
680 if (SUCCEEDED(hrc))
681 {
682 Bstr strlib;
683 hrc = systemProperties->COMGETTER(VRDEAuthLibrary)(strlib.asOutParam());
684 if (SUCCEEDED(hrc))
685 aLibrary = Utf8Str(strlib).c_str();
686 }
687
688 if (FAILED(hrc))
689 return setError(hrc, "failed to query the library setting\n");
690 }
691
692 return S_OK;
693}
694
695
696HRESULT VRDEServer::setAuthLibrary(const com::Utf8Str &aLibrary)
697{
698 /* the machine can also be in saved state for this property to change */
699 AutoMutableOrSavedStateDependency adep(mParent);
700 if (FAILED(adep.rc())) return adep.rc();
701
702 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
703
704 if (mData->mAuthLibrary != aLibrary)
705 {
706 mData.backup();
707 mData->mAuthLibrary = aLibrary;
708
709 /* leave the lock before informing callbacks */
710 alock.release();
711
712 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
713 mParent->setModified(Machine::IsModified_VRDEServer);
714 mlock.release();
715
716 mParent->onVRDEServerChange(/* aRestart */ TRUE);
717 }
718
719 return S_OK;
720}
721
722
723HRESULT VRDEServer::getAllowMultiConnection(BOOL *aAllowMultiConnection)
724{
725 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
726
727 *aAllowMultiConnection = mData->mAllowMultiConnection;
728
729 return S_OK;
730}
731
732
733HRESULT VRDEServer::setAllowMultiConnection(BOOL aAllowMultiConnection)
734{
735 /* the machine can also be in saved state for this property to change */
736 AutoMutableOrSavedStateDependency adep(mParent);
737 if (FAILED(adep.rc())) return adep.rc();
738
739 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
740
741 if (mData->mAllowMultiConnection != aAllowMultiConnection)
742 {
743 mData.backup();
744 mData->mAllowMultiConnection = aAllowMultiConnection;
745
746 /* leave the lock before informing callbacks */
747 alock.release();
748
749 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
750 mParent->setModified(Machine::IsModified_VRDEServer);
751 mlock.release();
752
753 mParent->onVRDEServerChange(/* aRestart */ TRUE); // @todo does it need a restart?
754 }
755
756 return S_OK;
757}
758
759HRESULT VRDEServer::getReuseSingleConnection(BOOL *aReuseSingleConnection)
760{
761 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
762
763 *aReuseSingleConnection = mData->mReuseSingleConnection;
764
765 return S_OK;
766}
767
768
769HRESULT VRDEServer::setReuseSingleConnection(BOOL aReuseSingleConnection)
770{
771 AutoMutableOrSavedStateDependency adep(mParent);
772 if (FAILED(adep.rc())) return adep.rc();
773
774 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
775
776 if (mData->mReuseSingleConnection != aReuseSingleConnection)
777 {
778 mData.backup();
779 mData->mReuseSingleConnection = aReuseSingleConnection;
780
781 /* leave the lock before informing callbacks */
782 alock.release();
783
784 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
785 mParent->setModified(Machine::IsModified_VRDEServer);
786 mlock.release();
787
788 mParent->onVRDEServerChange(/* aRestart */ TRUE); // @todo needs a restart?
789 }
790
791 return S_OK;
792}
793
794HRESULT VRDEServer::getVRDEExtPack(com::Utf8Str &aExtPack)
795{
796 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
797 Utf8Str strExtPack = mData->mVrdeExtPack;
798 alock.release();
799 HRESULT hrc = S_OK;
800
801 if (strExtPack.isNotEmpty())
802 {
803 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
804 hrc = S_OK;
805 else
806 {
807#ifdef VBOX_WITH_EXTPACK
808 ExtPackManager *pExtPackMgr = mParent->getVirtualBox()->i_getExtPackManager();
809 hrc = pExtPackMgr->checkVrdeExtPack(&strExtPack);
810#else
811 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), strExtPack.c_str());
812#endif
813 }
814 if (SUCCEEDED(hrc))
815 aExtPack = strExtPack;
816 }
817 else
818 {
819 /* Get the global setting. */
820 ComPtr<ISystemProperties> systemProperties;
821 hrc = mParent->getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
822 if (SUCCEEDED(hrc))
823 {
824 BSTR bstr;
825 hrc = systemProperties->COMGETTER(DefaultVRDEExtPack)(&bstr);
826 if (SUCCEEDED(hrc))
827 aExtPack = Utf8Str(bstr);
828 }
829 }
830 return hrc;
831}
832
833// public methods only for internal purposes
834/////////////////////////////////////////////////////////////////////////////
835HRESULT VRDEServer::setVRDEExtPack(const com::Utf8Str &aExtPack)
836{
837 HRESULT hrc = S_OK;
838 /* the machine can also be in saved state for this property to change */
839 AutoMutableOrSavedStateDependency adep(mParent);
840 hrc = adep.rc();
841 if (SUCCEEDED(hrc))
842 {
843 /*
844 * If not empty, check the specific extension pack.
845 */
846 if (!aExtPack.isEmpty())
847 {
848 if (aExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
849 hrc = S_OK;
850 else
851 {
852#ifdef VBOX_WITH_EXTPACK
853 ExtPackManager *pExtPackMgr = mParent->getVirtualBox()->i_getExtPackManager();
854 hrc = pExtPackMgr->checkVrdeExtPack(&aExtPack);
855#else
856 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), aExtPack.c_str());
857#endif
858 }
859 }
860 if (SUCCEEDED(hrc))
861 {
862 /*
863 * Update the setting if there is an actual change, post an
864 * change event to trigger a VRDE server restart.
865 */
866 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
867 if (aExtPack != mData->mVrdeExtPack)
868 {
869 mData.backup();
870 mData->mVrdeExtPack = aExtPack;
871
872 /* leave the lock before informing callbacks */
873 alock.release();
874
875 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
876 mParent->setModified(Machine::IsModified_VRDEServer);
877 mlock.release();
878
879 mParent->onVRDEServerChange(/* aRestart */ TRUE);
880 }
881 }
882 }
883
884 return hrc;
885}
886
887// public methods only for internal purposes
888/////////////////////////////////////////////////////////////////////////////
889
890/**
891 * @note Locks this object for writing.
892 */
893void VRDEServer::i_rollback()
894{
895 /* sanity */
896 AutoCaller autoCaller(this);
897 AssertComRCReturnVoid(autoCaller.rc());
898
899 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
900
901 mData.rollback();
902}
903
904/**
905 * @note Locks this object for writing, together with the peer object (also
906 * for writing) if there is one.
907 */
908void VRDEServer::i_commit()
909{
910 /* sanity */
911 AutoCaller autoCaller(this);
912 AssertComRCReturnVoid(autoCaller.rc());
913
914 /* sanity too */
915 AutoCaller peerCaller(mPeer);
916 AssertComRCReturnVoid(peerCaller.rc());
917
918 /* lock both for writing since we modify both (mPeer is "master" so locked
919 * first) */
920 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
921
922 if (mData.isBackedUp())
923 {
924 mData.commit();
925 if (mPeer)
926 {
927 /* attach new data to the peer and reshare it */
928 mPeer->mData.attach(mData);
929 }
930 }
931}
932
933/**
934 * @note Locks this object for writing, together with the peer object
935 * represented by @a aThat (locked for reading).
936 */
937void VRDEServer::i_copyFrom(VRDEServer *aThat)
938{
939 AssertReturnVoid(aThat != NULL);
940
941 /* sanity */
942 AutoCaller autoCaller(this);
943 AssertComRCReturnVoid(autoCaller.rc());
944
945 /* sanity too */
946 AutoCaller thatCaller(aThat);
947 AssertComRCReturnVoid(thatCaller.rc());
948
949 /* peer is not modified, lock it for reading (aThat is "master" so locked
950 * first) */
951 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
952 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
953
954 /* this will back up current data */
955 mData.assignCopy(aThat->mData);
956}
957/* 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