VirtualBox

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

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

scm --update-copyright-year

  • 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 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2022 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