VirtualBox

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

Last change on this file since 85672 was 85276, checked in by vboxsync, 4 years ago

Main/VRDEServerImpl.cpp: Workaround for Clang 11 nothrow/PPFN issue. bugref:9790

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