VirtualBox

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

Last change on this file since 98110 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

  • 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 98103 2023-01-17 14:15:46Z 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.rc());
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.rc());
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.rc());
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.rc());
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.rc())) return adep.rc();
252
253 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
254
255 HRESULT rc = 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 rc = mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
273 if (FAILED(rc))
274 {
275 /* Failed to enable/disable the server. Revert the internal state. */
276 adep.add();
277 if (SUCCEEDED(adep.rc()))
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 rc;
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 rc;
357 if (pszDash)
358 {
359 rc = i_portParseNumber(NULL, pszStart, pszDash);
360 if (RT_SUCCESS(rc))
361 rc = i_portParseNumber(NULL, pszDash + 1, pszEnd);
362 }
363 else
364 rc = i_portParseNumber(NULL, pszStart, pszEnd);
365
366 if (RT_FAILURE(rc))
367 return rc;
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.rc())) return adep.rc();
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 rc = VINF_SUCCESS;
479
480 RTLDRMOD hmod = NIL_RTLDRMOD;
481
482 RTERRINFOSTATIC ErrInfo;
483 RTErrInfoInitStatic(&ErrInfo);
484 if (RTPathHavePath(pszLibraryName))
485 rc = SUPR3HardenedLdrLoadPlugIn(pszLibraryName, &hmod, &ErrInfo.Core);
486 else
487 rc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &hmod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
488 if (RT_SUCCESS(rc))
489 {
490 rc = RTLdrGetSymbol(hmod, "VRDESupportedProperties", (void **)ppfn);
491
492 if (RT_FAILURE(rc) && rc != VERR_SYMBOL_NOT_FOUND)
493 LogRel(("VRDE: Error resolving symbol '%s', rc %Rrc.\n", "VRDESupportedProperties", rc));
494 }
495 else
496 {
497 if (RTErrInfoIsSet(&ErrInfo.Core))
498 LogRel(("VRDE: Error loading the library '%s': %s (%Rrc)\n", pszLibraryName, ErrInfo.Core.pszMsg, rc));
499 else
500 LogRel(("VRDE: Error loading the library '%s' rc = %Rrc.\n", pszLibraryName, rc));
501
502 hmod = NIL_RTLDRMOD;
503 }
504
505 if (RT_SUCCESS(rc))
506 {
507 *phmod = hmod;
508 }
509 else
510 {
511 if (hmod != NIL_RTLDRMOD)
512 {
513 RTLdrClose(hmod);
514 hmod = NIL_RTLDRMOD;
515 }
516 }
517
518 return rc;
519}
520
521HRESULT VRDEServer::getVRDEProperties(std::vector<com::Utf8Str> &aProperties)
522{
523 size_t cProperties = 0;
524 aProperties.resize(0);
525 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
526 if (!mData->fEnabled)
527 {
528 return S_OK;
529 }
530 alock.release();
531
532 /*
533 * Check that a VRDE extension pack name is set and resolve it into a
534 * library path.
535 */
536 Bstr bstrExtPack;
537 HRESULT hrc = COMGETTER(VRDEExtPack)(bstrExtPack.asOutParam());
538 Log(("VRDEPROP: get extpack hrc 0x%08X, isEmpty %d\n", hrc, bstrExtPack.isEmpty()));
539 if (FAILED(hrc))
540 return hrc;
541 if (bstrExtPack.isEmpty())
542 return E_FAIL;
543
544 Utf8Str strExtPack(bstrExtPack);
545 Utf8Str strVrdeLibrary;
546 int vrc = VINF_SUCCESS;
547 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
548 strVrdeLibrary = "VBoxVRDP";
549 else
550 {
551#ifdef VBOX_WITH_EXTPACK
552 VirtualBox *pVirtualBox = mParent->i_getVirtualBox();
553 ExtPackManager *pExtPackMgr = pVirtualBox->i_getExtPackManager();
554 vrc = pExtPackMgr->i_getVrdeLibraryPathForExtPack(&strExtPack, &strVrdeLibrary);
555#else
556 vrc = VERR_FILE_NOT_FOUND;
557#endif
558 }
559 Log(("VRDEPROP: library get rc %Rrc\n", vrc));
560
561 if (RT_SUCCESS(vrc))
562 {
563 /*
564 * Load the VRDE library and start the server, if it is enabled.
565 */
566 PFNVRDESUPPORTEDPROPERTIES pfn = NULL;
567 RTLDRMOD hmod = NIL_RTLDRMOD;
568#if CLANG_EXCEPTION_SPEC_HACK
569 vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, (void **)&pfn);
570#else
571 vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, &pfn);
572#endif
573 Log(("VRDEPROP: load library [%s] rc %Rrc\n", strVrdeLibrary.c_str(), vrc));
574 if (RT_SUCCESS(vrc))
575 {
576 const char * const *papszNames = pfn();
577
578 if (papszNames)
579 {
580 size_t i;
581 for (i = 0; papszNames[i] != NULL; ++i)
582 {
583 cProperties++;
584 }
585 }
586 Log(("VRDEPROP: %d properties\n", cProperties));
587
588 if (cProperties > 0)
589 {
590 aProperties.resize(cProperties);
591 for (size_t i = 0; i < cProperties && papszNames[i] != NULL; ++i)
592 {
593 aProperties[i] = papszNames[i];
594 }
595 }
596
597 /* Do not forget to unload the library. */
598 RTLdrClose(hmod);
599 hmod = NIL_RTLDRMOD;
600 }
601 }
602
603 if (RT_FAILURE(vrc))
604 {
605 return E_FAIL;
606 }
607
608 return S_OK;
609}
610
611
612HRESULT VRDEServer::getAuthType(AuthType_T *aType)
613{
614 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
615
616 *aType = mData->authType;
617
618 return S_OK;
619}
620
621HRESULT VRDEServer::setAuthType(AuthType_T aType)
622{
623 /* the machine can also be in saved state for this property to change */
624 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
625 if (FAILED(adep.rc())) return adep.rc();
626
627 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
628
629 if (mData->authType != aType)
630 {
631 mData.backup();
632 mData->authType = aType;
633
634 /* leave the lock before informing callbacks */
635 alock.release();
636
637 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
638 mParent->i_setModified(Machine::IsModified_VRDEServer);
639 mlock.release();
640
641 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
642 }
643
644 return S_OK;
645}
646
647HRESULT VRDEServer::getAuthTimeout(ULONG *aTimeout)
648{
649 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
650
651 *aTimeout = mData->ulAuthTimeout;
652
653 return S_OK;
654}
655
656
657HRESULT VRDEServer::setAuthTimeout(ULONG aTimeout)
658{
659 /* the machine can also be in saved state for this property to change */
660 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
661 if (FAILED(adep.rc())) return adep.rc();
662
663 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
664
665 if (aTimeout != mData->ulAuthTimeout)
666 {
667 mData.backup();
668 mData->ulAuthTimeout = aTimeout;
669
670 /* leave the lock before informing callbacks */
671 alock.release();
672
673 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
674 mParent->i_setModified(Machine::IsModified_VRDEServer);
675 mlock.release();
676
677 /* sunlover 20060131: This setter does not require the notification
678 * really */
679#if 0
680 mParent->onVRDEServerChange();
681#endif
682 }
683
684 return S_OK;
685}
686
687HRESULT VRDEServer::getAuthLibrary(com::Utf8Str &aLibrary)
688{
689 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
690 aLibrary = mData->strAuthLibrary;
691 alock.release();
692
693 if (aLibrary.isEmpty())
694 {
695 /* Get the global setting. */
696 ComPtr<ISystemProperties> systemProperties;
697 HRESULT hrc = mParent->i_getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
698 if (SUCCEEDED(hrc))
699 {
700 Bstr strlib;
701 hrc = systemProperties->COMGETTER(VRDEAuthLibrary)(strlib.asOutParam());
702 if (SUCCEEDED(hrc))
703 aLibrary = Utf8Str(strlib).c_str();
704 }
705
706 if (FAILED(hrc))
707 return setError(hrc, tr("failed to query the library setting\n"));
708 }
709
710 return S_OK;
711}
712
713
714HRESULT VRDEServer::setAuthLibrary(const com::Utf8Str &aLibrary)
715{
716 /* the machine can also be in saved state for this property to change */
717 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
718 if (FAILED(adep.rc())) return adep.rc();
719
720 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
721
722 if (mData->strAuthLibrary != aLibrary)
723 {
724 mData.backup();
725 mData->strAuthLibrary = aLibrary;
726
727 /* leave the lock before informing callbacks */
728 alock.release();
729
730 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
731 mParent->i_setModified(Machine::IsModified_VRDEServer);
732 mlock.release();
733
734 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
735 }
736
737 return S_OK;
738}
739
740
741HRESULT VRDEServer::getAllowMultiConnection(BOOL *aAllowMultiConnection)
742{
743 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
744
745 *aAllowMultiConnection = mData->fAllowMultiConnection;
746
747 return S_OK;
748}
749
750
751HRESULT VRDEServer::setAllowMultiConnection(BOOL aAllowMultiConnection)
752{
753 /* the machine can also be in saved state for this property to change */
754 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
755 if (FAILED(adep.rc())) return adep.rc();
756
757 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
758
759 if (mData->fAllowMultiConnection != RT_BOOL(aAllowMultiConnection))
760 {
761 mData.backup();
762 mData->fAllowMultiConnection = RT_BOOL(aAllowMultiConnection);
763
764 /* leave the lock before informing callbacks */
765 alock.release();
766
767 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
768 mParent->i_setModified(Machine::IsModified_VRDEServer);
769 mlock.release();
770
771 mParent->i_onVRDEServerChange(/* aRestart */ TRUE); /// @todo does it need a restart?
772 }
773
774 return S_OK;
775}
776
777HRESULT VRDEServer::getReuseSingleConnection(BOOL *aReuseSingleConnection)
778{
779 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
780
781 *aReuseSingleConnection = mData->fReuseSingleConnection;
782
783 return S_OK;
784}
785
786
787HRESULT VRDEServer::setReuseSingleConnection(BOOL aReuseSingleConnection)
788{
789 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
790 if (FAILED(adep.rc())) return adep.rc();
791
792 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
793
794 if (mData->fReuseSingleConnection != RT_BOOL(aReuseSingleConnection))
795 {
796 mData.backup();
797 mData->fReuseSingleConnection = RT_BOOL(aReuseSingleConnection);
798
799 /* leave the lock before informing callbacks */
800 alock.release();
801
802 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
803 mParent->i_setModified(Machine::IsModified_VRDEServer);
804 mlock.release();
805
806 mParent->i_onVRDEServerChange(/* aRestart */ TRUE); /// @todo needs a restart?
807 }
808
809 return S_OK;
810}
811
812HRESULT VRDEServer::getVRDEExtPack(com::Utf8Str &aExtPack)
813{
814 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
815 Utf8Str strExtPack = mData->strVrdeExtPack;
816 alock.release();
817 HRESULT hrc = S_OK;
818
819 if (strExtPack.isNotEmpty())
820 {
821 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
822 hrc = S_OK;
823 else
824 {
825#ifdef VBOX_WITH_EXTPACK
826 ExtPackManager *pExtPackMgr = mParent->i_getVirtualBox()->i_getExtPackManager();
827 hrc = pExtPackMgr->i_checkVrdeExtPack(&strExtPack);
828#else
829 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), strExtPack.c_str());
830#endif
831 }
832 if (SUCCEEDED(hrc))
833 aExtPack = strExtPack;
834 }
835 else
836 {
837 /* Get the global setting. */
838 ComPtr<ISystemProperties> systemProperties;
839 hrc = mParent->i_getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
840 if (SUCCEEDED(hrc))
841 {
842 Bstr bstr;
843 hrc = systemProperties->COMGETTER(DefaultVRDEExtPack)(bstr.asOutParam());
844 if (SUCCEEDED(hrc))
845 aExtPack = bstr;
846 }
847 }
848 return hrc;
849}
850
851// public methods only for internal purposes
852/////////////////////////////////////////////////////////////////////////////
853HRESULT VRDEServer::setVRDEExtPack(const com::Utf8Str &aExtPack)
854{
855 HRESULT hrc = S_OK;
856 /* the machine can also be in saved state for this property to change */
857 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
858 hrc = adep.rc();
859 if (SUCCEEDED(hrc))
860 {
861 /*
862 * If not empty, check the specific extension pack.
863 */
864 if (!aExtPack.isEmpty())
865 {
866 if (aExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
867 hrc = S_OK;
868 else
869 {
870#ifdef VBOX_WITH_EXTPACK
871 ExtPackManager *pExtPackMgr = mParent->i_getVirtualBox()->i_getExtPackManager();
872 hrc = pExtPackMgr->i_checkVrdeExtPack(&aExtPack);
873#else
874 hrc = setError(E_FAIL, tr("Extension pack '%s' does not exist"), aExtPack.c_str());
875#endif
876 }
877 }
878 if (SUCCEEDED(hrc))
879 {
880 /*
881 * Update the setting if there is an actual change, post an
882 * change event to trigger a VRDE server restart.
883 */
884 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
885 if (aExtPack != mData->strVrdeExtPack)
886 {
887 mData.backup();
888 mData->strVrdeExtPack = aExtPack;
889
890 /* leave the lock before informing callbacks */
891 alock.release();
892
893 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
894 mParent->i_setModified(Machine::IsModified_VRDEServer);
895 mlock.release();
896
897 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
898 }
899 }
900 }
901
902 return hrc;
903}
904
905// public methods only for internal purposes
906/////////////////////////////////////////////////////////////////////////////
907
908/**
909 * @note Locks this object for writing.
910 */
911void VRDEServer::i_rollback()
912{
913 /* sanity */
914 AutoCaller autoCaller(this);
915 AssertComRCReturnVoid(autoCaller.rc());
916
917 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
918
919 mData.rollback();
920}
921
922/**
923 * @note Locks this object for writing, together with the peer object (also
924 * for writing) if there is one.
925 */
926void VRDEServer::i_commit()
927{
928 /* sanity */
929 AutoCaller autoCaller(this);
930 AssertComRCReturnVoid(autoCaller.rc());
931
932 /* sanity too */
933 AutoCaller peerCaller(mPeer);
934 AssertComRCReturnVoid(peerCaller.rc());
935
936 /* lock both for writing since we modify both (mPeer is "master" so locked
937 * first) */
938 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
939
940 if (mData.isBackedUp())
941 {
942 mData.commit();
943 if (mPeer)
944 {
945 /* attach new data to the peer and reshare it */
946 mPeer->mData.attach(mData);
947 }
948 }
949}
950
951/**
952 * @note Locks this object for writing, together with the peer object
953 * represented by @a aThat (locked for reading).
954 */
955void VRDEServer::i_copyFrom(VRDEServer *aThat)
956{
957 AssertReturnVoid(aThat != NULL);
958
959 /* sanity */
960 AutoCaller autoCaller(this);
961 AssertComRCReturnVoid(autoCaller.rc());
962
963 /* sanity too */
964 AutoCaller thatCaller(aThat);
965 AssertComRCReturnVoid(thatCaller.rc());
966
967 /* peer is not modified, lock it for reading (aThat is "master" so locked
968 * first) */
969 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
970 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
971
972 /* this will back up current data */
973 mData.assignCopy(aThat->mData);
974}
975/* 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