VirtualBox

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

Last change on this file since 104541 was 104541, checked in by vboxsync, 7 months ago

Revert r163069-r163071 for debugging

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