VirtualBox

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

Last change on this file since 91514 was 91514, checked in by vboxsync, 3 years ago

Main: bugref:9790 - Update the workaround for Clang nothrow/PPFN
issue. It was not fixed in 13.0 so drop that arm of the test. While
here, don't repeat the test two times in one file (though each file is
still on its own).

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