VirtualBox

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

Last change on this file since 54971 was 54971, checked in by vboxsync, 10 years ago

Main/AudioAdapter+BandwidthControl+Machine+NetworkAdapter+ParallelPort+SerialPort+StorageController+USBDeviceFilter+USBDeviceFilters: Adjust rules when settings can be changed to allow as much as possible. Some changes restored the old rules (a previous change made the definition more restrictive), but many now allow changing settings when VM is saved or even at runtime when it is safe. Will resolve many complaints, especially when the GUI also is adapted accordingly.

  • 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 54971 2015-03-26 16:40:30Z vboxsync $ */
2/** @file
3 *
4 * VirtualBox COM class implementation
5 */
6
7/*
8 * Copyright (C) 2006-2015 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->mAuthType = AuthType_Null;
93 mData->mAuthTimeout = 0;
94 mData->mAuthLibrary.setNull();
95 mData->mEnabled = FALSE;
96 mData->mAllowMultiConnection = FALSE;
97 mData->mReuseSingleConnection = FALSE;
98 mData->mVrdeExtPack.setNull();
99
100 /* Confirm a successful initialization */
101 autoInitSpan.setSucceeded();
102
103 return S_OK;
104}
105
106/**
107 * Initializes the object given another object
108 * (a kind of copy constructor). This object shares data with
109 * the object passed as an argument.
110 *
111 * @note This object must be destroyed before the original object
112 * it shares data with is destroyed.
113 *
114 * @note Locks @a aThat object for reading.
115 */
116HRESULT VRDEServer::init(Machine *aParent, VRDEServer *aThat)
117{
118 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
119
120 ComAssertRet(aParent && aThat, E_INVALIDARG);
121
122 /* Enclose the state transition NotReady->InInit->Ready */
123 AutoInitSpan autoInitSpan(this);
124 AssertReturn(autoInitSpan.isOk(), E_FAIL);
125
126 unconst(mParent) = aParent;
127 unconst(mPeer) = aThat;
128
129 AutoCaller thatCaller(aThat);
130 AssertComRCReturnRC(thatCaller.rc());
131
132 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
133 mData.share(aThat->mData);
134
135 /* Confirm a successful initialization */
136 autoInitSpan.setSucceeded();
137
138 return S_OK;
139}
140
141/**
142 * Initializes the guest object given another guest object
143 * (a kind of copy constructor). This object makes a private copy of data
144 * of the original object passed as an argument.
145 *
146 * @note Locks @a aThat object for reading.
147 */
148HRESULT VRDEServer::initCopy(Machine *aParent, VRDEServer *aThat)
149{
150 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
151
152 ComAssertRet(aParent && aThat, E_INVALIDARG);
153
154 /* Enclose the state transition NotReady->InInit->Ready */
155 AutoInitSpan autoInitSpan(this);
156 AssertReturn(autoInitSpan.isOk(), E_FAIL);
157
158 unconst(mParent) = aParent;
159 /* mPeer is left null */
160
161 AutoCaller thatCaller(aThat);
162 AssertComRCReturnRC(thatCaller.rc());
163
164 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
165 mData.attachCopy(aThat->mData);
166
167 /* Confirm a successful initialization */
168 autoInitSpan.setSucceeded();
169
170 return S_OK;
171}
172
173/**
174 * Uninitializes the instance and sets the ready flag to FALSE.
175 * Called either from FinalRelease() or by the parent when it gets destroyed.
176 */
177void VRDEServer::uninit()
178{
179 LogFlowThisFunc(("\n"));
180
181 /* Enclose the state transition Ready->InUninit->NotReady */
182 AutoUninitSpan autoUninitSpan(this);
183 if (autoUninitSpan.uninitDone())
184 return;
185
186 mData.free();
187
188 unconst(mPeer) = NULL;
189 unconst(mParent) = NULL;
190}
191
192/**
193 * Loads settings from the given machine node.
194 * May be called once right after this object creation.
195 *
196 * @param aMachineNode <Machine> node.
197 *
198 * @note Locks this object for writing.
199 */
200HRESULT VRDEServer::i_loadSettings(const settings::VRDESettings &data)
201{
202 using namespace settings;
203
204 AutoCaller autoCaller(this);
205 AssertComRCReturnRC(autoCaller.rc());
206
207 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
208 mData->mEnabled = data.fEnabled;
209 mData->mAuthType = data.authType;
210 mData->mAuthTimeout = data.ulAuthTimeout;
211 mData->mAuthLibrary = data.strAuthLibrary;
212 mData->mAllowMultiConnection = data.fAllowMultiConnection;
213 mData->mReuseSingleConnection = data.fReuseSingleConnection;
214 mData->mVrdeExtPack = data.strVrdeExtPack;
215 mData->mProperties = data.mapProperties;
216
217 return S_OK;
218}
219
220/**
221 * Saves settings to the given machine node.
222 *
223 * @param aMachineNode <Machine> node.
224 *
225 * @note Locks this object for reading.
226 */
227HRESULT VRDEServer::i_saveSettings(settings::VRDESettings &data)
228{
229 AutoCaller autoCaller(this);
230 AssertComRCReturnRC(autoCaller.rc());
231
232 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
233
234 data.fEnabled = !!mData->mEnabled;
235 data.authType = mData->mAuthType;
236 data.strAuthLibrary = mData->mAuthLibrary;
237 data.ulAuthTimeout = mData->mAuthTimeout;
238 data.fAllowMultiConnection = !!mData->mAllowMultiConnection;
239 data.fReuseSingleConnection = !!mData->mReuseSingleConnection;
240 data.strVrdeExtPack = mData->mVrdeExtPack;
241 data.mapProperties = mData->mProperties;
242
243 return S_OK;
244}
245
246// IVRDEServer properties
247/////////////////////////////////////////////////////////////////////////////
248
249HRESULT VRDEServer::getEnabled(BOOL *aEnabled)
250{
251 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
252
253 *aEnabled = mData->mEnabled;
254
255 return S_OK;
256}
257
258HRESULT VRDEServer::setEnabled(BOOL aEnabled)
259{
260 /* the machine can also be in saved state for this property to change */
261 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
262 if (FAILED(adep.rc())) return adep.rc();
263
264 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
265
266 HRESULT rc = S_OK;
267
268 if (mData->mEnabled != aEnabled)
269 {
270 mData.backup();
271 mData->mEnabled = aEnabled;
272
273 /* leave the lock before informing callbacks */
274 alock.release();
275
276 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
277 mParent->i_setModified(Machine::IsModified_VRDEServer);
278 mlock.release();
279
280 /* Avoid deadlock when i_onVRDEServerChange eventually calls SetExtraData. */
281 adep.release();
282
283 rc = mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
284 }
285
286 return rc;
287}
288
289static int i_portParseNumber(uint16_t *pu16Port, const char *pszStart, const char *pszEnd)
290{
291 /* Gets a string of digits, converts to 16 bit port number.
292 * Note: pszStart <= pszEnd is expected, the string contains
293 * only digits and pszEnd points to the char after last
294 * digit.
295 */
296 size_t cch = pszEnd - pszStart;
297 if (cch > 0 && cch <= 5) /* Port is up to 5 decimal digits. */
298 {
299 unsigned uPort = 0;
300 while (pszStart != pszEnd)
301 {
302 uPort = uPort * 10 + *pszStart - '0';
303 pszStart++;
304 }
305
306 if (uPort != 0 && uPort < 0x10000)
307 {
308 if (pu16Port)
309 *pu16Port = (uint16_t)uPort;
310 return VINF_SUCCESS;
311 }
312 }
313
314 return VERR_INVALID_PARAMETER;
315}
316
317static int i_vrdpServerVerifyPortsString(com::Utf8Str portRange)
318{
319 const char *pszPortRange = portRange.c_str();
320
321 if (!pszPortRange || *pszPortRange == 0) /* Reject empty string. */
322 return VERR_INVALID_PARAMETER;
323
324 /* The string should be like "1000-1010,1020,2000-2003" */
325 while (*pszPortRange)
326 {
327 const char *pszStart = pszPortRange;
328 const char *pszDash = NULL;
329 const char *pszEnd = pszStart;
330
331 while (*pszEnd && *pszEnd != ',')
332 {
333 if (*pszEnd == '-')
334 {
335 if (pszDash != NULL)
336 return VERR_INVALID_PARAMETER; /* More than one '-'. */
337
338 pszDash = pszEnd;
339 }
340 else if (!RT_C_IS_DIGIT(*pszEnd))
341 return VERR_INVALID_PARAMETER;
342
343 pszEnd++;
344 }
345
346 /* Update the next range pointer. */
347 pszPortRange = pszEnd;
348 if (*pszPortRange == ',')
349 {
350 pszPortRange++;
351 }
352
353 /* A probably valid range. Verify and parse it. */
354 int rc;
355 if (pszDash)
356 {
357 rc = i_portParseNumber(NULL, pszStart, pszDash);
358 if (RT_SUCCESS(rc))
359 rc = i_portParseNumber(NULL, pszDash + 1, pszEnd);
360 }
361 else
362 rc = i_portParseNumber(NULL, pszStart, pszEnd);
363
364 if (RT_FAILURE(rc))
365 return rc;
366 }
367
368 return VINF_SUCCESS;
369}
370
371HRESULT VRDEServer::setVRDEProperty(const com::Utf8Str &aKey, const com::Utf8Str &aValue)
372{
373 LogFlowThisFunc(("\n"));
374
375 /* the machine can also be in saved state for this property to change */
376 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
377 if (FAILED(adep.rc())) return adep.rc();
378
379 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
380
381 /* Special processing for some "standard" properties. */
382 if (aKey == "TCP/Ports")
383 {
384 /* Verify the string. "0" means the default port. */
385 Utf8Str strPorts = aValue == "0"?
386 VRDP_DEFAULT_PORT_STR:
387 aValue;
388 int vrc = i_vrdpServerVerifyPortsString(strPorts);
389 if (RT_FAILURE(vrc))
390 return E_INVALIDARG;
391
392 if (strPorts != mData->mProperties["TCP/Ports"])
393 {
394 /* Port value is not verified here because it is up to VRDP transport to
395 * use it. Specifying a wrong port number will cause a running server to
396 * stop. There is no fool proof here.
397 */
398 mData.backup();
399 mData->mProperties["TCP/Ports"] = strPorts;
400
401 /* leave the lock before informing callbacks */
402 alock.release();
403
404 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
405 mParent->i_setModified(Machine::IsModified_VRDEServer);
406 mlock.release();
407
408 /* Avoid deadlock when i_onVRDEServerChange eventually calls SetExtraData. */
409 adep.release();
410
411 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
412 }
413 }
414 else
415 {
416 /* Generic properties processing.
417 * Look up the old value first; if nothing's changed then do nothing.
418 */
419 Utf8Str strOldValue;
420
421 settings::StringsMap::const_iterator it = mData->mProperties.find(aKey);
422 if (it != mData->mProperties.end())
423 strOldValue = it->second;
424
425 if (strOldValue != aValue)
426 {
427 if (aValue.isEmpty())
428 mData->mProperties.erase(aKey);
429 else
430 mData->mProperties[aKey] = aValue;
431
432 /* leave the lock before informing callbacks */
433 alock.release();
434
435 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
436 mParent->i_setModified(Machine::IsModified_VRDEServer);
437 mlock.release();
438
439 /* Avoid deadlock when i_onVRDEServerChange eventually calls SetExtraData. */
440 adep.release();
441
442 mParent->i_onVRDEServerChange(/* aRestart */ TRUE);
443 }
444 }
445
446 return S_OK;
447}
448
449HRESULT VRDEServer::getVRDEProperty(const com::Utf8Str &aKey, com::Utf8Str &aValue)
450{
451 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
452 settings::StringsMap::const_iterator it = mData->mProperties.find(aKey);
453 if (it != mData->mProperties.end())
454 aValue = it->second; // source is a Utf8Str
455 else if (aKey == "TCP/Ports")
456 aValue = VRDP_DEFAULT_PORT_STR;
457
458 return S_OK;
459}
460
461static int loadVRDELibrary(const char *pszLibraryName, RTLDRMOD *phmod, PFNVRDESUPPORTEDPROPERTIES *ppfn)
462{
463 int rc = VINF_SUCCESS;
464
465 RTLDRMOD hmod = NIL_RTLDRMOD;
466
467 RTERRINFOSTATIC ErrInfo;
468 RTErrInfoInitStatic(&ErrInfo);
469 if (RTPathHavePath(pszLibraryName))
470 rc = SUPR3HardenedLdrLoadPlugIn(pszLibraryName, &hmod, &ErrInfo.Core);
471 else
472 rc = SUPR3HardenedLdrLoadAppPriv(pszLibraryName, &hmod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
473 if (RT_SUCCESS(rc))
474 {
475 rc = RTLdrGetSymbol(hmod, "VRDESupportedProperties", (void **)ppfn);
476
477 if (RT_FAILURE(rc) && rc != VERR_SYMBOL_NOT_FOUND)
478 LogRel(("VRDE: Error resolving symbol '%s', rc %Rrc.\n", "VRDESupportedProperties", rc));
479 }
480 else
481 {
482 if (RTErrInfoIsSet(&ErrInfo.Core))
483 LogRel(("VRDE: Error loading the library '%s': %s (%Rrc)\n", pszLibraryName, ErrInfo.Core.pszMsg, rc));
484 else
485 LogRel(("VRDE: Error loading the library '%s' rc = %Rrc.\n", pszLibraryName, rc));
486
487 hmod = NIL_RTLDRMOD;
488 }
489
490 if (RT_SUCCESS(rc))
491 {
492 *phmod = hmod;
493 }
494 else
495 {
496 if (hmod != NIL_RTLDRMOD)
497 {
498 RTLdrClose(hmod);
499 hmod = NIL_RTLDRMOD;
500 }
501 }
502
503 return rc;
504}
505
506HRESULT VRDEServer::getVRDEProperties(std::vector<com::Utf8Str> &aProperties)
507{
508 size_t cProperties = 0;
509 aProperties.resize(0);
510 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
511 if (!mData->mEnabled)
512 {
513 return S_OK;
514 }
515 alock.release();
516
517 /*
518 * Check that a VRDE extension pack name is set and resolve it into a
519 * library path.
520 */
521 Bstr bstrExtPack;
522 HRESULT hrc = COMGETTER(VRDEExtPack)(bstrExtPack.asOutParam());
523 Log(("VRDEPROP: get extpack hrc 0x%08X, isEmpty %d\n", hrc, bstrExtPack.isEmpty()));
524 if (FAILED(hrc))
525 return hrc;
526 if (bstrExtPack.isEmpty())
527 return E_FAIL;
528
529 Utf8Str strExtPack(bstrExtPack);
530 Utf8Str strVrdeLibrary;
531 int vrc = VINF_SUCCESS;
532 if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
533 strVrdeLibrary = "VBoxVRDP";
534 else
535 {
536#ifdef VBOX_WITH_EXTPACK
537 VirtualBox *pVirtualBox = mParent->i_getVirtualBox();
538 ExtPackManager *pExtPackMgr = pVirtualBox->i_getExtPackManager();
539 vrc = pExtPackMgr->i_getVrdeLibraryPathForExtPack(&strExtPack, &strVrdeLibrary);
540#else
541 vrc = VERR_FILE_NOT_FOUND;
542#endif
543 }
544 Log(("VRDEPROP: library get rc %Rrc\n", vrc));
545
546 if (RT_SUCCESS(vrc))
547 {
548 /*
549 * Load the VRDE library and start the server, if it is enabled.
550 */
551 PFNVRDESUPPORTEDPROPERTIES pfn = NULL;
552 RTLDRMOD hmod = NIL_RTLDRMOD;
553 vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, &pfn);
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; papszNames[i] != NULL && i < cProperties; ++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->mAuthType;
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->mAuthType != aType)
611 {
612 mData.backup();
613 mData->mAuthType = 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->mAuthTimeout;
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->mAuthTimeout)
647 {
648 mData.backup();
649 mData->mAuthTimeout = 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->mAuthLibrary;
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->mAuthLibrary != aLibrary)
704 {
705 mData.backup();
706 mData->mAuthLibrary = 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->mAllowMultiConnection;
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->mAllowMultiConnection != aAllowMultiConnection)
741 {
742 mData.backup();
743 mData->mAllowMultiConnection = 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->mReuseSingleConnection;
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->mReuseSingleConnection != aReuseSingleConnection)
776 {
777 mData.backup();
778 mData->mReuseSingleConnection = 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->mVrdeExtPack;
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);
825 if (SUCCEEDED(hrc))
826 aExtPack = Utf8Str(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->mVrdeExtPack)
867 {
868 mData.backup();
869 mData->mVrdeExtPack = 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