VirtualBox

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

Last change on this file since 53624 was 53344, checked in by vboxsync, 10 years ago

Main: VRDEServer property TCP/Ports should accept 0 as default value

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.2 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2014 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->i_setModified(Machine::IsModified_VRDEServer);
277 mlock.release();
278
279 /* Avoid deadlock when i_onVRDEServerChange eventually calls SetExtraData. */
280 adep.release();
281
282 rc = mParent->i_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 size_t 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 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
379
380 /* Special processing for some "standard" properties. */
381 if (aKey == "TCP/Ports")
382 {
383 /* Verify the string. "0" means the default port. */
384 Utf8Str strPorts = aValue == "0"?
385 VRDP_DEFAULT_PORT_STR:
386 aValue;
387 int vrc = i_vrdpServerVerifyPortsString(strPorts);
388 if (RT_FAILURE(vrc))
389 return E_INVALIDARG;
390
391 if (strPorts != mData->mProperties["TCP/Ports"])
392 {
393 /* Port value is not verified here because it is up to VRDP transport to
394 * use it. Specifying a wrong port number will cause a running server to
395 * stop. There is no fool proof here.
396 */
397 mData.backup();
398 mData->mProperties["TCP/Ports"] = strPorts;
399
400 /* leave the lock before informing callbacks */
401 alock.release();
402
403 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
404 mParent->i_setModified(Machine::IsModified_VRDEServer);
405 mlock.release();
406
407 /* Avoid deadlock when i_onVRDEServerChange eventually calls SetExtraData. */
408 adep.release();
409
410 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
411 }
412 }
413 else
414 {
415 /* Generic properties processing.
416 * Look up the old value first; if nothing's changed then do nothing.
417 */
418 Utf8Str strOldValue;
419
420 settings::StringsMap::const_iterator it = mData->mProperties.find(aKey);
421 if (it != mData->mProperties.end())
422 strOldValue = it->second;
423
424 if (strOldValue != aValue)
425 {
426 if (aValue.isEmpty())
427 mData->mProperties.erase(aKey);
428 else
429 mData->mProperties[aKey] = aValue;
430
431 /* leave the lock before informing callbacks */
432 alock.release();
433
434 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
435 mParent->i_setModified(Machine::IsModified_VRDEServer);
436 mlock.release();
437
438 /* Avoid deadlock when i_onVRDEServerChange eventually calls SetExtraData. */
439 adep.release();
440
441 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
442 }
443 }
444
445 return S_OK;
446}
447
448HRESULT VRDEServer::getVRDEProperty(const com::Utf8Str &aKey, com::Utf8Str &aValue)
449{
450 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
451 settings::StringsMap::const_iterator it = mData->mProperties.find(aKey);
452 if (it != mData->mProperties.end())
453 aValue = it->second; // source is a Utf8Str
454 else if (aKey == "TCP/Ports")
455 aValue = VRDP_DEFAULT_PORT_STR;
456
457 return S_OK;
458}
459
460static int loadVRDELibrary(const char *pszLibraryName, RTLDRMOD *phmod, PFNVRDESUPPORTEDPROPERTIES *ppfn)
461{
462 int rc = VINF_SUCCESS;
463
464 RTLDRMOD hmod = NIL_RTLDRMOD;
465
466 RTERRINFOSTATIC ErrInfo;
467 RTErrInfoInitStatic(&ErrInfo);
468 if (RTPathHavePath(pszLibraryName))
469 rc = SUPR3HardenedLdrLoadPlugIn(pszLibraryName, &hmod, &ErrInfo.Core);
470 else
471 rc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &hmod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
472 if (RT_SUCCESS(rc))
473 {
474 rc = RTLdrGetSymbol(hmod, "VRDESupportedProperties", (void **)ppfn);
475
476 if (RT_FAILURE(rc) && rc != VERR_SYMBOL_NOT_FOUND)
477 LogRel(("VRDE: Error resolving symbol '%s', rc %Rrc.\n", "VRDESupportedProperties", rc));
478 }
479 else
480 {
481 if (RTErrInfoIsSet(&ErrInfo.Core))
482 LogRel(("VRDE: Error loading the library '%s': %s (%Rrc)\n", pszLibraryName, ErrInfo.Core.pszMsg, rc));
483 else
484 LogRel(("VRDE: Error loading the library '%s' rc = %Rrc.\n", pszLibraryName, rc));
485
486 hmod = NIL_RTLDRMOD;
487 }
488
489 if (RT_SUCCESS(rc))
490 {
491 *phmod = hmod;
492 }
493 else
494 {
495 if (hmod != NIL_RTLDRMOD)
496 {
497 RTLdrClose(hmod);
498 hmod = NIL_RTLDRMOD;
499 }
500 }
501
502 return rc;
503}
504
505HRESULT VRDEServer::getVRDEProperties(std::vector<com::Utf8Str> &aProperties)
506{
507 size_t cProperties = 0;
508 aProperties.resize(0);
509 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
510 if (!mData->mEnabled)
511 {
512 return S_OK;
513 }
514 alock.release();
515
516 /*
517 * Check that a VRDE extension pack name is set and resolve it into a
518 * library path.
519 */
520 Bstr bstrExtPack;
521 HRESULT hrc = COMGETTER(VRDEExtPack)(bstrExtPack.asOutParam());
522 Log(("VRDEPROP: get extpack hrc 0x%08X, isEmpty %d\n", hrc, bstrExtPack.isEmpty()));
523 if (FAILED(hrc))
524 return hrc;
525 if (bstrExtPack.isEmpty())
526 return E_FAIL;
527
528 Utf8Str strExtPack(bstrExtPack);
529 Utf8Str strVrdeLibrary;
530 int vrc = VINF_SUCCESS;
531 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
532 strVrdeLibrary = "VBoxVRDP";
533 else
534 {
535#ifdef VBOX_WITH_EXTPACK
536 VirtualBox *pVirtualBox = mParent->i_getVirtualBox();
537 ExtPackManager *pExtPackMgr = pVirtualBox->i_getExtPackManager();
538 vrc = pExtPackMgr->i_getVrdeLibraryPathForExtPack(&strExtPack, &strVrdeLibrary);
539#else
540 vrc = VERR_FILE_NOT_FOUND;
541#endif
542 }
543 Log(("VRDEPROP: library get rc %Rrc\n", vrc));
544
545 if (RT_SUCCESS(vrc))
546 {
547 /*
548 * Load the VRDE library and start the server, if it is enabled.
549 */
550 PFNVRDESUPPORTEDPROPERTIES pfn = NULL;
551 RTLDRMOD hmod = NIL_RTLDRMOD;
552 vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, &pfn);
553 Log(("VRDEPROP: load library [%s] rc %Rrc\n", strVrdeLibrary.c_str(), vrc));
554 if (RT_SUCCESS(vrc))
555 {
556 const char * const *papszNames = pfn();
557
558 if (papszNames)
559 {
560 size_t i;
561 for (i = 0; papszNames[i] != NULL; ++i)
562 {
563 cProperties++;
564 }
565 }
566 Log(("VRDEPROP: %d properties\n", cProperties));
567
568 if (cProperties > 0)
569 {
570 aProperties.resize(cProperties);
571 for (size_t i = 0; papszNames[i] != NULL && i < cProperties; ++i)
572 {
573 aProperties[i] = papszNames[i];
574 }
575 }
576
577 /* Do not forget to unload the library. */
578 RTLdrClose(hmod);
579 hmod = NIL_RTLDRMOD;
580 }
581 }
582
583 if (RT_FAILURE(vrc))
584 {
585 return E_FAIL;
586 }
587
588 return S_OK;
589}
590
591
592HRESULT VRDEServer::getAuthType(AuthType_T *aType)
593{
594 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
595
596 *aType = mData->mAuthType;
597
598 return S_OK;
599}
600
601HRESULT VRDEServer::setAuthType(AuthType_T aType)
602{
603 /* the machine can also be in saved state for this property to change */
604 AutoMutableOrSavedStateDependency adep(mParent);
605 if (FAILED(adep.rc())) return adep.rc();
606
607 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
608
609 if (mData->mAuthType != aType)
610 {
611 mData.backup();
612 mData->mAuthType = aType;
613
614 /* leave the lock before informing callbacks */
615 alock.release();
616
617 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
618 mParent->i_setModified(Machine::IsModified_VRDEServer);
619 mlock.release();
620
621 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
622 }
623
624 return S_OK;
625}
626
627HRESULT VRDEServer::getAuthTimeout(ULONG *aTimeout)
628{
629 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
630
631 *aTimeout = mData->mAuthTimeout;
632
633 return S_OK;
634}
635
636
637HRESULT VRDEServer::setAuthTimeout(ULONG aTimeout)
638{
639 /* the machine can also be in saved state for this property to change */
640 AutoMutableOrSavedStateDependency adep(mParent);
641 if (FAILED(adep.rc())) return adep.rc();
642
643 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
644
645 if (aTimeout != mData->mAuthTimeout)
646 {
647 mData.backup();
648 mData->mAuthTimeout = aTimeout;
649
650 /* leave the lock before informing callbacks */
651 alock.release();
652
653 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
654 mParent->i_setModified(Machine::IsModified_VRDEServer);
655 mlock.release();
656
657 /* sunlover 20060131: This setter does not require the notification
658 * really */
659#if 0
660 mParent->onVRDEServerChange();
661#endif
662 }
663
664 return S_OK;
665}
666
667HRESULT VRDEServer::getAuthLibrary(com::Utf8Str &aLibrary)
668{
669 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
670 aLibrary = mData->mAuthLibrary;
671 alock.release();
672
673 if (aLibrary.isEmpty())
674 {
675 /* Get the global setting. */
676 ComPtr<ISystemProperties> systemProperties;
677 HRESULT hrc = mParent->i_getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
678 if (SUCCEEDED(hrc))
679 {
680 Bstr strlib;
681 hrc = systemProperties->COMGETTER(VRDEAuthLibrary)(strlib.asOutParam());
682 if (SUCCEEDED(hrc))
683 aLibrary = Utf8Str(strlib).c_str();
684 }
685
686 if (FAILED(hrc))
687 return setError(hrc, "failed to query the library setting\n");
688 }
689
690 return S_OK;
691}
692
693
694HRESULT VRDEServer::setAuthLibrary(const com::Utf8Str &aLibrary)
695{
696 /* the machine can also be in saved state for this property to change */
697 AutoMutableOrSavedStateDependency adep(mParent);
698 if (FAILED(adep.rc())) return adep.rc();
699
700 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
701
702 if (mData->mAuthLibrary != aLibrary)
703 {
704 mData.backup();
705 mData->mAuthLibrary = aLibrary;
706
707 /* leave the lock before informing callbacks */
708 alock.release();
709
710 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
711 mParent->i_setModified(Machine::IsModified_VRDEServer);
712 mlock.release();
713
714 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
715 }
716
717 return S_OK;
718}
719
720
721HRESULT VRDEServer::getAllowMultiConnection(BOOL *aAllowMultiConnection)
722{
723 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
724
725 *aAllowMultiConnection = mData->mAllowMultiConnection;
726
727 return S_OK;
728}
729
730
731HRESULT VRDEServer::setAllowMultiConnection(BOOL aAllowMultiConnection)
732{
733 /* the machine can also be in saved state for this property to change */
734 AutoMutableOrSavedStateDependency adep(mParent);
735 if (FAILED(adep.rc())) return adep.rc();
736
737 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
738
739 if (mData->mAllowMultiConnection != aAllowMultiConnection)
740 {
741 mData.backup();
742 mData->mAllowMultiConnection = aAllowMultiConnection;
743
744 /* leave the lock before informing callbacks */
745 alock.release();
746
747 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
748 mParent->i_setModified(Machine::IsModified_VRDEServer);
749 mlock.release();
750
751 mParent->i_onVRDEServerChange(/* aRestart */ TRUE); // @todo does it need a restart?
752 }
753
754 return S_OK;
755}
756
757HRESULT VRDEServer::getReuseSingleConnection(BOOL *aReuseSingleConnection)
758{
759 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
760
761 *aReuseSingleConnection = mData->mReuseSingleConnection;
762
763 return S_OK;
764}
765
766
767HRESULT VRDEServer::setReuseSingleConnection(BOOL aReuseSingleConnection)
768{
769 AutoMutableOrSavedStateDependency adep(mParent);
770 if (FAILED(adep.rc())) return adep.rc();
771
772 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
773
774 if (mData->mReuseSingleConnection != aReuseSingleConnection)
775 {
776 mData.backup();
777 mData->mReuseSingleConnection = aReuseSingleConnection;
778
779 /* leave the lock before informing callbacks */
780 alock.release();
781
782 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
783 mParent->i_setModified(Machine::IsModified_VRDEServer);
784 mlock.release();
785
786 mParent->i_onVRDEServerChange(/* aRestart */ TRUE); // @todo needs a restart?
787 }
788
789 return S_OK;
790}
791
792HRESULT VRDEServer::getVRDEExtPack(com::Utf8Str &aExtPack)
793{
794 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
795 Utf8Str strExtPack = mData->mVrdeExtPack;
796 alock.release();
797 HRESULT hrc = S_OK;
798
799 if (strExtPack.isNotEmpty())
800 {
801 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
802 hrc = S_OK;
803 else
804 {
805#ifdef VBOX_WITH_EXTPACK
806 ExtPackManager *pExtPackMgr = mParent->i_getVirtualBox()->i_getExtPackManager();
807 hrc = pExtPackMgr->i_checkVrdeExtPack(&strExtPack);
808#else
809 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), strExtPack.c_str());
810#endif
811 }
812 if (SUCCEEDED(hrc))
813 aExtPack = strExtPack;
814 }
815 else
816 {
817 /* Get the global setting. */
818 ComPtr<ISystemProperties> systemProperties;
819 hrc = mParent->i_getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
820 if (SUCCEEDED(hrc))
821 {
822 BSTR bstr;
823 hrc = systemProperties->COMGETTER(DefaultVRDEExtPack)(&bstr);
824 if (SUCCEEDED(hrc))
825 aExtPack = Utf8Str(bstr);
826 }
827 }
828 return hrc;
829}
830
831// public methods only for internal purposes
832/////////////////////////////////////////////////////////////////////////////
833HRESULT VRDEServer::setVRDEExtPack(const com::Utf8Str &aExtPack)
834{
835 HRESULT hrc = S_OK;
836 /* the machine can also be in saved state for this property to change */
837 AutoMutableOrSavedStateDependency adep(mParent);
838 hrc = adep.rc();
839 if (SUCCEEDED(hrc))
840 {
841 /*
842 * If not empty, check the specific extension pack.
843 */
844 if (!aExtPack.isEmpty())
845 {
846 if (aExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
847 hrc = S_OK;
848 else
849 {
850#ifdef VBOX_WITH_EXTPACK
851 ExtPackManager *pExtPackMgr = mParent->i_getVirtualBox()->i_getExtPackManager();
852 hrc = pExtPackMgr->i_checkVrdeExtPack(&aExtPack);
853#else
854 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), aExtPack.c_str());
855#endif
856 }
857 }
858 if (SUCCEEDED(hrc))
859 {
860 /*
861 * Update the setting if there is an actual change, post an
862 * change event to trigger a VRDE server restart.
863 */
864 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
865 if (aExtPack != mData->mVrdeExtPack)
866 {
867 mData.backup();
868 mData->mVrdeExtPack = aExtPack;
869
870 /* leave the lock before informing callbacks */
871 alock.release();
872
873 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
874 mParent->i_setModified(Machine::IsModified_VRDEServer);
875 mlock.release();
876
877 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
878 }
879 }
880 }
881
882 return hrc;
883}
884
885// public methods only for internal purposes
886/////////////////////////////////////////////////////////////////////////////
887
888/**
889 * @note Locks this object for writing.
890 */
891void VRDEServer::i_rollback()
892{
893 /* sanity */
894 AutoCaller autoCaller(this);
895 AssertComRCReturnVoid(autoCaller.rc());
896
897 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
898
899 mData.rollback();
900}
901
902/**
903 * @note Locks this object for writing, together with the peer object (also
904 * for writing) if there is one.
905 */
906void VRDEServer::i_commit()
907{
908 /* sanity */
909 AutoCaller autoCaller(this);
910 AssertComRCReturnVoid(autoCaller.rc());
911
912 /* sanity too */
913 AutoCaller peerCaller(mPeer);
914 AssertComRCReturnVoid(peerCaller.rc());
915
916 /* lock both for writing since we modify both (mPeer is "master" so locked
917 * first) */
918 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
919
920 if (mData.isBackedUp())
921 {
922 mData.commit();
923 if (mPeer)
924 {
925 /* attach new data to the peer and reshare it */
926 mPeer->mData.attach(mData);
927 }
928 }
929}
930
931/**
932 * @note Locks this object for writing, together with the peer object
933 * represented by @a aThat (locked for reading).
934 */
935void VRDEServer::i_copyFrom(VRDEServer *aThat)
936{
937 AssertReturnVoid(aThat != NULL);
938
939 /* sanity */
940 AutoCaller autoCaller(this);
941 AssertComRCReturnVoid(autoCaller.rc());
942
943 /* sanity too */
944 AutoCaller thatCaller(aThat);
945 AssertComRCReturnVoid(thatCaller.rc());
946
947 /* peer is not modified, lock it for reading (aThat is "master" so locked
948 * first) */
949 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
950 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
951
952 /* this will back up current data */
953 mData.assignCopy(aThat->mData);
954}
955/* 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