VirtualBox

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

Last change on this file since 62890 was 61624, checked in by vboxsync, 8 years ago

Main: fixed lock ordering

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