VirtualBox

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

Last change on this file since 74897 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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